summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2010-01-01 10:34:51 +0000
committerrdivacky <rdivacky@FreeBSD.org>2010-01-01 10:34:51 +0000
commitbb1e3bc1e0be2b8f891db46457a8943451bf4d8b (patch)
tree1e68501209c9133fbda8d45171e59f8d6f12dd55 /lib
parent77212133072dc40f070a280af8217032f55a9eb4 (diff)
downloadFreeBSD-src-bb1e3bc1e0be2b8f891db46457a8943451bf4d8b.zip
FreeBSD-src-bb1e3bc1e0be2b8f891db46457a8943451bf4d8b.tar.gz
Updaet clang to 92395.
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/ASTContext.cpp125
-rw-r--r--lib/AST/CMakeLists.txt1
-rw-r--r--lib/AST/Decl.cpp79
-rw-r--r--lib/AST/DeclCXX.cpp16
-rw-r--r--lib/AST/DeclGroup.cpp1
-rw-r--r--lib/AST/DeclarationName.cpp2
-rw-r--r--lib/AST/Expr.cpp56
-rw-r--r--lib/AST/ExprCXX.cpp73
-rw-r--r--lib/AST/ExprConstant.cpp72
-rw-r--r--lib/AST/FullExpr.cpp58
-rw-r--r--lib/AST/Stmt.cpp128
-rw-r--r--lib/AST/StmtIterator.cpp16
-rw-r--r--lib/AST/StmtProfile.cpp1
-rw-r--r--lib/AST/Type.cpp23
-rw-r--r--lib/AST/TypePrinter.cpp15
-rw-r--r--lib/Analysis/AnalysisContext.cpp16
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.cpp2
-rw-r--r--lib/Analysis/BasicStore.cpp17
-rw-r--r--lib/Analysis/CFG.cpp197
-rw-r--r--lib/Analysis/CFRefCount.cpp17
-rw-r--r--lib/Analysis/CallInliner.cpp94
-rw-r--r--lib/Analysis/CheckDeadStores.cpp24
-rw-r--r--lib/Analysis/GRCoreEngine.cpp14
-rw-r--r--lib/Analysis/GRExprEngine.cpp582
-rw-r--r--lib/Analysis/LiveVariables.cpp27
-rw-r--r--lib/Analysis/MallocChecker.cpp32
-rw-r--r--lib/Analysis/MemRegion.cpp18
-rw-r--r--lib/Analysis/NoReturnFunctionChecker.cpp5
-rw-r--r--lib/Analysis/OSAtomicChecker.cpp10
-rw-r--r--lib/Analysis/RegionStore.cpp29
-rw-r--r--lib/Analysis/SValuator.cpp17
-rw-r--r--lib/Analysis/SimpleConstraintManager.cpp28
-rw-r--r--lib/Analysis/Store.cpp21
-rw-r--r--lib/Basic/Diagnostic.cpp13
-rw-r--r--lib/Basic/FileManager.cpp5
-rw-r--r--lib/Basic/TargetInfo.cpp2
-rw-r--r--lib/Basic/Targets.cpp231
-rw-r--r--lib/CodeGen/CGBlocks.cpp5
-rw-r--r--lib/CodeGen/CGBuiltin.cpp39
-rw-r--r--lib/CodeGen/CGCXX.cpp845
-rw-r--r--lib/CodeGen/CGCall.cpp48
-rw-r--r--lib/CodeGen/CGCall.h20
-rw-r--r--lib/CodeGen/CGClass.cpp775
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp118
-rw-r--r--lib/CodeGen/CGDecl.cpp8
-rw-r--r--lib/CodeGen/CGException.cpp66
-rw-r--r--lib/CodeGen/CGExpr.cpp110
-rw-r--r--lib/CodeGen/CGExprAgg.cpp51
-rw-r--r--lib/CodeGen/CGExprCXX.cpp74
-rw-r--r--lib/CodeGen/CGExprComplex.cpp11
-rw-r--r--lib/CodeGen/CGExprScalar.cpp43
-rw-r--r--lib/CodeGen/CGObjC.cpp8
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp34
-rw-r--r--lib/CodeGen/CGObjCMac.cpp10
-rw-r--r--lib/CodeGen/CGRTTI.cpp1118
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp16
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.h5
-rw-r--r--lib/CodeGen/CGTemporaries.cpp42
-rw-r--r--lib/CodeGen/CGVtable.cpp58
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp2
-rw-r--r--lib/CodeGen/CodeGenFunction.h33
-rw-r--r--lib/CodeGen/CodeGenModule.cpp8
-rw-r--r--lib/CodeGen/CodeGenModule.h24
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp11
-rw-r--r--lib/CodeGen/Mangle.cpp68
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp2
-rw-r--r--lib/CodeGen/TargetABIInfo.cpp4
-rw-r--r--lib/Driver/CC1Options.cpp2
-rw-r--r--lib/Driver/Driver.cpp18
-rw-r--r--lib/Driver/ToolChain.cpp4
-rw-r--r--lib/Driver/ToolChains.cpp66
-rw-r--r--lib/Driver/ToolChains.h2
-rw-r--r--lib/Driver/Tools.cpp106
-rw-r--r--lib/Driver/Tools.h2
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp57
-rw-r--r--lib/Frontend/CMakeLists.txt1
-rw-r--r--lib/Frontend/CompilerInvocation.cpp24
-rw-r--r--lib/Frontend/FrontendActions.cpp5
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp13
-rw-r--r--lib/Frontend/PCHReader.cpp17
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp2
-rw-r--r--lib/Frontend/PCHWriter.cpp19
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp2
-rw-r--r--lib/Frontend/RewriteBlocks.cpp1152
-rw-r--r--lib/Frontend/RewriteObjC.cpp241
-rw-r--r--lib/Frontend/Warnings.cpp37
-rw-r--r--lib/Lex/Lexer.cpp30
-rw-r--r--lib/Lex/LiteralSupport.cpp22
-rw-r--r--lib/Lex/MacroArgs.cpp64
-rw-r--r--lib/Lex/MacroArgs.h2
-rw-r--r--lib/Lex/PPDirectives.cpp35
-rw-r--r--lib/Lex/Preprocessor.cpp15
-rw-r--r--lib/Lex/TokenLexer.cpp4
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp10
-rw-r--r--lib/Parse/ParseDecl.cpp26
-rw-r--r--lib/Parse/ParseDeclCXX.cpp32
-rw-r--r--lib/Parse/ParseObjc.cpp2
-rw-r--r--lib/Parse/ParseStmt.cpp112
-rw-r--r--lib/Parse/ParseTemplate.cpp6
-rw-r--r--lib/Parse/ParseTentative.cpp19
-rw-r--r--lib/Parse/Parser.cpp13
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp17
-rw-r--r--lib/Sema/Lookup.h68
-rw-r--r--lib/Sema/Sema.cpp13
-rw-r--r--lib/Sema/Sema.h175
-rw-r--r--lib/Sema/SemaAccess.cpp2
-rw-r--r--lib/Sema/SemaCXXCast.cpp15
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp50
-rw-r--r--lib/Sema/SemaChecking.cpp3
-rw-r--r--lib/Sema/SemaCodeComplete.cpp79
-rw-r--r--lib/Sema/SemaDecl.cpp342
-rw-r--r--lib/Sema/SemaDeclAttr.cpp19
-rw-r--r--lib/Sema/SemaDeclCXX.cpp449
-rw-r--r--lib/Sema/SemaDeclObjC.cpp13
-rw-r--r--lib/Sema/SemaExpr.cpp639
-rw-r--r--lib/Sema/SemaExprCXX.cpp274
-rw-r--r--lib/Sema/SemaExprObjC.cpp2
-rw-r--r--lib/Sema/SemaInit.cpp1140
-rw-r--r--lib/Sema/SemaInit.h181
-rw-r--r--lib/Sema/SemaLookup.cpp662
-rw-r--r--lib/Sema/SemaOverload.cpp397
-rw-r--r--lib/Sema/SemaStmt.cpp31
-rw-r--r--lib/Sema/SemaTemplate.cpp93
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp156
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp5
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp29
-rw-r--r--lib/Sema/SemaType.cpp39
-rw-r--r--lib/Sema/TreeTransform.h96
128 files changed, 7725 insertions, 5149 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index cc7055d..74e74e7 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -55,44 +56,43 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
}
ASTContext::~ASTContext() {
- // Deallocate all the types.
- while (!Types.empty()) {
- Types.back()->Destroy(*this);
- Types.pop_back();
- }
+ if (FreeMemory) {
+ // Deallocate all the types.
+ while (!Types.empty()) {
+ Types.back()->Destroy(*this);
+ Types.pop_back();
+ }
- {
- llvm::FoldingSet<ExtQuals>::iterator
- I = ExtQualNodes.begin(), E = ExtQualNodes.end();
- while (I != E)
+ for (llvm::FoldingSet<ExtQuals>::iterator
+ I = ExtQualNodes.begin(), E = ExtQualNodes.end(); I != E; ) {
+ // Increment in loop to prevent using deallocated memory.
Deallocate(&*I++);
+ }
}
- {
- llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*>::iterator
- I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end();
- while (I != E) {
- ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second);
- delete R;
- }
+ for (llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*>::iterator
+ I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end(); I != E; ) {
+ // Increment in loop to prevent using deallocated memory.
+ ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second);
+ delete R;
}
- {
- llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*>::iterator
- I = ObjCLayouts.begin(), E = ObjCLayouts.end();
- while (I != E) {
- ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second);
- delete R;
- }
+ for (llvm::DenseMap<const ObjCContainerDecl*,
+ const ASTRecordLayout*>::iterator
+ I = ObjCLayouts.begin(), E = ObjCLayouts.end(); I != E; ) {
+ // Increment in loop to prevent using deallocated memory.
+ ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second);
+ delete R;
}
// Destroy nested-name-specifiers.
for (llvm::FoldingSet<NestedNameSpecifier>::iterator
NNS = NestedNameSpecifiers.begin(),
NNSEnd = NestedNameSpecifiers.end();
- NNS != NNSEnd;
- /* Increment in loop */)
+ NNS != NNSEnd; ) {
+ // Increment in loop to prevent using deallocated memory.
(*NNS++).Destroy(*this);
+ }
if (GlobalNestedNameSpecifier)
GlobalNestedNameSpecifier->Destroy(*this);
@@ -694,13 +694,6 @@ ASTContext::getTypeInfo(const Type *T) {
break;
}
break;
- case Type::FixedWidthInt:
- // FIXME: This isn't precisely correct; the width/alignment should depend
- // on the available types for the target
- Width = cast<FixedWidthIntType>(T)->getWidth();
- Width = std::max(llvm::NextPowerOf2(Width - 1), (uint64_t)8);
- Align = Width;
- break;
case Type::ObjCObjectPointer:
Width = Target.getPointerWidth(0);
Align = Target.getPointerAlign(0);
@@ -818,6 +811,15 @@ ASTContext::getTypeInfo(const Type *T) {
return std::make_pair(Width, Align);
}
+/// getTypeSizeInChars - Return the size of the specified type, in characters.
+/// This method does not work on incomplete types.
+CharUnits ASTContext::getTypeSizeInChars(QualType T) {
+ return CharUnits::fromRaw(getTypeSize(T) / getCharWidth());
+}
+CharUnits ASTContext::getTypeSizeInChars(const Type *T) {
+ return CharUnits::fromRaw(getTypeSize(T) / getCharWidth());
+}
+
/// getPreferredTypeAlign - Return the "preferred" alignment of the specified
/// type for the current target in bits. This can be different than the ABI
/// alignment in cases where it is beneficial for performance to overalign
@@ -1056,9 +1058,7 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
// Add in synthesized ivar count if laying out an implementation.
if (Impl) {
- unsigned FieldCount = D->ivar_size();
unsigned SynthCount = CountSynthesizedIvars(D);
- FieldCount += SynthCount;
// If there aren't any sythesized ivars then reuse the interface
// entry. Note we can't cache this because we simply free all
// entries later; however we shouldn't look up implementations
@@ -1267,15 +1267,6 @@ QualType ASTContext::getComplexType(QualType T) {
return QualType(New, 0);
}
-QualType ASTContext::getFixedWidthIntType(unsigned Width, bool Signed) {
- llvm::DenseMap<unsigned, FixedWidthIntType*> &Map = Signed ?
- SignedFixedWidthIntTypes : UnsignedFixedWidthIntTypes;
- FixedWidthIntType *&Entry = Map[Width];
- if (!Entry)
- Entry = new FixedWidthIntType(Width, Signed);
- return QualType(Entry, 0);
-}
-
/// getPointerType - Return the uniqued reference to the type for a pointer to
/// the specified type.
QualType ASTContext::getPointerType(QualType T) {
@@ -2381,6 +2372,42 @@ CanQualType ASTContext::getCanonicalType(QualType T) {
VAT->getBracketsRange()));
}
+QualType ASTContext::getUnqualifiedArrayType(QualType T,
+ Qualifiers &Quals) {
+ assert(T.isCanonical() && "Only operates on canonical types");
+ if (!isa<ArrayType>(T)) {
+ Quals = T.getLocalQualifiers();
+ return T.getLocalUnqualifiedType();
+ }
+
+ assert(!T.hasQualifiers() && "canonical array type has qualifiers!");
+ const ArrayType *AT = cast<ArrayType>(T);
+ QualType Elt = AT->getElementType();
+ QualType UnqualElt = getUnqualifiedArrayType(getCanonicalType(Elt), Quals);
+ if (Elt == UnqualElt)
+ return T;
+
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) {
+ return getConstantArrayType(UnqualElt, CAT->getSize(),
+ CAT->getSizeModifier(), 0);
+ }
+
+ if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(T)) {
+ return getIncompleteArrayType(UnqualElt, IAT->getSizeModifier(), 0);
+ }
+
+ if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(T)) {
+ return getVariableArrayType(UnqualElt, VAT->getSizeExpr()->Retain(),
+ VAT->getSizeModifier(), 0,
+ SourceRange());
+ }
+
+ const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(T);
+ return getDependentSizedArrayType(UnqualElt, DSAT->getSizeExpr()->Retain(),
+ DSAT->getSizeModifier(), 0,
+ SourceRange());
+}
+
DeclarationName ASTContext::getNameForTemplate(TemplateName Name) {
if (TemplateDecl *TD = Name.getAsTemplateDecl())
return TD->getDeclName();
@@ -2682,12 +2709,6 @@ unsigned ASTContext::getIntegerRank(Type *T) {
if (T->isSpecificBuiltinType(BuiltinType::Char32))
T = getFromTargetType(Target.getChar32Type()).getTypePtr();
- // There are two things which impact the integer rank: the width, and
- // the ordering of builtins. The builtin ordering is encoded in the
- // bottom three bits; the width is encoded in the bits above that.
- if (FixedWidthIntType* FWIT = dyn_cast<FixedWidthIntType>(T))
- return FWIT->getWidth() << 3;
-
switch (cast<BuiltinType>(T)->getKind()) {
default: assert(0 && "getIntegerRank(): not a built-in integer");
case BuiltinType::Bool:
@@ -4500,9 +4521,6 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
return QualType();
}
- case Type::FixedWidthInt:
- // Distinct fixed-width integers are not compatible.
- return QualType();
case Type::TemplateSpecialization:
assert(false && "Dependent types have no size");
break;
@@ -4518,9 +4536,6 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
unsigned ASTContext::getIntWidth(QualType T) {
if (T->isBooleanType())
return 1;
- if (FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) {
- return FWIT->getWidth();
- }
if (EnumType *ET = dyn_cast<EnumType>(T))
T = ET->getDecl()->getIntegerType();
// For builtin types, just use the standard type sizing method
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 0f0b22d..5aecf87 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -16,6 +16,7 @@ add_clang_library(clangAST
Expr.cpp
ExprCXX.cpp
ExprConstant.cpp
+ FullExpr.cpp
InheritViz.cpp
NestedNameSpecifier.cpp
ParentMap.cpp
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 4d0d422..e112fa3 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/TypeLoc.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
@@ -91,6 +92,34 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg);
}
+Expr *ParmVarDecl::getDefaultArg() {
+ assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!");
+ assert(!hasUninstantiatedDefaultArg() &&
+ "Default argument is not yet instantiated!");
+
+ Expr *Arg = getInit();
+ if (CXXExprWithTemporaries *E = dyn_cast_or_null<CXXExprWithTemporaries>(Arg))
+ return E->getSubExpr();
+
+ return Arg;
+}
+
+unsigned ParmVarDecl::getNumDefaultArgTemporaries() const {
+ if (const CXXExprWithTemporaries *E =
+ dyn_cast<CXXExprWithTemporaries>(getInit()))
+ return E->getNumTemporaries();
+
+ return 0;
+}
+
+CXXTemporary *ParmVarDecl::getDefaultArgTemporary(unsigned i) {
+ assert(getNumDefaultArgTemporaries() &&
+ "Default arguments does not have any temporaries!");
+
+ CXXExprWithTemporaries *E = cast<CXXExprWithTemporaries>(getInit());
+ return E->getTemporary(i);
+}
+
SourceRange ParmVarDecl::getDefaultArgRange() const {
if (const Expr *E = getInit())
return E->getSourceRange();
@@ -183,6 +212,9 @@ TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) TypedefDecl(DC, L, Id, TInfo);
}
+// Anchor TypedefDecl's vtable here.
+TypedefDecl::~TypedefDecl() {}
+
EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, SourceLocation TKL,
EnumDecl *PrevDecl) {
@@ -426,11 +458,6 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
return getNameAsString();
while (Ctx) {
- if (Ctx->isFunctionOrMethod())
- // FIXME: That probably will happen, when D was member of local
- // scope class/struct/union. How do we handle this case?
- break;
-
if (const ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
@@ -440,6 +467,48 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
TemplateArgs.flat_size(),
P);
Names.push_back(Spec->getIdentifier()->getNameStart() + TemplateArgsStr);
+ } else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(Ctx)) {
+ if (ND->isAnonymousNamespace())
+ Names.push_back("<anonymous namespace>");
+ else
+ Names.push_back(ND->getNameAsString());
+ } else if (const RecordDecl *RD = dyn_cast<RecordDecl>(Ctx)) {
+ if (!RD->getIdentifier()) {
+ std::string RecordString = "<anonymous ";
+ RecordString += RD->getKindName();
+ RecordString += ">";
+ Names.push_back(RecordString);
+ } else {
+ Names.push_back(RD->getNameAsString());
+ }
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Ctx)) {
+ std::string Proto = FD->getNameAsString();
+
+ const FunctionProtoType *FT = 0;
+ if (FD->hasWrittenPrototype())
+ FT = dyn_cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>());
+
+ Proto += "(";
+ if (FT) {
+ llvm::raw_string_ostream POut(Proto);
+ unsigned NumParams = FD->getNumParams();
+ for (unsigned i = 0; i < NumParams; ++i) {
+ if (i)
+ POut << ", ";
+ std::string Param;
+ FD->getParamDecl(i)->getType().getAsStringInternal(Param, P);
+ POut << Param;
+ }
+
+ if (FT->isVariadic()) {
+ if (NumParams > 0)
+ POut << ", ";
+ POut << "...";
+ }
+ }
+ Proto += ")";
+
+ Names.push_back(Proto);
} else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx))
Names.push_back(ND->getNameAsString());
else
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 292a3ed..bbbb19a 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -164,8 +164,7 @@ CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context,
if (isa<FunctionTemplateDecl>(*Con))
continue;
- if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context,
- FoundTQs)) {
+ if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(FoundTQs)) {
if (((TypeQuals & Qualifiers::Const) == (FoundTQs & Qualifiers::Const)) ||
(!(TypeQuals & Qualifiers::Const) && (FoundTQs & Qualifiers::Const)))
return cast<CXXConstructorDecl>(*Con);
@@ -246,7 +245,7 @@ CXXRecordDecl::addedConstructor(ASTContext &Context,
// Note when we have a user-declared copy constructor, which will
// suppress the implicit declaration of a copy constructor.
- if (ConDecl->isCopyConstructor(Context)) {
+ if (ConDecl->isCopyConstructor()) {
UserDeclaredCopyConstructor = true;
// C++ [class.copy]p6:
@@ -757,8 +756,7 @@ bool CXXConstructorDecl::isDefaultConstructor() const {
}
bool
-CXXConstructorDecl::isCopyConstructor(ASTContext &Context,
- unsigned &TypeQuals) const {
+CXXConstructorDecl::isCopyConstructor(unsigned &TypeQuals) const {
// C++ [class.copy]p2:
// A non-template constructor for class X is a copy constructor
// if its first parameter is of type X&, const X&, volatile X& or
@@ -779,6 +777,8 @@ CXXConstructorDecl::isCopyConstructor(ASTContext &Context,
return false;
// Is it a reference to our class type?
+ ASTContext &Context = getASTContext();
+
CanQualType PointeeType
= Context.getCanonicalType(ParamRefType->getPointeeType());
CanQualType ClassTy
@@ -874,7 +874,11 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
isa<CXXRecordDecl>(D) ||
isa<FunctionTemplateDecl>(D) ||
isa<ClassTemplateDecl>(D));
- assert(D->getFriendObjectKind());
+
+ // As a temporary hack, we permit template instantiation to point
+ // to the original declaration when instantiating members.
+ assert(D->getFriendObjectKind() ||
+ (cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind()));
}
#endif
diff --git a/lib/AST/DeclGroup.cpp b/lib/AST/DeclGroup.cpp
index 5bdc881..434bf00 100644
--- a/lib/AST/DeclGroup.cpp
+++ b/lib/AST/DeclGroup.cpp
@@ -32,6 +32,7 @@ DeclGroup::DeclGroup(unsigned numdecls, Decl** decls) : NumDecls(numdecls) {
}
void DeclGroup::Destroy(ASTContext& C) {
+ // Decls are destroyed by the DeclContext.
this->~DeclGroup();
C.Deallocate((void*) this);
}
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 0ce03c2..60c40e2 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -210,7 +210,7 @@ std::string DeclarationName::getAsString() const {
}
case CXXOperatorName: {
- static const char *OperatorNames[NUM_OVERLOADED_OPERATORS] = {
+ static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = {
0,
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
Spelling,
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 139e04b..04a6abc 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -174,6 +174,8 @@ std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT,
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
if (MD->isVirtual())
Out << "virtual ";
+ if (MD->isStatic())
+ Out << "static ";
}
PrintingPolicy Policy(Context.getLangOptions());
@@ -203,6 +205,14 @@ std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT,
}
Proto += ")";
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ Qualifiers ThisQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers());
+ if (ThisQuals.hasConst())
+ Proto += " const";
+ if (ThisQuals.hasVolatile())
+ Proto += " volatile";
+ }
+
if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
AFT->getResultType().getAsStringInternal(Proto, Policy);
@@ -398,14 +408,20 @@ void CallExpr::DoDestroy(ASTContext& C) {
C.Deallocate(this);
}
-FunctionDecl *CallExpr::getDirectCallee() {
+Decl *CallExpr::getCalleeDecl() {
Expr *CEE = getCallee()->IgnoreParenCasts();
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE))
- return dyn_cast<FunctionDecl>(DRE->getDecl());
+ return DRE->getDecl();
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(CEE))
+ return ME->getMemberDecl();
return 0;
}
+FunctionDecl *CallExpr::getDirectCallee() {
+ return dyn_cast_or_null<FunctionDecl>(getCalleeDecl());
+}
+
/// setNumArgs - This changes the number of arguments present in this call.
/// Any orphaned expressions are deleted by this, and any new operands are set
/// to null.
@@ -858,7 +874,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
case CXXMemberCallExprClass: {
// If this is a direct call, get the callee.
const CallExpr *CE = cast<CallExpr>(this);
- if (const FunctionDecl *FD = CE->getDirectCallee()) {
+ if (const Decl *FD = CE->getCalleeDecl()) {
// If the callee has attribute pure, const, or warn_unused_result, warn
// about it. void foo() { strlen("bar"); } should warn.
//
@@ -1047,8 +1063,13 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
// -- If E2 is a non-static data member [...]. If E1 is an
// lvalue, then E1.E2 is an lvalue.
- if (isa<FieldDecl>(Member))
- return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx);
+ if (isa<FieldDecl>(Member)) {
+ if (m->isArrow())
+ return LV_Valid;
+ Expr *BaseExp = m->getBase();
+ return (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) ?
+ LV_SubObjCPropertySetting : BaseExp->isLvalue(Ctx);
+ }
// -- If it refers to a static member function [...], then
// E1.E2 is an lvalue.
@@ -1065,9 +1086,13 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
// Not an lvalue.
return LV_InvalidExpression;
}
-
+
// C99 6.5.2.3p4
- return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx);
+ if (m->isArrow())
+ return LV_Valid;
+ Expr *BaseExp = m->getBase();
+ return (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) ?
+ LV_SubObjCPropertySetting : BaseExp->isLvalue(Ctx);
}
case UnaryOperatorClass:
if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref)
@@ -1204,6 +1229,16 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
return LV_Valid;
}
+ case Expr::CXXExprWithTemporariesClass:
+ return cast<CXXExprWithTemporaries>(this)->getSubExpr()->isLvalue(Ctx);
+
+ case Expr::ObjCMessageExprClass:
+ if (const ObjCMethodDecl *Method
+ = cast<ObjCMessageExpr>(this)->getMethodDecl())
+ if (Method->getResultType()->isLValueReferenceType())
+ return LV_Valid;
+ break;
+
default:
break;
}
@@ -1244,6 +1279,7 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
}
return MLV_InvalidExpression;
case LV_MemberFunction: return MLV_MemberFunction;
+ case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting;
}
// The following is illegal:
@@ -1996,7 +2032,7 @@ ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo,
QualType retType, ObjCMethodDecl *mproto,
SourceLocation LBrac, SourceLocation RBrac,
Expr **ArgExprs, unsigned nargs)
- : Expr(ObjCMessageExprClass, retType), SelName(selInfo),
+ : Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo),
MethodProto(mproto) {
NumArgs = nargs;
SubExprs = new Stmt*[NumArgs+1];
@@ -2015,7 +2051,7 @@ ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo,
QualType retType, ObjCMethodDecl *mproto,
SourceLocation LBrac, SourceLocation RBrac,
Expr **ArgExprs, unsigned nargs)
- : Expr(ObjCMessageExprClass, retType), SelName(selInfo),
+ : Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo),
MethodProto(mproto) {
NumArgs = nargs;
SubExprs = new Stmt*[NumArgs+1];
@@ -2033,7 +2069,7 @@ ObjCMessageExpr::ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo,
QualType retType, ObjCMethodDecl *mproto,
SourceLocation LBrac, SourceLocation RBrac,
Expr **ArgExprs, unsigned nargs)
-: Expr(ObjCMessageExprClass, retType), SelName(selInfo),
+: Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo),
MethodProto(mproto) {
NumArgs = nargs;
SubExprs = new Stmt*[NumArgs+1];
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index a9f96ad..81584b7 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -282,6 +282,18 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
}
}
+SourceRange CXXConstructExpr::getSourceRange() const {
+ // FIXME: Should we know where the parentheses are, if there are any?
+ for (std::reverse_iterator<Stmt**> I(&Args[NumArgs]), E(&Args[0]); I!=E;++I) {
+ // Ignore CXXDefaultExprs when computing the range, as they don't
+ // have a range.
+ if (!isa<CXXDefaultArgExpr>(*I))
+ return SourceRange(Loc, (*I)->getLocEnd());
+ }
+
+ return SourceRange(Loc);
+}
+
SourceRange CXXOperatorCallExpr::getSourceRange() const {
OverloadedOperatorKind Kind = getOperator();
if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) {
@@ -340,6 +352,21 @@ const char *CXXNamedCastExpr::getCastName() const {
}
}
+CXXDefaultArgExpr *
+CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc,
+ ParmVarDecl *Param, Expr *SubExpr) {
+ void *Mem = C.Allocate(sizeof(CXXDefaultArgExpr) + sizeof(Stmt *));
+ return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param,
+ SubExpr);
+}
+
+void CXXDefaultArgExpr::DoDestroy(ASTContext &C) {
+ if (Param.getInt())
+ getExpr()->Destroy(C);
+ this->~CXXDefaultArgExpr();
+ C.Deallocate(this);
+}
+
CXXTemporary *CXXTemporary::Create(ASTContext &C,
const CXXDestructorDecl *Destructor) {
return new (C) CXXTemporary(Destructor);
@@ -372,34 +399,40 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
Expr **Args,
unsigned NumArgs,
SourceLocation rParenLoc)
- : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, Cons,
- false, Args, NumArgs),
+ : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, tyBeginLoc,
+ Cons, false, Args, NumArgs),
TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {
}
CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
+ SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
- Expr **Args, unsigned NumArgs) {
- return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, D, Elidable,
- Args, NumArgs);
+ Expr **Args, unsigned NumArgs,
+ bool ZeroInitialization) {
+ return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
+ Elidable, Args, NumArgs, ZeroInitialization);
}
CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
+ SourceLocation Loc,
CXXConstructorDecl *D, bool elidable,
- Expr **args, unsigned numargs)
+ Expr **args, unsigned numargs,
+ bool ZeroInitialization)
: Expr(SC, T,
T->isDependentType(),
(T->isDependentType() ||
CallExpr::hasAnyValueDependentArguments(args, numargs))),
- Constructor(D), Elidable(elidable), Args(0), NumArgs(numargs) {
- if (NumArgs) {
- Args = new (C) Stmt*[NumArgs];
-
- for (unsigned i = 0; i != NumArgs; ++i) {
- assert(args[i] && "NULL argument in CXXConstructExpr");
- Args[i] = args[i];
- }
+ Constructor(D), Loc(Loc), Elidable(elidable),
+ ZeroInitialization(ZeroInitialization), Args(0), NumArgs(numargs)
+{
+ if (NumArgs) {
+ Args = new (C) Stmt*[NumArgs];
+
+ for (unsigned i = 0; i != NumArgs; ++i) {
+ assert(args[i] && "NULL argument in CXXConstructExpr");
+ Args[i] = args[i];
}
+ }
}
CXXConstructExpr::CXXConstructExpr(EmptyShell Empty, ASTContext &C,
@@ -420,12 +453,10 @@ void CXXConstructExpr::DoDestroy(ASTContext &C) {
CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr,
CXXTemporary **temps,
- unsigned numtemps,
- bool shoulddestroytemps)
+ unsigned numtemps)
: Expr(CXXExprWithTemporariesClass, subexpr->getType(),
subexpr->isTypeDependent(), subexpr->isValueDependent()),
- SubExpr(subexpr), Temps(0), NumTemps(numtemps),
- ShouldDestroyTemps(shoulddestroytemps) {
+ SubExpr(subexpr), Temps(0), NumTemps(numtemps) {
if (NumTemps > 0) {
Temps = new CXXTemporary*[NumTemps];
for (unsigned i = 0; i < NumTemps; ++i)
@@ -436,10 +467,8 @@ CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr,
CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C,
Expr *SubExpr,
CXXTemporary **Temps,
- unsigned NumTemps,
- bool ShouldDestroyTemps){
- return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps,
- ShouldDestroyTemps);
+ unsigned NumTemps) {
+ return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps);
}
void CXXExprWithTemporaries::DoDestroy(ASTContext &C) {
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 13831dc..06afec7 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -222,7 +222,6 @@ public:
APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
APValue VisitDeclRefExpr(DeclRefExpr *E);
- APValue VisitBlockExpr(BlockExpr *E);
APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E, 0); }
APValue VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
APValue VisitMemberExpr(MemberExpr *E);
@@ -270,13 +269,6 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
return APValue();
}
-APValue LValueExprEvaluator::VisitBlockExpr(BlockExpr *E) {
- if (E->hasBlockDeclRefExprs())
- return APValue();
-
- return APValue(E, 0);
-}
-
APValue LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
if (!Info.AnyLValue && !E->isFileScope())
return APValue();
@@ -366,7 +358,7 @@ public:
APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
APValue VisitBinaryOperator(const BinaryOperator *E);
- APValue VisitCastExpr(const CastExpr* E);
+ APValue VisitCastExpr(CastExpr* E);
APValue VisitUnaryExtension(const UnaryOperator *E)
{ return Visit(E->getSubExpr()); }
APValue VisitUnaryAddrOf(const UnaryOperator *E);
@@ -443,23 +435,49 @@ APValue PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
}
-APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
- const Expr* SubExpr = E->getSubExpr();
+APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
+ Expr* SubExpr = E->getSubExpr();
- // Check for pointer->pointer cast
- if (SubExpr->getType()->isPointerType() ||
- SubExpr->getType()->isObjCObjectPointerType() ||
- SubExpr->getType()->isNullPtrType()) {
- APValue Result;
- if (EvaluatePointer(SubExpr, Result, Info))
+ switch (E->getCastKind()) {
+ default:
+ break;
+
+ case CastExpr::CK_Unknown: {
+ // FIXME: The handling for CK_Unknown is ugly/shouldn't be necessary!
+
+ // Check for pointer->pointer cast
+ if (SubExpr->getType()->isPointerType() ||
+ SubExpr->getType()->isObjCObjectPointerType() ||
+ SubExpr->getType()->isNullPtrType() ||
+ SubExpr->getType()->isBlockPointerType())
+ return Visit(SubExpr);
+
+ if (SubExpr->getType()->isIntegralType()) {
+ APValue Result;
+ if (!EvaluateIntegerOrLValue(SubExpr, Result, Info))
+ break;
+
+ if (Result.isInt()) {
+ Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
+ return APValue(0, Result.getInt().getZExtValue());
+ }
+
+ // Cast is of an lvalue, no need to change value.
return Result;
- return APValue();
+ }
+ break;
}
- if (SubExpr->getType()->isIntegralType()) {
+ case CastExpr::CK_NoOp:
+ case CastExpr::CK_BitCast:
+ case CastExpr::CK_AnyPointerToObjCPointerCast:
+ case CastExpr::CK_AnyPointerToBlockPointerCast:
+ return Visit(SubExpr);
+
+ case CastExpr::CK_IntegralToPointer: {
APValue Result;
if (!EvaluateIntegerOrLValue(SubExpr, Result, Info))
- return APValue();
+ break;
if (Result.isInt()) {
Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
@@ -469,14 +487,13 @@ APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
// Cast is of an lvalue, no need to change value.
return Result;
}
-
- if (SubExpr->getType()->isFunctionType() ||
- SubExpr->getType()->isBlockPointerType() ||
- SubExpr->getType()->isArrayType()) {
+ case CastExpr::CK_ArrayToPointerDecay:
+ case CastExpr::CK_FunctionToPointerDecay: {
APValue Result;
if (EvaluateLValue(SubExpr, Result, Info))
return Result;
- return APValue();
+ break;
+ }
}
return APValue();
@@ -970,8 +987,9 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
}
}
+ // TODO: Perhaps we should let LLVM lower this?
if (E->getArg(0)->HasSideEffects(Info.Ctx)) {
- if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() < 2)
+ if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() == 0)
return Success(-1ULL, E);
return Success(0, E);
}
@@ -1290,8 +1308,6 @@ unsigned IntExprEvaluator::GetAlignOfExpr(const Expr *E) {
/// VisitSizeAlignOfExpr - Evaluate a sizeof or alignof with a result as the
/// expression's type.
bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
- QualType DstTy = E->getType();
-
// Handle alignof separately.
if (!E->isSizeOf()) {
if (E->isArgumentType())
diff --git a/lib/AST/FullExpr.cpp b/lib/AST/FullExpr.cpp
new file mode 100644
index 0000000..f47284f
--- /dev/null
+++ b/lib/AST/FullExpr.cpp
@@ -0,0 +1,58 @@
+//===--- FullExpr.cpp - C++ full expression class ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the FullExpr interface, to be used for type safe handling
+// of full expressions.
+//
+// Full expressions are described in C++ [intro.execution]p12.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/FullExpr.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "llvm/Support/AlignOf.h"
+using namespace clang;
+
+FullExpr FullExpr::Create(ASTContext &Context, Expr *SubExpr,
+ CXXTemporary **Temporaries, unsigned NumTemporaries) {
+ FullExpr E;
+
+ if (!NumTemporaries) {
+ E.SubExpr = SubExpr;
+ return E;
+ }
+
+ unsigned Size = sizeof(FullExpr)
+ + sizeof(CXXTemporary *) * NumTemporaries;
+
+ unsigned Align = llvm::AlignOf<ExprAndTemporaries>::Alignment;
+ ExprAndTemporaries *ET =
+ static_cast<ExprAndTemporaries *>(Context.Allocate(Size, Align));
+
+ ET->SubExpr = SubExpr;
+ std::copy(Temporaries, Temporaries + NumTemporaries, ET->temps_begin());
+
+ return E;
+}
+
+void FullExpr::Destroy(ASTContext &Context) {
+ if (Expr *E = SubExpr.dyn_cast<Expr *>()) {
+ E->Destroy(Context);
+ return;
+ }
+
+ ExprAndTemporaries *ET = SubExpr.get<ExprAndTemporaries *>();
+ for (ExprAndTemporaries::temps_iterator i = ET->temps_begin(),
+ e = ET->temps_end(); i != e; ++i)
+ (*i)->Destroy(Context);
+
+ Context.Deallocate(ET);
+}
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index fad80ec..7c7aeb8 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -47,17 +47,6 @@ const char *Stmt::getStmtClassName() const {
return getStmtInfoTableEntry((StmtClass)sClass).Name;
}
-void Stmt::DestroyChildren(ASTContext &C) {
- for (child_iterator I = child_begin(), E = child_end(); I !=E; )
- if (Stmt* Child = *I++) Child->Destroy(C);
-}
-
-void Stmt::DoDestroy(ASTContext &C) {
- DestroyChildren(C);
- this->~Stmt();
- C.Deallocate((void *)this);
-}
-
void Stmt::PrintStats() {
// Ensure the table is primed.
getStmtInfoTableEntry(Stmt::NullStmtClass);
@@ -93,20 +82,6 @@ bool Stmt::CollectingStats(bool Enable) {
return StatSwitch;
}
-void SwitchStmt::DoDestroy(ASTContext &Ctx) {
- // Destroy the SwitchCase statements in this switch. In the normal
- // case, this loop will merely decrement the reference counts from
- // the Retain() calls in addSwitchCase();
- SwitchCase *SC = FirstCase;
- while (SC) {
- SwitchCase *Next = SC->getNextSwitchCase();
- SC->Destroy(Ctx);
- SC = Next;
- }
-
- Stmt::DoDestroy(Ctx);
-}
-
void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) {
if (this->Body)
C.Deallocate(Body);
@@ -412,6 +387,71 @@ ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc,
RParenLoc = rparenloc;
}
+//===----------------------------------------------------------------------===//
+// AST Destruction.
+//===----------------------------------------------------------------------===//
+
+void Stmt::DestroyChildren(ASTContext &C) {
+ for (child_iterator I = child_begin(), E = child_end(); I !=E; )
+ if (Stmt* Child = *I++) Child->Destroy(C);
+}
+
+static void BranchDestroy(ASTContext &C, Stmt *S, Stmt **SubExprs,
+ unsigned NumExprs) {
+ // We do not use child_iterator here because that will include
+ // the expressions referenced by the condition variable.
+ for (Stmt **I = SubExprs, **E = SubExprs + NumExprs; I != E; ++I)
+ if (Stmt *Child = *I) Child->Destroy(C);
+
+ S->~Stmt();
+ C.Deallocate((void *) S);
+}
+
+void Stmt::DoDestroy(ASTContext &C) {
+ DestroyChildren(C);
+ this->~Stmt();
+ C.Deallocate((void *)this);
+}
+
+void CXXCatchStmt::DoDestroy(ASTContext& C) {
+ if (ExceptionDecl)
+ ExceptionDecl->Destroy(C);
+ Stmt::DoDestroy(C);
+}
+
+void DeclStmt::DoDestroy(ASTContext &C) {
+ // Don't use StmtIterator to iterate over the Decls, as that can recurse
+ // into VLA size expressions (which are owned by the VLA). Further, Decls
+ // are owned by the DeclContext, and will be destroyed with them.
+ if (DG.isDeclGroup())
+ DG.getDeclGroup().Destroy(C);
+}
+
+void IfStmt::DoDestroy(ASTContext &C) {
+ BranchDestroy(C, this, SubExprs, END_EXPR);
+}
+
+void ForStmt::DoDestroy(ASTContext &C) {
+ BranchDestroy(C, this, SubExprs, END_EXPR);
+}
+
+void SwitchStmt::DoDestroy(ASTContext &C) {
+ // Destroy the SwitchCase statements in this switch. In the normal
+ // case, this loop will merely decrement the reference counts from
+ // the Retain() calls in addSwitchCase();
+ SwitchCase *SC = FirstCase;
+ while (SC) {
+ SwitchCase *Next = SC->getNextSwitchCase();
+ SC->Destroy(C);
+ SC = Next;
+ }
+
+ BranchDestroy(C, this, SubExprs, END_EXPR);
+}
+
+void WhileStmt::DoDestroy(ASTContext &C) {
+ BranchDestroy(C, this, SubExprs, END_EXPR);
+}
//===----------------------------------------------------------------------===//
// Child Iterators for iterating over subexpressions/substatements
@@ -447,24 +487,40 @@ Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; }
Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; }
// IfStmt
-Stmt::child_iterator IfStmt::child_begin() { return &SubExprs[0]; }
-Stmt::child_iterator IfStmt::child_end() { return &SubExprs[0]+END_EXPR; }
+Stmt::child_iterator IfStmt::child_begin() {
+ return child_iterator(Var, &SubExprs[0]);
+}
+Stmt::child_iterator IfStmt::child_end() {
+ return child_iterator(0, &SubExprs[0]+END_EXPR);
+}
// SwitchStmt
-Stmt::child_iterator SwitchStmt::child_begin() { return &SubExprs[0]; }
-Stmt::child_iterator SwitchStmt::child_end() { return &SubExprs[0]+END_EXPR; }
+Stmt::child_iterator SwitchStmt::child_begin() {
+ return child_iterator(Var, &SubExprs[0]);
+}
+Stmt::child_iterator SwitchStmt::child_end() {
+ return child_iterator(0, &SubExprs[0]+END_EXPR);
+}
// WhileStmt
-Stmt::child_iterator WhileStmt::child_begin() { return &SubExprs[0]; }
-Stmt::child_iterator WhileStmt::child_end() { return &SubExprs[0]+END_EXPR; }
+Stmt::child_iterator WhileStmt::child_begin() {
+ return child_iterator(Var, &SubExprs[0]);
+}
+Stmt::child_iterator WhileStmt::child_end() {
+ return child_iterator(0, &SubExprs[0]+END_EXPR);
+}
// DoStmt
Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; }
// ForStmt
-Stmt::child_iterator ForStmt::child_begin() { return &SubExprs[0]; }
-Stmt::child_iterator ForStmt::child_end() { return &SubExprs[0]+END_EXPR; }
+Stmt::child_iterator ForStmt::child_begin() {
+ return child_iterator(CondVar, &SubExprs[0]);
+}
+Stmt::child_iterator ForStmt::child_end() {
+ return child_iterator(0, &SubExprs[0]+END_EXPR);
+}
// ObjCForCollectionStmt
Stmt::child_iterator ObjCForCollectionStmt::child_begin() {
@@ -565,12 +621,6 @@ QualType CXXCatchStmt::getCaughtType() const {
return QualType();
}
-void CXXCatchStmt::DoDestroy(ASTContext& C) {
- if (ExceptionDecl)
- ExceptionDecl->Destroy(C);
- Stmt::DoDestroy(C);
-}
-
// CXXTryStmt
Stmt::child_iterator CXXTryStmt::child_begin() { return &Stmts[0]; }
Stmt::child_iterator CXXTryStmt::child_end() { return &Stmts[0]+Stmts.size(); }
diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp
index 4f62b66..7fc7c96 100644
--- a/lib/AST/StmtIterator.cpp
+++ b/lib/AST/StmtIterator.cpp
@@ -65,7 +65,7 @@ void StmtIteratorBase::NextDecl(bool ImmediateAdvance) {
assert (getVAPtr() == NULL);
if (inDecl()) {
- assert (decl);
+ assert(decl);
// FIXME: SIMPLIFY AWAY.
if (ImmediateAdvance)
@@ -74,7 +74,7 @@ void StmtIteratorBase::NextDecl(bool ImmediateAdvance) {
return;
}
else {
- assert (inDeclGroup());
+ assert(inDeclGroup());
if (ImmediateAdvance)
++DGI;
@@ -113,19 +113,19 @@ bool StmtIteratorBase::HandleDecl(Decl* D) {
return false;
}
-StmtIteratorBase::StmtIteratorBase(Decl* d)
- : decl(d), RawVAPtr(DeclMode) {
- assert (decl);
- NextDecl(false);
+StmtIteratorBase::StmtIteratorBase(Decl *d, Stmt **s)
+ : stmt(s), decl(d), RawVAPtr(d ? DeclMode : 0) {
+ if (decl)
+ NextDecl(false);
}
StmtIteratorBase::StmtIteratorBase(Decl** dgi, Decl** dge)
- : DGI(dgi), RawVAPtr(DeclGroupMode), DGE(dge) {
+ : stmt(0), DGI(dgi), RawVAPtr(DeclGroupMode), DGE(dge) {
NextDecl(false);
}
StmtIteratorBase::StmtIteratorBase(VariableArrayType* t)
-: decl(0), RawVAPtr(SizeOfTypeVAMode) {
+ : stmt(0), decl(0), RawVAPtr(SizeOfTypeVAMode) {
RawVAPtr |= reinterpret_cast<uintptr_t>(t);
}
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index e2d772b..b74e1ef 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -540,7 +540,6 @@ StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) {
void StmtProfiler::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *S) {
VisitExpr(S);
- ID.AddBoolean(S->shouldDestroyTemporaries());
for (unsigned I = 0, N = S->getNumTemporaries(); I != N; ++I)
VisitDecl(
const_cast<CXXDestructorDecl *>(S->getTemporary(I)->getDestructor()));
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 687beae..e0055f1 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -387,8 +387,6 @@ bool Type::isIntegerType() const {
// FIXME: In C++, enum types are never integer types.
if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
return true;
- if (isa<FixedWidthIntType>(CanonicalType))
- return true;
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isIntegerType();
return false;
@@ -397,13 +395,11 @@ bool Type::isIntegerType() const {
bool Type::isIntegralType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
- BT->getKind() <= BuiltinType::LongLong;
+ BT->getKind() <= BuiltinType::Int128;
if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
return true; // Complete enum types are integral.
// FIXME: In C++, enum types are never integral.
- if (isa<FixedWidthIntType>(CanonicalType))
- return true;
return false;
}
@@ -453,16 +449,12 @@ bool Type::isAnyCharacterType() const {
bool Type::isSignedIntegerType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
return BT->getKind() >= BuiltinType::Char_S &&
- BT->getKind() <= BuiltinType::LongLong;
+ BT->getKind() <= BuiltinType::Int128;
}
if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
return ET->getDecl()->getIntegerType()->isSignedIntegerType();
- if (const FixedWidthIntType *FWIT =
- dyn_cast<FixedWidthIntType>(CanonicalType))
- return FWIT->isSigned();
-
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isSignedIntegerType();
return false;
@@ -481,10 +473,6 @@ bool Type::isUnsignedIntegerType() const {
if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
return ET->getDecl()->getIntegerType()->isUnsignedIntegerType();
- if (const FixedWidthIntType *FWIT =
- dyn_cast<FixedWidthIntType>(CanonicalType))
- return !FWIT->isSigned();
-
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isUnsignedIntegerType();
return false;
@@ -515,8 +503,6 @@ bool Type::isRealType() const {
BT->getKind() <= BuiltinType::LongDouble;
if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
return TT->getDecl()->isEnum() && TT->getDecl()->isDefinition();
- if (isa<FixedWidthIntType>(CanonicalType))
- return true;
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isRealType();
return false;
@@ -530,8 +516,6 @@ bool Type::isArithmeticType() const {
// GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2).
// If a body isn't seen by the time we get here, return false.
return ET->getDecl()->isDefinition();
- if (isa<FixedWidthIntType>(CanonicalType))
- return true;
return isa<ComplexType>(CanonicalType) || isa<VectorType>(CanonicalType);
}
@@ -545,8 +529,6 @@ bool Type::isScalarType() const {
return true;
return false;
}
- if (isa<FixedWidthIntType>(CanonicalType))
- return true;
return isa<PointerType>(CanonicalType) ||
isa<BlockPointerType>(CanonicalType) ||
isa<MemberPointerType>(CanonicalType) ||
@@ -725,6 +707,7 @@ bool Type::isSpecifierType() const {
case Typename:
case ObjCInterface:
case ObjCObjectPointer:
+ case Elaborated:
return true;
default:
return false;
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 4a2b956..818657c 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -94,21 +94,6 @@ void TypePrinter::PrintBuiltin(const BuiltinType *T, std::string &S) {
}
}
-void TypePrinter::PrintFixedWidthInt(const FixedWidthIntType *T,
- std::string &S) {
- // FIXME: Once we get bitwidth attribute, write as
- // "int __attribute__((bitwidth(x)))".
- std::string prefix = "__clang_fixedwidth";
- prefix += llvm::utostr_32(T->getWidth());
- prefix += (char)(T->isSigned() ? 'S' : 'U');
- if (S.empty()) {
- S = prefix;
- } else {
- // Prefix the basic type, e.g. 'int X'.
- S = prefix + S;
- }
-}
-
void TypePrinter::PrintComplex(const ComplexType *T, std::string &S) {
Print(T->getElementType(), S);
S = "_Complex " + S;
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 05e5196..97e6d91 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -105,7 +105,7 @@ void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID,
}
void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getAnalysisContext(), getParent(), CallSite);
+ Profile(ID, getAnalysisContext(), getParent(), CallSite, Block, Index);
}
void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) {
@@ -145,8 +145,18 @@ LocationContextManager::getLocationContext(AnalysisContext *ctx,
const StackFrameContext*
LocationContextManager::getStackFrame(AnalysisContext *ctx,
const LocationContext *parent,
- const Stmt *s) {
- return getLocationContext<StackFrameContext, Stmt>(ctx, parent, s);
+ const Stmt *s, const CFGBlock *blk,
+ unsigned idx) {
+ llvm::FoldingSetNodeID ID;
+ StackFrameContext::Profile(ID, ctx, parent, s, blk, idx);
+ void *InsertPos;
+ StackFrameContext *L =
+ cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
+ if (!L) {
+ L = new StackFrameContext(ctx, parent, s, blk, idx);
+ Contexts.InsertNode(L, InsertPos);
+ }
+ return L;
}
const ScopeContext *
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
index c913779..67483d9 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -294,7 +294,7 @@ namespace {
}
static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
- static unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
+ static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
if (i < kCFNumberCharType)
return FixedSize[i-1];
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp
index a38aaa7..224281b 100644
--- a/lib/Analysis/BasicStore.cpp
+++ b/lib/Analysis/BasicStore.cpp
@@ -479,15 +479,14 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
const Decl& CD = *InitLoc->getDecl();
if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CD)) {
if (MD->getSelfDecl() == PD) {
- // FIXME: Just use a symbolic region, and remove ObjCObjectRegion
- // entirely.
- const ObjCObjectRegion *SelfRegion =
- MRMgr.getObjCObjectRegion(MD->getClassInterface(),
- MRMgr.getHeapRegion());
-
- St = BindInternal(St, ValMgr.makeLoc(MRMgr.getVarRegion(PD, InitLoc)),
- ValMgr.makeLoc(SelfRegion));
-
+ // FIXME: Add type constraints (when they become available) to
+ // SelfRegion? (i.e., it implements MD->getClassInterface()).
+ const MemRegion *VR = MRMgr.getVarRegion(PD, InitLoc);
+ const MemRegion *SelfRegion =
+ ValMgr.getRegionValueSymbolVal(VR).getAsRegion();
+ assert(SelfRegion);
+ St = BindInternal(St, ValMgr.makeLoc(VR),
+ loc::MemRegionVal(SelfRegion));
// Scan the method for ivar references. While this requires an
// entire AST scan, the cost should not be high in practice.
St = scanForIvars(MD->getBody(), PD, SelfRegion, St);
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index e1a1e72..eab7da7 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -34,6 +34,17 @@ static SourceLocation GetEndLoc(Decl* D) {
return D->getLocation();
}
+
+class AddStmtChoice {
+public:
+ enum Kind { NotAlwaysAdd = 0, AlwaysAdd, AlwaysAddAsLValue };
+public:
+ AddStmtChoice(Kind kind) : k(kind) {}
+ bool alwaysAdd() const { return k != NotAlwaysAdd; }
+ bool asLValue() const { return k == AlwaysAddAsLValue; }
+private:
+ Kind k;
+};
/// CFGBuilder - This class implements CFG construction from an AST.
/// The builder is stateful: an instance of the builder should be used to only
@@ -84,15 +95,16 @@ public:
private:
// Visitors to walk an AST and construct the CFG.
- CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd);
- CFGBlock *VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd);
- CFGBlock *VisitBlockExpr(BlockExpr* E, bool alwaysAdd);
+ CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc);
+ CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc);
+ CFGBlock *VisitBlockExpr(BlockExpr* E, AddStmtChoice asc);
CFGBlock *VisitBreakStmt(BreakStmt *B);
- CFGBlock *VisitCallExpr(CallExpr *C, bool alwaysAdd);
+ CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc);
CFGBlock *VisitCaseStmt(CaseStmt *C);
- CFGBlock *VisitChooseExpr(ChooseExpr *C);
+ CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc);
CFGBlock *VisitCompoundStmt(CompoundStmt *C);
- CFGBlock *VisitConditionalOperator(ConditionalOperator *C);
+ CFGBlock *VisitConditionalOperator(ConditionalOperator *C,
+ AddStmtChoice asc);
CFGBlock *VisitContinueStmt(ContinueStmt *C);
CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S) { return NYS(); }
CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
@@ -112,13 +124,13 @@ private:
CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S);
CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
CFGBlock *VisitReturnStmt(ReturnStmt* R);
- CFGBlock *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, bool alwaysAdd);
- CFGBlock *VisitStmtExpr(StmtExpr *S, bool alwaysAdd);
+ CFGBlock *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, AddStmtChoice asc);
+ CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc);
CFGBlock *VisitSwitchStmt(SwitchStmt *S);
CFGBlock *VisitWhileStmt(WhileStmt *W);
- CFGBlock *Visit(Stmt *S, bool alwaysAdd = false);
- CFGBlock *VisitStmt(Stmt *S, bool alwaysAdd);
+ CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd);
+ CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc);
CFGBlock *VisitChildren(Stmt* S);
// NYS == Not Yet Supported
@@ -130,10 +142,13 @@ private:
void autoCreateBlock() { if (!Block) Block = createBlock(); }
CFGBlock *createBlock(bool add_successor = true);
bool FinishBlock(CFGBlock* B);
- CFGBlock *addStmt(Stmt *S) { return Visit(S, true); }
+ CFGBlock *addStmt(Stmt *S, AddStmtChoice asc = AddStmtChoice::AlwaysAdd) {
+ return Visit(S, asc);
+ }
- void AppendStmt(CFGBlock *B, Stmt *S) {
- B->appendStmt(S, cfg->getBumpVectorContext());
+ void AppendStmt(CFGBlock *B, Stmt *S,
+ AddStmtChoice asc = AddStmtChoice::AlwaysAdd) {
+ B->appendStmt(S, cfg->getBumpVectorContext(), asc.asLValue());
}
void AddSuccessor(CFGBlock *B, CFGBlock *S) {
@@ -278,38 +293,38 @@ bool CFGBuilder::FinishBlock(CFGBlock* B) {
/// Visit - Walk the subtree of a statement and add extra
/// blocks for ternary operators, &&, and ||. We also process "," and
/// DeclStmts (which may contain nested control-flow).
-CFGBlock* CFGBuilder::Visit(Stmt * S, bool alwaysAdd) {
+CFGBlock* CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
tryAgain:
switch (S->getStmtClass()) {
default:
- return VisitStmt(S, alwaysAdd);
+ return VisitStmt(S, asc);
case Stmt::AddrLabelExprClass:
- return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), alwaysAdd);
+ return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), asc);
case Stmt::BinaryOperatorClass:
- return VisitBinaryOperator(cast<BinaryOperator>(S), alwaysAdd);
+ return VisitBinaryOperator(cast<BinaryOperator>(S), asc);
case Stmt::BlockExprClass:
- return VisitBlockExpr(cast<BlockExpr>(S), alwaysAdd);
+ return VisitBlockExpr(cast<BlockExpr>(S), asc);
case Stmt::BreakStmtClass:
return VisitBreakStmt(cast<BreakStmt>(S));
case Stmt::CallExprClass:
- return VisitCallExpr(cast<CallExpr>(S), alwaysAdd);
+ return VisitCallExpr(cast<CallExpr>(S), asc);
case Stmt::CaseStmtClass:
return VisitCaseStmt(cast<CaseStmt>(S));
case Stmt::ChooseExprClass:
- return VisitChooseExpr(cast<ChooseExpr>(S));
+ return VisitChooseExpr(cast<ChooseExpr>(S), asc);
case Stmt::CompoundStmtClass:
return VisitCompoundStmt(cast<CompoundStmt>(S));
case Stmt::ConditionalOperatorClass:
- return VisitConditionalOperator(cast<ConditionalOperator>(S));
+ return VisitConditionalOperator(cast<ConditionalOperator>(S), asc);
case Stmt::ContinueStmtClass:
return VisitContinueStmt(cast<ContinueStmt>(S));
@@ -367,10 +382,10 @@ tryAgain:
return VisitReturnStmt(cast<ReturnStmt>(S));
case Stmt::SizeOfAlignOfExprClass:
- return VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), alwaysAdd);
+ return VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), asc);
case Stmt::StmtExprClass:
- return VisitStmtExpr(cast<StmtExpr>(S), alwaysAdd);
+ return VisitStmtExpr(cast<StmtExpr>(S), asc);
case Stmt::SwitchStmtClass:
return VisitSwitchStmt(cast<SwitchStmt>(S));
@@ -380,10 +395,10 @@ tryAgain:
}
}
-CFGBlock *CFGBuilder::VisitStmt(Stmt *S, bool alwaysAdd) {
- if (alwaysAdd) {
+CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
+ if (asc.alwaysAdd()) {
autoCreateBlock();
- AppendStmt(Block, S);
+ AppendStmt(Block, S, asc);
}
return VisitChildren(S);
@@ -399,21 +414,23 @@ CFGBlock *CFGBuilder::VisitChildren(Stmt* Terminator) {
return B;
}
-CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd) {
+CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
+ AddStmtChoice asc) {
AddressTakenLabels.insert(A->getLabel());
- if (alwaysAdd) {
+ if (asc.alwaysAdd()) {
autoCreateBlock();
- AppendStmt(Block, A);
+ AppendStmt(Block, A, asc);
}
return Block;
}
-CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd) {
+CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
+ AddStmtChoice asc) {
if (B->isLogicalOp()) { // && or ||
CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
- AppendStmt(ConfluenceBlock, B);
+ AppendStmt(ConfluenceBlock, B, asc);
if (!FinishBlock(ConfluenceBlock))
return 0;
@@ -450,18 +467,18 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd) {
}
else if (B->getOpcode() == BinaryOperator::Comma) { // ,
autoCreateBlock();
- AppendStmt(Block, B);
+ AppendStmt(Block, B, asc);
addStmt(B->getRHS());
return addStmt(B->getLHS());
}
- return VisitStmt(B, alwaysAdd);
+ return VisitStmt(B, asc);
}
-CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, bool alwaysAdd) {
- if (alwaysAdd) {
+CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {
+ if (asc.alwaysAdd()) {
autoCreateBlock();
- AppendStmt(Block, E);
+ AppendStmt(Block, E, asc);
}
return Block;
}
@@ -487,7 +504,7 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
return Block;
}
-CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, bool alwaysAdd) {
+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 (C->getCallee()->getType().getNoReturnAttr()) {
@@ -499,14 +516,14 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, bool alwaysAdd) {
NoReturn = true;
if (!NoReturn)
- return VisitStmt(C, alwaysAdd);
+ return VisitStmt(C, asc);
if (Block && !FinishBlock(Block))
return 0;
// Create new block with no successor for the remaining pieces.
Block = createBlock(false);
- AppendStmt(Block, C);
+ AppendStmt(Block, C, asc);
// Wire this to the exit block directly.
AddSuccessor(Block, &cfg->getExit());
@@ -514,9 +531,10 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, bool alwaysAdd) {
return VisitChildren(C);
}
-CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C) {
+CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
+ AddStmtChoice asc) {
CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
- AppendStmt(ConfluenceBlock, C);
+ AppendStmt(ConfluenceBlock, C, asc);
if (!FinishBlock(ConfluenceBlock))
return 0;
@@ -555,11 +573,12 @@ CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) {
return LastBlock;
}
-CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C) {
+CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C,
+ AddStmtChoice asc) {
// Create the confluence block that will "merge" the results of the ternary
// expression.
CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
- AppendStmt(ConfluenceBlock, C);
+ AppendStmt(ConfluenceBlock, C, asc);
if (!FinishBlock(ConfluenceBlock))
return 0;
@@ -670,7 +689,10 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(Decl* D) {
case Stmt::StringLiteralClass:
break;
default:
- Block = addStmt(Init);
+ Block = addStmt(Init,
+ VD->getType()->isReferenceType()
+ ? AddStmtChoice::AlwaysAddAsLValue
+ : AddStmtChoice::AlwaysAdd);
}
}
@@ -754,7 +776,19 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) {
// Add the condition as the last statement in the new block. This may create
// new blocks as the condition may contain control-flow. Any newly created
// blocks will be pointed to be "Block".
- return addStmt(I->getCond());
+ Block = addStmt(I->getCond());
+
+ // Finally, if the IfStmt contains a condition variable, add both the IfStmt
+ // and the condition variable initialization to the CFG.
+ if (VarDecl *VD = I->getConditionVariable()) {
+ if (Expr *Init = VD->getInit()) {
+ autoCreateBlock();
+ AppendStmt(Block, I, AddStmtChoice::AlwaysAdd);
+ addStmt(Init);
+ }
+ }
+
+ return Block;
}
@@ -776,7 +810,7 @@ CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) {
// Add the return statement to the block. This may create new blocks if R
// contains control-flow (short-circuit operations).
- return VisitStmt(R, true);
+ return VisitStmt(R, AddStmtChoice::AlwaysAdd);
}
CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) {
@@ -854,6 +888,19 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
if (Stmt* C = F->getCond()) {
Block = ExitConditionBlock;
EntryConditionBlock = addStmt(C);
+ assert(Block == EntryConditionBlock);
+
+ // If this block contains a condition variable, add both the condition
+ // variable and initializer to the CFG.
+ if (VarDecl *VD = F->getConditionVariable()) {
+ if (Expr *Init = VD->getInit()) {
+ autoCreateBlock();
+ AppendStmt(Block, F, AddStmtChoice::AlwaysAdd);
+ EntryConditionBlock = addStmt(Init);
+ assert(Block == EntryConditionBlock);
+ }
+ }
+
if (Block) {
if (!FinishBlock(EntryConditionBlock))
return 0;
@@ -1000,7 +1047,7 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
// Walk the 'element' expression to see if there are any side-effects. We
// generate new blocks as necesary. We DON'T add the statement by default to
// the CFG unless it contains control-flow.
- EntryConditionBlock = Visit(S->getElement(), false);
+ EntryConditionBlock = Visit(S->getElement(), AddStmtChoice::NotAlwaysAdd);
if (Block) {
if (!FinishBlock(EntryConditionBlock))
return 0;
@@ -1096,6 +1143,18 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
Block = ExitConditionBlock;
EntryConditionBlock = addStmt(C);
assert(Block == EntryConditionBlock);
+
+ // If this block contains a condition variable, add both the condition
+ // variable and initializer to the CFG.
+ if (VarDecl *VD = W->getConditionVariable()) {
+ if (Expr *Init = VD->getInit()) {
+ autoCreateBlock();
+ AppendStmt(Block, W, AddStmtChoice::AlwaysAdd);
+ EntryConditionBlock = addStmt(Init);
+ assert(Block == EntryConditionBlock);
+ }
+ }
+
if (Block) {
if (!FinishBlock(EntryConditionBlock))
return 0;
@@ -1182,7 +1241,7 @@ CFGBlock* CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt* S) {
// Add the statement to the block. This may create new blocks if S contains
// control-flow (short-circuit operations).
- return VisitStmt(S, true);
+ return VisitStmt(S, AddStmtChoice::AlwaysAdd);
}
CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) {
@@ -1198,7 +1257,7 @@ CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) {
// Add the statement to the block. This may create new blocks if S contains
// control-flow (short-circuit operations).
- return VisitStmt(T, true);
+ return VisitStmt(T, AddStmtChoice::AlwaysAdd);
}
CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) {
@@ -1316,9 +1375,9 @@ CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) {
}
CFGBlock *CFGBuilder::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E,
- bool alwaysAdd) {
+ AddStmtChoice asc) {
- if (alwaysAdd) {
+ if (asc.alwaysAdd()) {
autoCreateBlock();
AppendStmt(Block, E);
}
@@ -1335,8 +1394,8 @@ CFGBlock *CFGBuilder::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E,
/// VisitStmtExpr - Utility method to handle (nested) statement
/// expressions (a GCC extension).
-CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, bool alwaysAdd) {
- if (alwaysAdd) {
+CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {
+ if (asc.alwaysAdd()) {
autoCreateBlock();
AppendStmt(Block, SE);
}
@@ -1391,8 +1450,19 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
SwitchTerminatedBlock->setTerminator(Terminator);
assert (Terminator->getCond() && "switch condition must be non-NULL");
Block = SwitchTerminatedBlock;
-
- return addStmt(Terminator->getCond());
+ Block = addStmt(Terminator->getCond());
+
+ // Finally, if the SwitchStmt contains a condition variable, add both the
+ // SwitchStmt and the condition variable initialization to the CFG.
+ if (VarDecl *VD = Terminator->getConditionVariable()) {
+ if (Expr *Init = VD->getInit()) {
+ autoCreateBlock();
+ AppendStmt(Block, Terminator, AddStmtChoice::AlwaysAdd);
+ addStmt(Init);
+ }
+ }
+
+ return Block;
}
CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) {
@@ -1514,17 +1584,20 @@ namespace {
typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy;
}
-static void FindSubExprAssignments(Stmt* Terminator, llvm::SmallPtrSet<Expr*,50>& Set) {
- if (!Terminator)
+static void FindSubExprAssignments(Stmt *S,
+ llvm::SmallPtrSet<Expr*,50>& Set) {
+ if (!S)
return;
- for (Stmt::child_iterator I=Terminator->child_begin(), E=Terminator->child_end(); I!=E; ++I) {
- if (!*I) continue;
-
- if (BinaryOperator* B = dyn_cast<BinaryOperator>(*I))
+ for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) {
+ Stmt *child = *I;
+ if (!child)
+ continue;
+
+ if (BinaryOperator* B = dyn_cast<BinaryOperator>(child))
if (B->isAssignmentOp()) Set.insert(B);
- FindSubExprAssignments(*I, Set);
+ FindSubExprAssignments(child, Set);
}
}
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index 9639ad9..a15a8f1 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -1149,7 +1149,11 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// [PR 3337] Use 'getAs<FunctionType>' to strip away any typedefs on the
// function's type.
const FunctionType* FT = FD->getType()->getAs<FunctionType>();
- const char* FName = FD->getIdentifier()->getNameStart();
+ const IdentifierInfo *II = FD->getIdentifier();
+ if (!II)
+ break;
+
+ const char* FName = II->getNameStart();
// Strip away preceding '_'. Doing this here will effect all the checks
// down below.
@@ -2938,6 +2942,17 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
QualType T = Ex->getType();
+ // For CallExpr, use the result type to know if it returns a reference.
+ if (const CallExpr *CE = dyn_cast<CallExpr>(Ex)) {
+ const Expr *Callee = CE->getCallee();
+ if (const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl())
+ T = FD->getResultType();
+ }
+ else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(Ex)) {
+ if (const ObjCMethodDecl *MD = ME->getMethodDecl())
+ T = MD->getResultType();
+ }
+
if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
unsigned Count = Builder.getCurrentBlockCount();
ValueManager &ValMgr = Eng.getValueManager();
diff --git a/lib/Analysis/CallInliner.cpp b/lib/Analysis/CallInliner.cpp
index 43523c2..d18bbcc 100644
--- a/lib/Analysis/CallInliner.cpp
+++ b/lib/Analysis/CallInliner.cpp
@@ -11,36 +11,46 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/LocalCheckers.h"
using namespace clang;
namespace {
-
-class CallInliner : public GRTransferFuncs {
- ASTContext &Ctx;
+class CallInliner : public Checker {
public:
- CallInliner(ASTContext &ctx) : Ctx(ctx) {}
+ static void *getTag() {
+ static int x;
+ return &x;
+ }
- void EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine,
- GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L,
- ExplodedNode* Pred);
-
+ virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
+ virtual void EvalEndPath(GREndPathNodeBuilder &B,void *tag,GRExprEngine &Eng);
};
+}
+void clang::RegisterCallInliner(GRExprEngine &Eng) {
+ Eng.registerCheck(new CallInliner());
}
-void CallInliner::EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine,
- GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L,
- ExplodedNode* Pred) {
- FunctionDecl const *FD = L.getAsFunctionDecl();
+bool CallInliner::EvalCallExpr(CheckerContext &C, const CallExpr *CE) {
+ const GRState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = state->getSVal(Callee);
+
+ const FunctionDecl *FD = L.getAsFunctionDecl();
if (!FD)
- return; // GRExprEngine is responsible for the autotransition.
+ return false;
+
+ if (!FD->isThisDeclarationADefinition())
+ return false;
+ GRStmtNodeBuilder &Builder = C.getNodeBuilder();
// Make a new LocationContext.
- StackFrameContext const *LocCtx =
- Engine.getAnalysisManager().getStackFrame(FD, Pred->getLocationContext(), CE);
+ const StackFrameContext *LocCtx = C.getAnalysisManager().getStackFrame(FD,
+ C.getPredecessor()->getLocationContext(), CE,
+ Builder.getBlock(), Builder.getIndex());
CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry());
@@ -54,22 +64,50 @@ void CallInliner::EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine,
// Construct an edge representing the starting location in the function.
BlockEdge Loc(Entry, SuccB, LocCtx);
- GRState const *state = Builder.GetState(Pred);
- state = Engine.getStoreManager().EnterStackFrame(state, LocCtx);
-
+ state = C.getStoreManager().EnterStackFrame(state, LocCtx);
+ // This is a hack. We really should not use the GRStmtNodeBuilder.
bool isNew;
- ExplodedNode *SuccN = Engine.getGraph().getNode(Loc, state, &isNew);
- SuccN->addPredecessor(Pred, Engine.getGraph());
-
- Builder.Deferred.erase(Pred);
+ GRExprEngine &Eng = C.getEngine();
+ ExplodedNode *Pred = C.getPredecessor();
+
- // This is a hack. We really should not use the GRStmtNodeBuilder.
+ ExplodedNode *SuccN = Eng.getGraph().getNode(Loc, state, &isNew);
+ SuccN->addPredecessor(Pred, Eng.getGraph());
+ C.getNodeBuilder().Deferred.erase(Pred);
+
if (isNew)
Builder.getWorkList()->Enqueue(SuccN);
Builder.HasGeneratedNode = true;
+
+ return true;
}
-
-GRTransferFuncs *clang::CreateCallInliner(ASTContext &ctx) {
- return new CallInliner(ctx);
+
+void CallInliner::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
+ GRExprEngine &Eng) {
+ const GRState *state = B.getState();
+ ExplodedNode *Pred = B.getPredecessor();
+ const StackFrameContext *LocCtx =
+ cast<StackFrameContext>(Pred->getLocationContext());
+
+ const Stmt *CE = LocCtx->getCallSite();
+
+ // Check if this is the top level stack frame.
+ if (!LocCtx->getParent())
+ return;
+
+ PostStmt NodeLoc(CE, LocCtx->getParent());
+
+ bool isNew;
+ ExplodedNode *Succ = Eng.getGraph().getNode(NodeLoc, state, &isNew);
+ Succ->addPredecessor(Pred, Eng.getGraph());
+
+ // When creating the new work list unit, increment the statement index to
+ // point to the statement after the CallExpr.
+ if (isNew)
+ B.getWorkList().Enqueue(Succ,
+ *const_cast<CFGBlock*>(LocCtx->getCallSiteBlock()),
+ LocCtx->getIndex() + 1);
+
+ B.HasGeneratedNode = true;
}
diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp
index db9016f..6e4d899 100644
--- a/lib/Analysis/CheckDeadStores.cpp
+++ b/lib/Analysis/CheckDeadStores.cpp
@@ -84,7 +84,14 @@ public:
const LiveVariables::AnalysisDataTy& AD,
const LiveVariables::ValTy& Live) {
- if (VD->hasLocalStorage() && !Live(VD, AD) &&
+ if (!VD->hasLocalStorage())
+ return;
+ // Reference types confuse the dead stores checker. Skip them
+ // for now.
+ if (VD->getType()->getAs<ReferenceType>())
+ return;
+
+ if (!Live(VD, AD) &&
!(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>()))
Report(VD, dsk, Ex->getSourceRange().getBegin(),
Val->getSourceRange());
@@ -93,7 +100,6 @@ public:
void CheckDeclRef(DeclRefExpr* DR, Expr* Val, DeadStoreKind dsk,
const LiveVariables::AnalysisDataTy& AD,
const LiveVariables::ValTy& Live) {
-
if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
CheckVarDecl(VD, DR, Val, dsk, AD, Live);
}
@@ -183,13 +189,22 @@ public:
if (!V)
continue;
-
- if (V->hasLocalStorage())
+
+ if (V->hasLocalStorage()) {
+ // Reference types confuse the dead stores checker. Skip them
+ // for now.
+ if (V->getType()->getAs<ReferenceType>())
+ return;
+
if (Expr* E = V->getInit()) {
// Don't warn on C++ objects (yet) until we can show that their
// constructors/destructors don't have side effects.
if (isa<CXXConstructExpr>(E))
return;
+
+ if (isa<CXXExprWithTemporaries>(E))
+ return;
+
// A dead initialization is a variable that is dead after it
// is initialized. We don't flag warnings for those variables
// marked 'unused'.
@@ -218,6 +233,7 @@ public:
Report(V, DeadInit, V->getLocation(), E->getSourceRange());
}
}
+ }
}
}
};
diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Analysis/GRCoreEngine.cpp
index 644dd19..209452a 100644
--- a/lib/Analysis/GRCoreEngine.cpp
+++ b/lib/Analysis/GRCoreEngine.cpp
@@ -122,8 +122,8 @@ void GRCoreEngine::ProcessEndPath(GREndPathNodeBuilder& Builder) {
SubEngine.ProcessEndPath(Builder);
}
-void GRCoreEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& Builder) {
- SubEngine.ProcessStmt(S, Builder);
+void GRCoreEngine::ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder) {
+ SubEngine.ProcessStmt(E, Builder);
}
bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const GRState* State,
@@ -213,9 +213,9 @@ void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
CFGBlock* Blk = L.getDst();
// Check if we are entering the EXIT block.
- if (Blk == &(Pred->getLocationContext()->getCFG()->getExit())) {
+ if (Blk == &(L.getLocationContext()->getCFG()->getExit())) {
- assert (Pred->getLocationContext()->getCFG()->getExit().size() == 0
+ assert (L.getLocationContext()->getCFG()->getExit().size() == 0
&& "EXIT block cannot contain Stmts.");
// Process the final state transition.
@@ -241,10 +241,10 @@ void GRCoreEngine::HandleBlockEntrance(const BlockEntrance& L,
WList->setBlockCounter(Counter);
// Process the entrance of the block.
- if (Stmt* S = L.getFirstStmt()) {
+ if (CFGElement E = L.getFirstElement()) {
GRStmtNodeBuilder Builder(L.getBlock(), 0, Pred, this,
SubEngine.getStateManager());
- ProcessStmt(S, Builder);
+ ProcessStmt(E, Builder);
}
else
HandleBlockExit(L.getBlock(), Pred);
@@ -447,7 +447,7 @@ GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* state,
ProgramPoint::Kind K,
const void *tag) {
- const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag);
+ const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag);
return generateNodeInternal(L, state, Pred);
}
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 51e6a54..2ce8edd 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -33,6 +33,7 @@
using namespace clang;
using llvm::dyn_cast;
+using llvm::dyn_cast_or_null;
using llvm::cast;
using llvm::APSInt;
@@ -45,6 +46,29 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
return Ctx.Selectors.getSelector(0, &II);
}
+
+static bool CalleeReturnsReference(const CallExpr *CE) {
+ const Expr *Callee = CE->getCallee();
+ QualType T = Callee->getType();
+
+ if (const PointerType *PT = T->getAs<PointerType>()) {
+ const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>();
+ T = FT->getResultType();
+ }
+ else {
+ const BlockPointerType *BT = T->getAs<BlockPointerType>();
+ T = BT->getPointeeType()->getAs<FunctionType>()->getResultType();
+ }
+ return T->isReferenceType();
+}
+
+static bool ReceiverReturnsReference(const ObjCMessageExpr *ME) {
+ const ObjCMethodDecl *MD = ME->getMethodDecl();
+ if (!MD)
+ return false;
+ return MD->getResultType()->isReferenceType();
+}
+
//===----------------------------------------------------------------------===//
// Batch auditor. DEPRECATED.
//===----------------------------------------------------------------------===//
@@ -227,7 +251,7 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
CurrSet->clear();
}
-
+
void *tag = I->first;
Checker *checker = I->second;
@@ -306,8 +330,9 @@ GRExprEngine::~GRExprEngine() {
// Utility methods.
//===----------------------------------------------------------------------===//
-void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) {
+void GRExprEngine::setTransferFunctionsAndCheckers(GRTransferFuncs* tf) {
StateMgr.TF = tf;
+ StateMgr.Checkers = &Checkers;
tf->RegisterChecks(*this);
tf->RegisterPrinters(getStateManager().Printers);
}
@@ -333,43 +358,55 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
// FIXME: It would be nice if we had a more general mechanism to add
// such preconditions. Some day.
- const Decl *D = InitLoc->getDecl();
-
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- // Precondition: the first argument of 'main' is an integer guaranteed
- // to be > 0.
- if (FD->getIdentifier()->getName() == "main" &&
- FD->getNumParams() > 0) {
+ do {
+ const Decl *D = InitLoc->getDecl();
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // Precondition: the first argument of 'main' is an integer guaranteed
+ // to be > 0.
+ const IdentifierInfo *II = FD->getIdentifier();
+ if (!II || !(II->getName() == "main" && FD->getNumParams() > 0))
+ break;
+
const ParmVarDecl *PD = FD->getParamDecl(0);
QualType T = PD->getType();
- if (T->isIntegerType())
- if (const MemRegion *R = state->getRegion(PD, InitLoc)) {
- SVal V = state->getSVal(loc::MemRegionVal(R));
- SVal Constraint_untested = EvalBinOp(state, BinaryOperator::GT, V,
- ValMgr.makeZeroVal(T),
- getContext().IntTy);
-
- if (DefinedOrUnknownSVal *Constraint =
- dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested)) {
- if (const GRState *newState = state->Assume(*Constraint, true))
- state = newState;
- }
- }
+ if (!T->isIntegerType())
+ break;
+
+ const MemRegion *R = state->getRegion(PD, InitLoc);
+ if (!R)
+ break;
+
+ SVal V = state->getSVal(loc::MemRegionVal(R));
+ SVal Constraint_untested = EvalBinOp(state, BinaryOperator::GT, V,
+ ValMgr.makeZeroVal(T),
+ getContext().IntTy);
+
+ DefinedOrUnknownSVal *Constraint =
+ dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested);
+
+ if (!Constraint)
+ break;
+
+ if (const GRState *newState = state->Assume(*Constraint, true))
+ state = newState;
+
+ break;
}
- }
- else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- // Precondition: 'self' is always non-null upon entry to an Objective-C
- // method.
- const ImplicitParamDecl *SelfD = MD->getSelfDecl();
- const MemRegion *R = state->getRegion(SelfD, InitLoc);
- SVal V = state->getSVal(loc::MemRegionVal(R));
+
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ // Precondition: 'self' is always non-null upon entry to an Objective-C
+ // method.
+ const ImplicitParamDecl *SelfD = MD->getSelfDecl();
+ const MemRegion *R = state->getRegion(SelfD, InitLoc);
+ SVal V = state->getSVal(loc::MemRegionVal(R));
- if (const Loc *LV = dyn_cast<Loc>(&V)) {
- // Assume that the pointer value in 'self' is non-null.
- state = state->Assume(*LV, true);
- assert(state && "'self' cannot be null");
+ if (const Loc *LV = dyn_cast<Loc>(&V)) {
+ // Assume that the pointer value in 'self' is non-null.
+ state = state->Assume(*LV, true);
+ assert(state && "'self' cannot be null");
+ }
}
- }
+ } while (0);
return state;
}
@@ -378,17 +415,15 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
// Top-level transfer function logic (Dispatcher).
//===----------------------------------------------------------------------===//
-void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
-
+void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) {
+ CurrentStmt = CE.getStmt();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
- S->getLocStart(),
+ CurrentStmt->getLocStart(),
"Error evaluating statement");
Builder = &builder;
EntryNode = builder.getLastNode();
- CurrentStmt = S;
-
// Set up our simple checks.
if (BatchAuditor)
Builder->setAuditor(BatchAuditor.get());
@@ -415,7 +450,7 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
// FIXME: This should soon be removed.
ExplodedNodeSet Tmp2;
- getTF().EvalDeadSymbols(Tmp2, *this, *Builder, EntryNode, S,
+ getTF().EvalDeadSymbols(Tmp2, *this, *Builder, EntryNode, CurrentStmt,
CleanedState, SymReaper);
if (Checkers.empty())
@@ -437,8 +472,8 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
Checker *checker = I->second;
for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end();
NI != NE; ++NI)
- checker->GR_EvalDeadSymbols(*DstSet, *Builder, *this, S, *NI,
- SymReaper, tag);
+ checker->GR_EvalDeadSymbols(*DstSet, *Builder, *this, CurrentStmt,
+ *NI, SymReaper, tag);
SrcSet = DstSet;
}
}
@@ -457,7 +492,10 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
Builder->SetCleanedState(*I == EntryNode ? CleanedState : GetState(*I));
// Visit the statement.
- Visit(S, *I, Dst);
+ if (CE.asLValue())
+ VisitLValue(cast<Expr>(CurrentStmt), *I, Dst);
+ else
+ Visit(CurrentStmt, *I, Dst);
// Do we need to auto-generate a node? We only need to do this to generate
// a node with a "cleaned" state; GRCoreEngine will actually handle
@@ -465,7 +503,7 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
if (Dst.size() == 1 && *Dst.begin() == EntryNode
&& !Builder->HasGeneratedNode && !HasAutoGenerated) {
HasAutoGenerated = true;
- builder.generateNode(S, GetState(EntryNode), *I);
+ builder.generateNode(CurrentStmt, GetState(EntryNode), *I);
}
}
@@ -504,7 +542,6 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
case Stmt::CXXTypeidExprClass:
case Stmt::CXXBoolLiteralExprClass:
case Stmt::CXXNullPtrLiteralExprClass:
- case Stmt::CXXThisExprClass:
case Stmt::CXXThrowExprClass:
case Stmt::CXXDefaultArgExprClass:
case Stmt::CXXZeroInitValueExprClass:
@@ -565,7 +602,8 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
break;
}
- if (AMgr.shouldEagerlyAssume() && (B->isRelationalOp() || B->isEqualityOp())) {
+ if (AMgr.shouldEagerlyAssume() &&
+ (B->isRelationalOp() || B->isEqualityOp())) {
ExplodedNodeSet Tmp;
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp, false);
EvalEagerlyAssume(Dst, Tmp, cast<Expr>(S));
@@ -579,7 +617,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass: {
CallExpr* C = cast<CallExpr>(S);
- VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
+ VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, false);
break;
}
@@ -606,6 +644,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
break;
}
+ case Stmt::CXXThisExprClass:
+ VisitCXXThisExpr(cast<CXXThisExpr>(S), Pred, Dst);
+ break;
+
case Stmt::DeclRefExprClass:
VisitDeclRefExpr(cast<DeclRefExpr>(S), Pred, Dst, false);
break;
@@ -614,12 +656,24 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst);
break;
+ case Stmt::ForStmtClass:
+ // This case isn't for branch processing, but for handling the
+ // initialization of a condition variable.
+ VisitCondInit(cast<ForStmt>(S)->getConditionVariable(), S, Pred, Dst);
+ break;
+
case Stmt::ImplicitCastExprClass:
case Stmt::CStyleCastExprClass: {
CastExpr* C = cast<CastExpr>(S);
- VisitCast(C, C->getSubExpr(), Pred, Dst);
+ VisitCast(C, C->getSubExpr(), Pred, Dst, false);
break;
}
+
+ case Stmt::IfStmtClass:
+ // This case isn't for branch processing, but for handling the
+ // initialization of a condition variable.
+ VisitCondInit(cast<IfStmt>(S)->getConditionVariable(), S, Pred, Dst);
+ break;
case Stmt::InitListExprClass:
VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
@@ -637,10 +691,9 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst);
break;
- case Stmt::ObjCMessageExprClass: {
- VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst);
+ case Stmt::ObjCMessageExprClass:
+ VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst, false);
break;
- }
case Stmt::ObjCAtThrowStmtClass: {
// FIXME: This is not complete. We basically treat @throw as
@@ -687,10 +740,16 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
case Stmt::StringLiteralClass:
VisitLValue(cast<StringLiteral>(S), Pred, Dst);
break;
+
+ case Stmt::SwitchStmtClass:
+ // This case isn't for branch processing, but for handling the
+ // initialization of a condition variable.
+ VisitCondInit(cast<SwitchStmt>(S)->getConditionVariable(), S, Pred, Dst);
+ break;
case Stmt::UnaryOperatorClass: {
UnaryOperator *U = cast<UnaryOperator>(S);
- if (AMgr.shouldEagerlyAssume() && (U->getOpcode() == UnaryOperator::LNot)) {
+ if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UnaryOperator::LNot)) {
ExplodedNodeSet Tmp;
VisitUnaryOperator(U, Pred, Tmp, false);
EvalEagerlyAssume(Dst, Tmp, U);
@@ -699,48 +758,92 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
VisitUnaryOperator(U, Pred, Dst, false);
break;
}
+
+ case Stmt::WhileStmtClass:
+ // This case isn't for branch processing, but for handling the
+ // initialization of a condition variable.
+ VisitCondInit(cast<WhileStmt>(S)->getConditionVariable(), S, Pred, Dst);
+ break;
}
}
void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
+
+ PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+ Ex->getLocStart(),
+ "Error evaluating statement");
+
Ex = Ex->IgnoreParens();
- if (Ex != CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)) {
+ if (Ex != CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)){
Dst.Add(Pred);
return;
}
switch (Ex->getStmtClass()) {
+ // C++ stuff we don't support yet.
+ case Stmt::CXXExprWithTemporariesClass:
+ case Stmt::CXXMemberCallExprClass:
+ case Stmt::CXXZeroInitValueExprClass: {
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+ Builder->BuildSinks = true;
+ MakeNode(Dst, Ex, Pred, GetState(Pred));
+ break;
+ }
case Stmt::ArraySubscriptExprClass:
VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(Ex), Pred, Dst, true);
return;
+ case Stmt::BinaryOperatorClass:
+ case Stmt::CompoundAssignOperatorClass:
+ VisitBinaryOperator(cast<BinaryOperator>(Ex), Pred, Dst, true);
+ return;
+
case Stmt::BlockDeclRefExprClass:
VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(Ex), Pred, Dst, true);
return;
+
+ case Stmt::CallExprClass:
+ case Stmt::CXXOperatorCallExprClass: {
+ CallExpr *C = cast<CallExpr>(Ex);
+ assert(CalleeReturnsReference(C));
+ VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true);
+ break;
+ }
+
+ case Stmt::CompoundLiteralExprClass:
+ VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(Ex), Pred, Dst, true);
+ return;
case Stmt::DeclRefExprClass:
VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true);
return;
-
- case Stmt::ObjCIvarRefExprClass:
- VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(Ex), Pred, Dst, true);
- return;
-
- case Stmt::UnaryOperatorClass:
- VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true);
- return;
-
+
+ case Stmt::ImplicitCastExprClass:
+ case Stmt::CStyleCastExprClass: {
+ CastExpr *C = cast<CastExpr>(Ex);
+ QualType T = Ex->getType();
+ VisitCast(C, C->getSubExpr(), Pred, Dst, true);
+ break;
+ }
+
case Stmt::MemberExprClass:
VisitMemberExpr(cast<MemberExpr>(Ex), Pred, Dst, true);
return;
- case Stmt::CompoundLiteralExprClass:
- VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(Ex), Pred, Dst, true);
+ case Stmt::ObjCIvarRefExprClass:
+ VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(Ex), Pred, Dst, true);
+ return;
+
+ case Stmt::ObjCMessageExprClass: {
+ ObjCMessageExpr *ME = cast<ObjCMessageExpr>(Ex);
+ assert(ReceiverReturnsReference(ME));
+ VisitObjCMessageExpr(ME, Pred, Dst, true);
return;
+ }
case Stmt::ObjCPropertyRefExprClass:
case Stmt::ObjCImplicitSetterGetterRefExprClass:
@@ -765,11 +868,10 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
return;
}
- case Stmt::BinaryOperatorClass:
- case Stmt::CompoundAssignOperatorClass:
- VisitBinaryOperator(cast<BinaryOperator>(Ex), Pred, Dst, true);
+ case Stmt::UnaryOperatorClass:
+ VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true);
return;
-
+
default:
// Arbitrary subexpressions can return aggregate temporaries that
// can be used in a lvalue context. We need to enhance our support
@@ -1023,7 +1125,8 @@ void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) {
void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R,
ExplodedNode* Pred, ExplodedNodeSet& Dst) {
- assert (Ex == CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(Ex));
+ assert(Ex == CurrentStmt &&
+ Pred->getLocationContext()->getCFG()->isBlkExpr(Ex));
const GRState* state = GetState(Pred);
SVal X = state->getSVal(Ex);
@@ -1147,7 +1250,7 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred,
assert(B->getOpcode() == BinaryOperator::LAnd ||
B->getOpcode() == BinaryOperator::LOr);
- assert(B == CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B));
+ assert(B==CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B));
const GRState* state = GetState(Pred);
SVal X = state->getSVal(B);
@@ -1232,13 +1335,23 @@ void GRExprEngine::VisitCommonDeclRefExpr(Expr *Ex, const NamedDecl *D,
SVal V = state->getLValue(VD, Pred->getLocationContext());
- if (asLValue)
+ if (asLValue) {
+ // For references, the 'lvalue' is the pointer address stored in the
+ // reference region.
+ if (VD->getType()->isReferenceType()) {
+ if (const MemRegion *R = V.getAsRegion())
+ V = state->getSVal(R);
+ else
+ V = UnknownVal();
+ }
+
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
ProgramPoint::PostLValueKind);
+ }
else
EvalLoad(Dst, Ex, Pred, state, V);
- return;
+ return;
} else if (const EnumConstantDecl* ED = dyn_cast<EnumConstantDecl>(D)) {
assert(!asLValue && "EnumConstantDecl does not have lvalue.");
@@ -1415,6 +1528,37 @@ void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred,
const GRState* state, SVal location,
const void *tag, QualType LoadTy) {
+ // Are we loading from a region? This actually results in two loads; one
+ // to fetch the address of the referenced value and one to fetch the
+ // referenced value.
+ if (const TypedRegion *TR =
+ dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
+
+ QualType ValTy = TR->getValueType(getContext());
+ if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) {
+ static int loadReferenceTag = 0;
+ ExplodedNodeSet Tmp;
+ EvalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag,
+ getContext().getPointerType(RT->getPointeeType()));
+
+ // Perform the load from the referenced value.
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end() ; I!=E; ++I) {
+ state = GetState(*I);
+ location = state->getSVal(Ex);
+ EvalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy);
+ }
+ return;
+ }
+ }
+
+ EvalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy);
+}
+
+void GRExprEngine::EvalLoadCommon(ExplodedNodeSet& Dst, Expr *Ex,
+ ExplodedNode* Pred,
+ const GRState* state, SVal location,
+ const void *tag, QualType LoadTy) {
+
// Evaluate the location (checks for bad dereferences).
ExplodedNodeSet Tmp;
EvalLocation(Tmp, Ex, Pred, state, location, tag, true);
@@ -1489,94 +1633,111 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
// Transfer function: Function calls.
//===----------------------------------------------------------------------===//
+namespace {
+class CallExprWLItem {
+public:
+ CallExpr::arg_iterator I;
+ ExplodedNode *N;
+
+ CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n)
+ : I(i), N(n) {}
+};
+} // end anonymous namespace
+
void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
CallExpr::arg_iterator AI,
CallExpr::arg_iterator AE,
- ExplodedNodeSet& Dst) {
+ ExplodedNodeSet& Dst, bool asLValue) {
+
// Determine the type of function we're calling (if available).
const FunctionProtoType *Proto = NULL;
QualType FnType = CE->getCallee()->IgnoreParens()->getType();
if (const PointerType *FnTypePtr = FnType->getAs<PointerType>())
Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>();
- VisitCallRec(CE, Pred, AI, AE, Dst, Proto, /*ParamIdx=*/0);
-}
-
-void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred,
- CallExpr::arg_iterator AI,
- CallExpr::arg_iterator AE,
- ExplodedNodeSet& Dst,
- const FunctionProtoType *Proto,
- unsigned ParamIdx) {
+ // Create a worklist to process the arguments.
+ llvm::SmallVector<CallExprWLItem, 20> WorkList;
+ WorkList.reserve(AE - AI);
+ WorkList.push_back(CallExprWLItem(AI, Pred));
+
+ ExplodedNodeSet ArgsEvaluated;
- // Process the arguments.
- if (AI != AE) {
- // If the call argument is being bound to a reference parameter,
- // visit it as an lvalue, not an rvalue.
+ while (!WorkList.empty()) {
+ CallExprWLItem Item = WorkList.back();
+ WorkList.pop_back();
+
+ if (Item.I == AE) {
+ ArgsEvaluated.insert(Item.N);
+ continue;
+ }
+
+ // Evaluate the argument.
+ ExplodedNodeSet Tmp;
+ const unsigned ParamIdx = Item.I - AI;
+
bool VisitAsLvalue = false;
if (Proto && ParamIdx < Proto->getNumArgs())
VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();
-
- ExplodedNodeSet DstTmp;
+
if (VisitAsLvalue)
- VisitLValue(*AI, Pred, DstTmp);
+ VisitLValue(*Item.I, Item.N, Tmp);
else
- Visit(*AI, Pred, DstTmp);
- ++AI;
+ Visit(*Item.I, Item.N, Tmp);
+
+ // Enqueue evaluating the next argument on the worklist.
+ ++(Item.I);
- for (ExplodedNodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE;
- ++DI)
- VisitCallRec(CE, *DI, AI, AE, Dst, Proto, ParamIdx + 1);
-
- return;
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
+ WorkList.push_back(CallExprWLItem(Item.I, *NI));
}
- // If we reach here we have processed all of the arguments. Evaluate
- // the callee expression.
+ // Now process the call itself.
ExplodedNodeSet DstTmp;
Expr* Callee = CE->getCallee()->IgnoreParens();
-
- { // Enter new scope to make the lifetime of 'DstTmp2' bounded.
+
+ for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(),
+ NE=ArgsEvaluated.end(); NI != NE; ++NI) {
+ // Evaluate the callee.
ExplodedNodeSet DstTmp2;
- Visit(Callee, Pred, DstTmp2);
-
+ Visit(Callee, *NI, DstTmp2);
// Perform the previsit of the CallExpr, storing the results in DstTmp.
CheckerVisit(CE, DstTmp, DstTmp2, true);
}
-
- // Finally, evaluate the function call.
+
+ // Finally, evaluate the function call. We try each of the checkers
+ // to see if the can evaluate the function call.
ExplodedNodeSet DstTmp3;
+
for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
DI != DE; ++DI) {
-
+
const GRState* state = GetState(*DI);
SVal L = state->getSVal(Callee);
-
+
// FIXME: Add support for symbolic function calls (calls involving
// function pointer values that are symbolic).
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
ExplodedNodeSet DstChecker;
-
+
// If the callee is processed by a checker, skip the rest logic.
if (CheckerEvalCall(CE, DstChecker, *DI))
DstTmp3.insert(DstChecker);
else {
for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(),
- DE_Checker = DstChecker.end();
- DI_Checker != DE_Checker; ++DI_Checker) {
-
- // Dispatch to the plug-in transfer function.
+ DE_Checker = DstChecker.end();
+ DI_Checker != DE_Checker; ++DI_Checker) {
+
+ // Dispatch to the plug-in transfer function.
unsigned OldSize = DstTmp3.size();
SaveOr OldHasGen(Builder->HasGeneratedNode);
Pred = *DI_Checker;
-
+
// Dispatch to transfer function logic to handle the call itself.
// FIXME: Allow us to chain together transfer functions.
- assert(Builder && "GRStmtNodeBuilder must be defined.");
-
+ assert(Builder && "GRStmtNodeBuilder must be defined.");
getTF().EvalCall(DstTmp3, *this, *Builder, CE, L, Pred);
-
+
// Handle the case where no nodes where generated. Auto-generate that
// contains the updated state if we aren't generating sinks.
if (!Builder->BuildSinks && DstTmp3.size() == OldSize &&
@@ -1585,9 +1746,31 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred,
}
}
}
-
- // Perform the post-condition check of the CallExpr.
- CheckerVisit(CE, Dst, DstTmp3, false);
+
+ // Finally, perform the post-condition check of the CallExpr and store
+ // the created nodes in 'Dst'.
+
+ if (!(!asLValue && CalleeReturnsReference(CE))) {
+ CheckerVisit(CE, Dst, DstTmp3, false);
+ return;
+ }
+
+ // Handle the case where the called function returns a reference but
+ // we expect an rvalue. For such cases, convert the reference to
+ // an rvalue.
+ // FIXME: This conversion doesn't actually happen unless the result
+ // of CallExpr is consumed by another expression.
+ ExplodedNodeSet DstTmp4;
+ CheckerVisit(CE, DstTmp4, DstTmp3, false);
+ QualType LoadTy = CE->getType();
+
+ static int *ConvertToRvalueTag = 0;
+ for (ExplodedNodeSet::iterator NI = DstTmp4.begin(), NE = DstTmp4.end();
+ NI!=NE; ++NI) {
+ const GRState *state = GetState(*NI);
+ EvalLoad(Dst, CE, *NI, state, state->getSVal(CE),
+ &ConvertToRvalueTag, LoadTy);
+ }
}
//===----------------------------------------------------------------------===//
@@ -1764,16 +1947,18 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S,
//===----------------------------------------------------------------------===//
void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
- ExplodedNodeSet& Dst){
+ ExplodedNodeSet& Dst, bool asLValue){
VisitObjCMessageExprArgHelper(ME, ME->arg_begin(), ME->arg_end(),
- Pred, Dst);
+ Pred, Dst, asLValue);
}
void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
- ObjCMessageExpr::arg_iterator AI,
- ObjCMessageExpr::arg_iterator AE,
- ExplodedNode* Pred, ExplodedNodeSet& Dst) {
+ ObjCMessageExpr::arg_iterator AI,
+ ObjCMessageExpr::arg_iterator AE,
+ ExplodedNode* Pred,
+ ExplodedNodeSet& Dst,
+ bool asLValue) {
if (AI == AE) {
// Process the receiver.
@@ -1784,12 +1969,12 @@ void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE;
++NI)
- VisitObjCMessageExprDispatchHelper(ME, *NI, Dst);
+ VisitObjCMessageExprDispatchHelper(ME, *NI, Dst, asLValue);
return;
}
- VisitObjCMessageExprDispatchHelper(ME, Pred, Dst);
+ VisitObjCMessageExprDispatchHelper(ME, Pred, Dst, asLValue);
return;
}
@@ -1799,12 +1984,13 @@ void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
++AI;
for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI)
- VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst);
+ VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst, asLValue);
}
void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
+ ExplodedNodeSet& Dst,
+ bool asLValue) {
// Handle previsits checks.
ExplodedNodeSet Src, DstTmp;
@@ -1812,12 +1998,17 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
CheckerVisit(ME, DstTmp, Src, true);
- unsigned size = Dst.size();
+ ExplodedNodeSet PostVisitSrc;
for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
DI!=DE; ++DI) {
+
Pred = *DI;
bool RaisesException = false;
+
+ unsigned OldSize = PostVisitSrc.size();
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
if (const Expr *Receiver = ME->getReceiver()) {
const GRState *state = Pred->getState();
@@ -1832,8 +2023,8 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
// There are three cases: can be nil or non-nil, must be nil, must be
// non-nil. We handle must be nil, and merge the rest two into non-nil.
if (nilState && !notNilState) {
- CheckerEvalNilReceiver(ME, Dst, nilState, Pred);
- return;
+ CheckerEvalNilReceiver(ME, PostVisitSrc, nilState, Pred);
+ continue;
}
assert(notNilState);
@@ -1844,39 +2035,29 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
// Check if we raise an exception. For now treat these as sinks.
// Eventually we will want to handle exceptions properly.
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
if (RaisesException)
Builder->BuildSinks = true;
// Dispatch to plug-in transfer function.
- SaveOr OldHasGen(Builder->HasGeneratedNode);
- EvalObjCMessageExpr(Dst, ME, Pred, notNilState);
+ EvalObjCMessageExpr(PostVisitSrc, ME, Pred, notNilState);
}
else {
-
IdentifierInfo* ClsName = ME->getClassName();
Selector S = ME->getSelector();
// Check for special instance methods.
-
if (!NSExceptionII) {
ASTContext& Ctx = getContext();
-
NSExceptionII = &Ctx.Idents.get("NSException");
}
if (ClsName == NSExceptionII) {
-
enum { NUM_RAISE_SELECTORS = 2 };
// Lazily create a cache of the selectors.
-
if (!NSExceptionInstanceRaiseSelectors) {
-
ASTContext& Ctx = getContext();
-
NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS];
-
llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
unsigned idx = 0;
@@ -1894,26 +2075,51 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
if (S == NSExceptionInstanceRaiseSelectors[i]) {
- RaisesException = true; break;
+ RaisesException = true;
+ break;
}
}
// Check if we raise an exception. For now treat these as sinks.
// Eventually we will want to handle exceptions properly.
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
if (RaisesException)
Builder->BuildSinks = true;
// Dispatch to plug-in transfer function.
- SaveOr OldHasGen(Builder->HasGeneratedNode);
- EvalObjCMessageExpr(Dst, ME, Pred, Builder->GetState(Pred));
+ EvalObjCMessageExpr(PostVisitSrc, ME, Pred, Builder->GetState(Pred));
}
+
+ // Handle the case where no nodes where generated. Auto-generate that
+ // contains the updated state if we aren't generating sinks.
+ if (!Builder->BuildSinks && PostVisitSrc.size() == OldSize &&
+ !Builder->HasGeneratedNode)
+ MakeNode(PostVisitSrc, ME, Pred, GetState(Pred));
}
- // Handle the case where no nodes where generated. Auto-generate that
- // contains the updated state if we aren't generating sinks.
- if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode)
- MakeNode(Dst, ME, Pred, GetState(Pred));
+ // Finally, perform the post-condition check of the ObjCMessageExpr and store
+ // the created nodes in 'Dst'.
+ if (!(!asLValue && ReceiverReturnsReference(ME))) {
+ CheckerVisit(ME, Dst, PostVisitSrc, false);
+ return;
+ }
+
+ // Handle the case where the message expression returns a reference but
+ // we expect an rvalue. For such cases, convert the reference to
+ // an rvalue.
+ // FIXME: This conversion doesn't actually happen unless the result
+ // of ObjCMessageExpr is consumed by another expression.
+ ExplodedNodeSet DstRValueConvert;
+ CheckerVisit(ME, DstRValueConvert, PostVisitSrc, false);
+ QualType LoadTy = ME->getType();
+
+ static int *ConvertToRvalueTag = 0;
+ for (ExplodedNodeSet::iterator NI = DstRValueConvert.begin(),
+ NE = DstRValueConvert.end();
+ NI!=NE; ++NI) {
+ const GRState *state = GetState(*NI);
+ EvalLoad(Dst, ME, *NI, state, state->getSVal(ME),
+ &ConvertToRvalueTag, LoadTy);
+ }
}
//===----------------------------------------------------------------------===//
@@ -1921,7 +2127,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
//===----------------------------------------------------------------------===//
void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred,
- ExplodedNodeSet& Dst){
+ ExplodedNodeSet& Dst, bool asLValue){
ExplodedNodeSet S1;
QualType T = CastE->getType();
QualType ExTy = Ex->getType();
@@ -1929,7 +2135,8 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred,
if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
T = ExCast->getTypeAsWritten();
- if (ExTy->isArrayType() || ExTy->isFunctionType() || T->isReferenceType())
+ if (ExTy->isArrayType() || ExTy->isFunctionType() || T->isReferenceType() ||
+ asLValue)
VisitLValue(Ex, Pred, S1);
else
Visit(Ex, Pred, S1);
@@ -1939,10 +2146,19 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred,
// Check for casting to "void".
if (T->isVoidType()) {
+ assert(!asLValue);
for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I)
Dst.Add(*I);
return;
}
+
+ // If we are evaluating the cast in an lvalue context, we implicitly want
+ // the cast to evaluate to a location.
+ if (asLValue) {
+ ASTContext &Ctx = getContext();
+ T = Ctx.getPointerType(Ctx.getCanonicalType(T));
+ ExTy = Ctx.getPointerType(Ctx.getCanonicalType(ExTy));
+ }
for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
ExplodedNode* N = *I;
@@ -1992,8 +2208,12 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
// time a function is called those values may not be current.
ExplodedNodeSet Tmp;
- if (InitEx)
- Visit(InitEx, Pred, Tmp);
+ if (InitEx) {
+ if (VD->getType()->isReferenceType())
+ VisitLValue(InitEx, Pred, Tmp);
+ else
+ Visit(InitEx, Pred, Tmp);
+ }
else
Tmp.Add(Pred);
@@ -2009,7 +2229,6 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
if (InitEx) {
SVal InitVal = state->getSVal(InitEx);
- QualType T = VD->getType();
// Recover some path-sensitivity if a scalar value evaluated to
// UnknownVal.
@@ -2020,7 +2239,7 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
}
EvalBind(Dst, DS, DS, *I, state,
- loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
+ loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
}
else {
state = state->bindDeclWithNoInit(state->getRegion(VD, LC));
@@ -2029,6 +2248,33 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
}
}
+void GRExprEngine::VisitCondInit(VarDecl *VD, Stmt *S,
+ ExplodedNode *Pred, ExplodedNodeSet& Dst) {
+
+ Expr* InitEx = VD->getInit();
+ ExplodedNodeSet Tmp;
+ Visit(InitEx, Pred, Tmp);
+
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ ExplodedNode *N = *I;
+ const GRState *state = GetState(N);
+
+ const LocationContext *LC = N->getLocationContext();
+ SVal InitVal = state->getSVal(InitEx);
+
+ // Recover some path-sensitivity if a scalar value evaluated to
+ // UnknownVal.
+ if (InitVal.isUnknown() ||
+ !getConstraintManager().canReasonAbout(InitVal)) {
+ InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
+ Builder->getCurrentBlockCount());
+ }
+
+ EvalBind(Dst, S, S, N, state,
+ loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
+ }
+}
+
namespace {
// This class is used by VisitInitListExpr as an item in a worklist
// for processing the values contained in an InitListExpr.
@@ -2082,7 +2328,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred,
InitListExpr::reverse_iterator NewItr = X.Itr + 1;
- for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(),NE=Tmp.end();NI!=NE;++NI) {
// Get the last initializer value.
state = GetState(*NI);
SVal InitV = state->getSVal(cast<Expr>(*X.Itr));
@@ -2114,7 +2360,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred,
ExplodedNodeSet Tmp;
Expr* Init = E->getInit(0);
Visit(Init, Pred, Tmp);
- for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I != EI; ++I) {
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), EI=Tmp.end(); I != EI; ++I) {
state = GetState(*I);
MakeNode(Dst, E, *I, state->BindExpr(E, state->getSVal(Init)));
}
@@ -2382,7 +2628,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
ExplodedNodeSet Tmp2;
EvalLoad(Tmp2, Ex, *I, state, V1);
- for (ExplodedNodeSet::iterator I2 = Tmp2.begin(), E2 = Tmp2.end(); I2!=E2; ++I2) {
+ for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) {
state = GetState(*I2);
SVal V2_untested = state->getSVal(Ex);
@@ -2445,14 +2691,23 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
}
}
-void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
+
+void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
+ ExplodedNodeSet & Dst) {
+ // Get the this object region from StoreManager.
+ Loc V = getStoreManager().getThisObject(TE->getType()->getPointeeType());
+ MakeNode(Dst, TE, Pred, GetState(Pred)->BindExpr(TE, V));
+}
+
+void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst) {
VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst);
}
void GRExprEngine::VisitAsmStmtHelperOutputs(AsmStmt* A,
AsmStmt::outputs_iterator I,
AsmStmt::outputs_iterator E,
- ExplodedNode* Pred, ExplodedNodeSet& Dst) {
+ ExplodedNode* Pred, ExplodedNodeSet& Dst) {
if (I == E) {
VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst);
return;
@@ -2463,14 +2718,15 @@ void GRExprEngine::VisitAsmStmtHelperOutputs(AsmStmt* A,
++I;
- for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
+ for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI)
VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst);
}
void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A,
AsmStmt::inputs_iterator I,
AsmStmt::inputs_iterator E,
- ExplodedNode* Pred, ExplodedNodeSet& Dst) {
+ ExplodedNode* Pred,
+ ExplodedNodeSet& Dst) {
if (I == E) {
// We have processed both the inputs and the outputs. All of the outputs
@@ -2598,7 +2854,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
// Simulate the effects of a "store": bind the value of the RHS
// to the L-Value represented by the LHS.
- EvalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV, RightV);
+ EvalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV,RightV);
continue;
}
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index 84e268f..0b2620e 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -112,6 +112,11 @@ public:
void VisitUnaryOperator(UnaryOperator* U);
void Visit(Stmt *S);
void VisitTerminator(CFGBlock* B);
+
+ /// VisitConditionVariableInit - Handle the initialization of condition
+ /// variables at branches. Valid statements include IfStmt, ForStmt,
+ /// WhileStmt, and SwitchStmt.
+ void VisitConditionVariableInit(Stmt *S);
void SetTopValue(LiveVariables::ValTy& V) {
V = AD.AlwaysLive;
@@ -126,7 +131,9 @@ void TransferFuncs::Visit(Stmt *S) {
if (AD.Observer)
AD.Observer->ObserveStmt(S,AD,LiveState);
- if (getCFG().isBlkExpr(S)) LiveState(S,AD) = Dead;
+ if (getCFG().isBlkExpr(S))
+ LiveState(S, AD) = Dead;
+
StmtVisitor<TransferFuncs,void>::Visit(S);
}
else if (!getCFG().isBlkExpr(S)) {
@@ -142,6 +149,11 @@ void TransferFuncs::Visit(Stmt *S) {
LiveState(S,AD) = Alive;
}
}
+
+void TransferFuncs::VisitConditionVariableInit(Stmt *S) {
+ assert(!getCFG().isBlkExpr(S));
+ CFGRecStmtVisitor<TransferFuncs>::VisitConditionVariableInit(S);
+}
void TransferFuncs::VisitTerminator(CFGBlock* B) {
@@ -289,17 +301,8 @@ void TransferFuncs::VisitDeclStmt(DeclStmt* DS) {
//===----------------------------------------------------------------------===//
namespace {
-
-struct Merge {
- typedef StmtDeclBitVector_Types::ValTy ValTy;
-
- void operator()(ValTy& Dst, const ValTy& Src) {
- Dst.OrDeclBits(Src);
- Dst.OrBlkExprBits(Src);
- }
-};
-
-typedef DataflowSolver<LiveVariables, TransferFuncs, Merge> Solver;
+ typedef StmtDeclBitVector_Types::Union Merge;
+ typedef DataflowSolver<LiveVariables, TransferFuncs, Merge> Solver;
} // end anonymous namespace
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp
index 2ed070a..fab73ee 100644
--- a/lib/Analysis/MallocChecker.cpp
+++ b/lib/Analysis/MallocChecker.cpp
@@ -23,13 +23,13 @@ using namespace clang;
namespace {
class RefState {
- enum Kind { Allocated, Released, Escaped } K;
+ enum Kind { AllocateUnchecked, AllocateFailed, Released, Escaped } K;
const Stmt *S;
public:
RefState(Kind k, const Stmt *s) : K(k), S(s) {}
- bool isAllocated() const { return K == Allocated; }
+ bool isAllocated() const { return K == AllocateUnchecked; }
bool isReleased() const { return K == Released; }
bool isEscaped() const { return K == Escaped; }
@@ -37,7 +37,12 @@ public:
return K == X.K && S == X.S;
}
- static RefState getAllocated(const Stmt *s) { return RefState(Allocated, s); }
+ static RefState getAllocateUnchecked(const Stmt *s) {
+ return RefState(AllocateUnchecked, s);
+ }
+ static RefState getAllocateFailed() {
+ return RefState(AllocateFailed, 0);
+ }
static RefState getReleased(const Stmt *s) { return RefState(Released, s); }
static RefState getEscaped(const Stmt *s) { return RefState(Escaped, s); }
@@ -62,6 +67,8 @@ public:
void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper);
void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng);
void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
+ const GRState *EvalAssume(const GRState *state, SVal Cond, bool Assumption);
+
private:
void MallocMem(CheckerContext &C, const CallExpr *CE);
const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
@@ -74,6 +81,8 @@ private:
};
} // end anonymous namespace
+typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy;
+
namespace clang {
template <>
struct GRStateTrait<RegionState>
@@ -144,7 +153,7 @@ const GRState *MallocChecker::MallocMemAux(CheckerContext &C,
SymbolRef Sym = RetVal.getAsLocSymbol();
assert(Sym);
// Set the symbol's state to Allocated.
- return state->set<RegionState>(Sym, RefState::getAllocated(CE));
+ return state->set<RegionState>(Sym, RefState::getAllocateUnchecked(CE));
}
void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
@@ -298,3 +307,18 @@ void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
C.addTransition(state);
}
+
+const GRState *MallocChecker::EvalAssume(const GRState *state, SVal Cond,
+ bool Assumption) {
+ // If a symblic region is assumed to NULL, set its state to AllocateFailed.
+ // FIXME: should also check symbols assumed to non-null.
+
+ RegionStateTy RS = state->get<RegionState>();
+
+ for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
+ if (state->getSymVal(I.getKey()))
+ state = state->set<RegionState>(I.getKey(),RefState::getAllocateFailed());
+ }
+
+ return state;
+}
diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp
index bc3a5b7..74fe3bf 100644
--- a/lib/Analysis/MemRegion.cpp
+++ b/lib/Analysis/MemRegion.cpp
@@ -291,6 +291,17 @@ void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
BlockDataRegion::ProfileRegion(ID, BC, LC, getSuperRegion());
}
+void CXXObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+ QualType T,
+ const MemRegion *sReg) {
+ ID.AddPointer(T.getTypePtr());
+ ID.AddPointer(sReg);
+}
+
+void CXXObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ProfileRegion(ID, T, getSuperRegion());
+}
+
//===----------------------------------------------------------------------===//
// Region pretty-printing.
//===----------------------------------------------------------------------===//
@@ -552,10 +563,9 @@ MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
return getSubRegion<ObjCIvarRegion>(d, superRegion);
}
-const ObjCObjectRegion*
-MemRegionManager::getObjCObjectRegion(const ObjCInterfaceDecl* d,
- const MemRegion* superRegion) {
- return getSubRegion<ObjCObjectRegion>(d, superRegion);
+const CXXObjectRegion *
+MemRegionManager::getCXXObjectRegion(QualType T) {
+ return getSubRegion<CXXObjectRegion>(T, getUnknownRegion());
}
const AllocaRegion*
diff --git a/lib/Analysis/NoReturnFunctionChecker.cpp b/lib/Analysis/NoReturnFunctionChecker.cpp
index 6806273..5cfd9ac 100644
--- a/lib/Analysis/NoReturnFunctionChecker.cpp
+++ b/lib/Analysis/NoReturnFunctionChecker.cpp
@@ -45,13 +45,12 @@ bool NoReturnFunctionChecker::EvalCallExpr(CheckerContext &C,
if (FD->getAttr<NoReturnAttr>() || FD->getAttr<AnalyzerNoReturnAttr>())
BuildSinks = true;
- else {
+ else if (const IdentifierInfo *II = FD->getIdentifier()) {
// HACK: Some functions are not marked noreturn, and don't return.
// Here are a few hardwired ones. If this takes too long, we can
// potentially cache these results.
- using llvm::StringRef;
BuildSinks
- = llvm::StringSwitch<bool>(StringRef(FD->getIdentifier()->getName()))
+ = llvm::StringSwitch<bool>(llvm::StringRef(II->getName()))
.Case("exit", true)
.Case("panic", true)
.Case("error", true)
diff --git a/lib/Analysis/OSAtomicChecker.cpp b/lib/Analysis/OSAtomicChecker.cpp
index 5a89345..cf16796 100644
--- a/lib/Analysis/OSAtomicChecker.cpp
+++ b/lib/Analysis/OSAtomicChecker.cpp
@@ -44,11 +44,15 @@ bool OSAtomicChecker::EvalCallExpr(CheckerContext &C,const CallExpr *CE) {
if (!FD)
return false;
- const char *FName = FD->getNameAsCString();
+ const IdentifierInfo *II = FD->getIdentifier();
+ if (!II)
+ return false;
+
+ llvm::StringRef FName(II->getName());
// Check for compare and swap.
- if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 ||
- strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0)
+ if (FName.startswith("OSAtomicCompareAndSwap") ||
+ FName.startswith("objc_atomicCompareAndSwap"))
return EvalOSAtomicCompareAndSwap(C, CE);
// FIXME: Other atomics.
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index b5eeb1e..3bc9dcc 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -349,6 +349,7 @@ public:
SVal RetrieveArray(const GRState *St, const TypedRegion* R);
+ /// Get the state and region whose binding this region R corresponds to.
std::pair<const GRState*, const MemRegion*>
GetLazyBinding(RegionBindings B, const MemRegion *R);
@@ -539,8 +540,7 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
}
// Handle the region itself.
- if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R) ||
- isa<ObjCObjectRegion>(R)) {
+ if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R)) {
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelavant.
DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
@@ -744,8 +744,8 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
case MemRegion::ElementRegionKind:
case MemRegion::FieldRegionKind:
case MemRegion::ObjCIvarRegionKind:
- case MemRegion::ObjCObjectRegionKind:
case MemRegion::SymbolicRegionKind:
+ case MemRegion::CXXObjectRegionKind:
return UnknownVal();
case MemRegion::StringRegionKind: {
@@ -867,8 +867,8 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
// Fall-through.
case MemRegion::CompoundLiteralRegionKind:
case MemRegion::FieldRegionKind:
- case MemRegion::ObjCObjectRegionKind:
case MemRegion::ObjCIvarRegionKind:
+ case MemRegion::CXXObjectRegionKind:
return UnknownVal();
case MemRegion::FunctionTextRegionKind:
@@ -987,12 +987,12 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
assert(!isa<UnknownVal>(L) && "location unknown");
assert(!isa<UndefinedVal>(L) && "location undefined");
-
+
// FIXME: Is this even possible? Shouldn't this be treated as a null
// dereference at a higher level?
if (isa<loc::ConcreteInt>(L))
return SValuator::CastResult(state, UndefinedVal());
-
+
const MemRegion *MR = cast<loc::MemRegionVal>(L).getRegion();
// FIXME: return symbolic value for these cases.
@@ -1090,8 +1090,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
}
// All other values are symbolic.
- return SValuator::CastResult(state,
- ValMgr.getRegionValueSymbolValOrUnknown(R, RTy));
+ return SValuator::CastResult(state, ValMgr.getRegionValueSymbolVal(R, RTy));
}
std::pair<const GRState*, const MemRegion*>
@@ -1256,7 +1255,7 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state,
}
// All other values are symbolic.
- return ValMgr.getRegionValueSymbolValOrUnknown(R, Ty);
+ return ValMgr.getRegionValueSymbolVal(R, Ty);
}
SVal RegionStoreManager::RetrieveObjCIvar(const GRState* state,
@@ -1296,7 +1295,7 @@ SVal RegionStoreManager::RetrieveVar(const GRState *state,
if (R->hasGlobalsOrParametersStorage() ||
isa<UnknownSpaceRegion>(R->getMemorySpace()))
- return ValMgr.getRegionValueSymbolValOrUnknown(R, VD->getType());
+ return ValMgr.getRegionValueSymbolVal(R, VD->getType());
return UndefinedVal();
}
@@ -1307,7 +1306,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const GRState *state,
QualType valTy = R->getValueType(getContext());
// All other values are symbolic.
- return ValMgr.getRegionValueSymbolValOrUnknown(R, valTy);
+ return ValMgr.getRegionValueSymbolVal(R, valTy);
}
SVal RegionStoreManager::RetrieveStruct(const GRState *state,
@@ -1425,7 +1424,13 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
// Binding directly to a symbolic region should be treated as binding
// to element 0.
QualType T = SR->getSymbol()->getType(getContext());
- T = T->getAs<PointerType>()->getPointeeType();
+
+ // FIXME: Is this the right way to handle symbols that are references?
+ if (const PointerType *PT = T->getAs<PointerType>())
+ T = PT->getPointeeType();
+ else
+ T = T->getAs<ReferenceType>()->getPointeeType();
+
R = GetElementZeroRegion(SR, T);
}
diff --git a/lib/Analysis/SValuator.cpp b/lib/Analysis/SValuator.cpp
index ac727b0..49bc0c4 100644
--- a/lib/Analysis/SValuator.cpp
+++ b/lib/Analysis/SValuator.cpp
@@ -72,10 +72,14 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
// Check for casts from integers to pointers.
if (Loc::IsLocType(castTy) && originalTy->isIntegerType()) {
if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&val)) {
- // Just unpackage the lval and return it.
+ if (const MemRegion *R = LV->getLoc().getAsRegion()) {
+ StoreManager &storeMgr = ValMgr.getStateManager().getStoreManager();
+ R = storeMgr.CastRegion(R, castTy);
+ return R ? CastResult(state, loc::MemRegionVal(R))
+ : CastResult(state, UnknownVal());
+ }
return CastResult(state, LV->getLoc());
}
-
goto DispatchCast;
}
@@ -136,15 +140,12 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
// different type. If the MemRegion* returned is NULL, this expression
// evaluates to UnknownVal.
R = storeMgr.CastRegion(R, castTy);
-
- if (R)
- return CastResult(state, loc::MemRegionVal(R));
-
- return CastResult(state, UnknownVal());
+ return R ? CastResult(state, loc::MemRegionVal(R))
+ : CastResult(state, UnknownVal());
}
- // All other cases.
DispatchCast:
+ // All other cases.
return CastResult(state,
isa<Loc>(val) ? EvalCastL(cast<Loc>(val), castTy)
: EvalCastNL(cast<NonLoc>(val), castTy));
diff --git a/lib/Analysis/SimpleConstraintManager.cpp b/lib/Analysis/SimpleConstraintManager.cpp
index 015db76..23c3b41 100644
--- a/lib/Analysis/SimpleConstraintManager.cpp
+++ b/lib/Analysis/SimpleConstraintManager.cpp
@@ -15,6 +15,7 @@
#include "SimpleConstraintManager.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/PathSensitive/Checker.h"
namespace clang {
@@ -72,8 +73,17 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc Cond,
// EvalAssume is used to call into the GRTransferFunction object to perform
// any checker-specific update of the state based on this assumption being
// true or false.
- return state ? state->getTransferFuncs().EvalAssume(state, Cond, Assumption)
- : NULL;
+
+ if (!state)
+ return 0;
+
+ std::vector<std::pair<void *, Checker*> >::iterator
+ I = state->checker_begin(), E = state->checker_end();
+
+ for (; I != E; ++I) {
+ state = I->second->EvalAssume(state, Cond, Assumption);
+ }
+ return state->getTransferFuncs().EvalAssume(state, Cond, Assumption);
}
const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
@@ -128,8 +138,18 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state,
// EvalAssume is used to call into the GRTransferFunction object to perform
// any checker-specific update of the state based on this assumption being
// true or false.
- return state ? state->getTransferFuncs().EvalAssume(state, Cond, Assumption)
- : NULL;
+
+ if (!state)
+ return 0;
+
+ std::vector<std::pair<void *, Checker*> >::iterator
+ I = state->checker_begin(), E = state->checker_end();
+
+ for (; I != E; ++I) {
+ state = I->second->EvalAssume(state, Cond, Assumption);
+ }
+
+ return state->getTransferFuncs().EvalAssume(state, Cond, Assumption);
}
const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp
index e6ff6e5..8d911b8 100644
--- a/lib/Analysis/Store.cpp
+++ b/lib/Analysis/Store.cpp
@@ -98,7 +98,6 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
}
case MemRegion::StringRegionKind:
- case MemRegion::ObjCObjectRegionKind:
// FIXME: Need to handle arbitrary downcasts.
case MemRegion::SymbolicRegionKind:
case MemRegion::AllocaRegionKind:
@@ -106,6 +105,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
case MemRegion::FieldRegionKind:
case MemRegion::ObjCIvarRegionKind:
case MemRegion::VarRegionKind:
+ case MemRegion::CXXObjectRegionKind:
return MakeElementRegion(R, PointeeTy);
case MemRegion::ElementRegionKind: {
@@ -198,11 +198,21 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
/// as another region.
SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
QualType castTy) {
+
+#ifndef NDEBUG
if (castTy.isNull())
return V;
+
+ ASTContext &Ctx = ValMgr.getContext();
+ QualType T = R->getValueType(Ctx);
+
+ // Automatically translate references to pointers.
+ if (const ReferenceType *RT = T->getAs<ReferenceType>())
+ T = Ctx.getPointerType(RT->getPointeeType());
+
+ assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, T));
+#endif
- assert(ValMgr.getContext().hasSameUnqualifiedType(castTy,
- R->getValueType(ValMgr.getContext())));
return V;
}
@@ -230,3 +240,8 @@ SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL,
const LocationContext *LC) {
return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
}
+
+Loc StoreManager::getThisObject(QualType T) {
+ const CXXObjectRegion *R = MRMgr.getCXXObjectRegion(T);
+ return loc::MemRegionVal(R);
+}
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 8d0d813..4351f66 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -203,6 +203,7 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
AllExtensionsSilenced = 0;
IgnoreAllWarnings = false;
WarningsAsErrors = false;
+ ErrorsAsFatal = false;
SuppressSystemWarnings = false;
SuppressAllDiagnostics = false;
ExtBehavior = Ext_Ignore;
@@ -326,9 +327,13 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const {
return Diagnostic::Ignored;
Result = Diagnostic::Warning;
if (ExtBehavior == Ext_Error) Result = Diagnostic::Error;
+ if (Result == Diagnostic::Error && ErrorsAsFatal)
+ Result = Diagnostic::Fatal;
break;
case diag::MAP_ERROR:
Result = Diagnostic::Error;
+ if (ErrorsAsFatal)
+ Result = Diagnostic::Fatal;
break;
case diag::MAP_FATAL:
Result = Diagnostic::Fatal;
@@ -349,6 +354,8 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const {
if (WarningsAsErrors)
Result = Diagnostic::Error;
+ if (Result == Diagnostic::Error && ErrorsAsFatal)
+ Result = Diagnostic::Fatal;
break;
case diag::MAP_WARNING_NO_WERROR:
@@ -361,6 +368,12 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const {
return Diagnostic::Ignored;
break;
+
+ case diag::MAP_ERROR_NO_WFATAL:
+ // Diagnostics specified as -Wno-fatal-error=foo should be errors, but
+ // unaffected by -Wfatal-errors.
+ Result = Diagnostic::Error;
+ break;
}
// Okay, we're about to return this as a "diagnostic to emit" one last check:
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index 434ff39..c4296c3 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -219,6 +219,11 @@ static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
///
const DirectoryEntry *FileManager::getDirectory(const char *NameStart,
const char *NameEnd) {
+ // stat doesn't like trailing separators (at least on Windows).
+ if (((NameEnd - NameStart) > 1) &&
+ ((*(NameEnd - 1) == '/') || (*(NameEnd - 1) == '\\')))
+ NameEnd--;
+
++NumDirLookups;
llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
DirEntries.GetOrCreateValue(NameStart, NameEnd);
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index a1f97f4..493beee 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -360,6 +360,8 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
Info.setAllowsRegister();
break;
case 'm': // memory operand.
+ case 'o': // offsettable memory operand
+ case 'V': // non-offsettable memory operand
Info.setAllowsMemory();
break;
case 'g': // general register, memory operand or immediate integer.
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index e5a4c43..b6b5c6c 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -323,11 +323,14 @@ protected:
Define(Defs, "__PPU__", "1");
Define(Defs, "__CELLOS_LV2__", "1");
Define(Defs, "__ELF__", "1");
+ Define(Defs, "__LP32__", "1");
}
public:
PS3PPUTargetInfo(const std::string& triple)
: OSTargetInfo<Target>(triple) {
this->UserLabelPrefix = "";
+ this->LongWidth = this->LongAlign = this->PointerWidth = this->PointerAlign = 32;
+ this->SizeType = TargetInfo::UnsignedInt;
}
};
@@ -625,7 +628,7 @@ const Builtin::Info BuiltinInfo[] = {
#include "clang/Basic/BuiltinsX86.def"
};
-const char *GCCRegNames[] = {
+static const char* const GCCRegNames[] = {
"ax", "dx", "cx", "bx", "si", "di", "bp", "sp",
"st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
"argp", "flags", "fspr", "dirflag", "frame",
@@ -685,7 +688,7 @@ public:
bool Enabled) const;
virtual void getDefaultFeatures(const std::string &CPU,
llvm::StringMap<bool> &Features) const;
- virtual void HandleTargetFeatures(const std::vector<std::string> &Features);
+ virtual void HandleTargetFeatures(std::vector<std::string> &Features);
};
void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
@@ -802,8 +805,7 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
/// HandleTargetOptions - Perform initialization based on the user
/// configured set of features.
-void
-X86TargetInfo::HandleTargetFeatures(const std::vector<std::string> &Features) {
+void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
// Remember the maximum enabled sselevel.
for (unsigned i = 0, e = Features.size(); i !=e; ++i) {
// Ignore disabled features.
@@ -993,8 +995,8 @@ public:
WCharType = UnsignedShort;
DoubleAlign = LongLongAlign = 64;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
- "a0:0:64-f80:32:32-n8:16:32";
+ "i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-"
+ "v128:128:128-a0:0:64-f80:32:32-n8:16:32";
}
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defines) const {
@@ -1181,52 +1183,40 @@ public:
namespace {
class ARMTargetInfo : public TargetInfo {
- enum {
- Armv4t,
- Armv5,
- Armv6,
- Armv7a,
- XScale
- } ArmArch;
+ // Possible FPU choices.
+ enum FPUMode {
+ NoFPU,
+ VFP2FPU,
+ VFP3FPU,
+ NeonFPU
+ };
- static const TargetInfo::GCCRegAlias GCCRegAliases[];
- static const char * const GCCRegNames[];
+ static bool FPUModeIsVFP(FPUMode Mode) {
+ return Mode >= VFP2FPU && Mode <= NeonFPU;
+ }
+
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+ static const char * const GCCRegNames[];
- std::string ABI;
- bool IsThumb;
+ std::string ABI, CPU;
+
+ unsigned FPU : 3;
+
+ unsigned IsThumb : 1;
+
+ // Initialized via features.
+ unsigned SoftFloat : 1;
+ unsigned SoftFloatABI : 1;
public:
ARMTargetInfo(const std::string &TripleStr)
- : TargetInfo(TripleStr), ABI("aapcs-linux"), IsThumb(false)
+ : TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s")
{
- llvm::Triple Triple(TripleStr);
-
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
- // FIXME: This shouldn't be done this way, we should use features to
- // indicate the arch. See lib/Driver/Tools.cpp.
- llvm::StringRef Version(""), Arch = Triple.getArchName();
- if (Arch.startswith("arm"))
- Version = Arch.substr(3);
- else if (Arch.startswith("thumb"))
- Version = Arch.substr(5);
- if (Version == "v7")
- ArmArch = Armv7a;
- else if (Version.empty() || Version == "v6" || Version == "v6t2")
- ArmArch = Armv6;
- else if (Version == "v5")
- ArmArch = Armv5;
- else if (Version == "v4t")
- ArmArch = Armv4t;
- else if (Arch == "xscale" || Arch == "thumbv5e")
- ArmArch = XScale;
- else
- ArmArch = Armv6;
-
- if (Arch.startswith("thumb"))
- IsThumb = true;
-
+ // FIXME: Should we just treat this as a feature?
+ IsThumb = getTriple().getArchName().startswith("thumb");
if (IsThumb) {
DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-"
@@ -1269,6 +1259,88 @@ public:
return true;
}
+
+ void getDefaultFeatures(const std::string &CPU,
+ llvm::StringMap<bool> &Features) const {
+ // FIXME: This should not be here.
+ Features["vfp2"] = false;
+ Features["vfp3"] = false;
+ Features["neon"] = false;
+
+ if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore")
+ Features["vfp2"] = true;
+ else if (CPU == "cortex-a8" || CPU == "cortex-a9")
+ Features["neon"] = true;
+ }
+
+ virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
+ const std::string &Name,
+ bool Enabled) const {
+ if (Name == "soft-float" || Name == "soft-float-abi") {
+ Features[Name] = Enabled;
+ } else if (Name == "vfp2" || Name == "vfp3" || Name == "neon") {
+ // These effectively are a single option, reset them when any is enabled.
+ if (Enabled)
+ Features["vfp2"] = Features["vfp3"] = Features["neon"] = false;
+ Features[Name] = Enabled;
+ } else
+ return false;
+
+ return true;
+ }
+
+ virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+ FPU = NoFPU;
+ SoftFloat = SoftFloatABI = false;
+ for (unsigned i = 0, e = Features.size(); i != e; ++i) {
+ if (Features[i] == "+soft-float")
+ SoftFloat = true;
+ else if (Features[i] == "+soft-float-abi")
+ SoftFloatABI = true;
+ else if (Features[i] == "+vfp2")
+ FPU = VFP2FPU;
+ else if (Features[i] == "+vfp3")
+ FPU = VFP3FPU;
+ else if (Features[i] == "+neon")
+ FPU = NeonFPU;
+ }
+
+ // Remove front-end specific options which the backend handles differently.
+ std::vector<std::string>::iterator it;
+ it = std::find(Features.begin(), Features.end(), "+soft-float");
+ if (it != Features.end())
+ Features.erase(it);
+ it = std::find(Features.begin(), Features.end(), "+soft-float-abi");
+ if (it != Features.end())
+ Features.erase(it);
+ }
+
+ static const char *getCPUDefineSuffix(llvm::StringRef Name) {
+ return llvm::StringSwitch<const char*>(Name)
+ .Cases("arm8", "arm810", "4")
+ .Cases("strongarm", "strongarm110", "strongarm1100", "strongarm1110", "4")
+ .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "arm720t", "arm9", "4T")
+ .Cases("arm9tdmi", "arm920", "arm920t", "arm922t", "arm940t", "4T")
+ .Case("ep9312", "4T")
+ .Cases("arm10tdmi", "arm1020t", "5T")
+ .Cases("arm9e", "arm946e-s", "arm966e-s", "arm968e-s", "5TE")
+ .Case("arm926ej-s", "5TEJ")
+ .Cases("arm10e", "arm1020e", "arm1022e", "5TE")
+ .Cases("xscale", "iwmmxt", "5TE")
+ .Case("arm1136j-s", "6J")
+ .Cases("arm1176jz-s", "arm1176jzf-s", "6ZK")
+ .Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K")
+ .Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
+ .Cases("cortex-a8", "cortex-a9", "7A")
+ .Default(0);
+ }
+ virtual bool setCPU(const std::string &Name) {
+ if (!getCPUDefineSuffix(Name))
+ return false;
+
+ CPU = Name;
+ return true;
+ }
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defs) const {
// Target identification.
@@ -1276,46 +1348,55 @@ public:
Define(Defs, "__arm__");
// Target properties.
+ Define(Defs, "__ARMEL__");
Define(Defs, "__LITTLE_ENDIAN__");
+ Define(Defs, "__REGISTER_PREFIX__", "");
+
+ llvm::StringRef CPUArch = getCPUDefineSuffix(CPU);
+ std::string ArchName = "__ARM_ARCH_";
+ ArchName += CPUArch;
+ ArchName += "__";
+ Define(Defs, ArchName);
// Subtarget options.
- //
- // FIXME: Neither THUMB_INTERWORK nor SOFTFP is not being set correctly
- // here.
- if (ArmArch == Armv7a) {
- Define(Defs, "__ARM_ARCH_7A__");
- Define(Defs, "__THUMB_INTERWORK__");
- } else if (ArmArch == Armv6) {
- Define(Defs, "__ARM_ARCH_6K__");
- Define(Defs, "__THUMB_INTERWORK__");
- } else if (ArmArch == Armv5) {
- Define(Defs, "__ARM_ARCH_5TEJ__");
+
+ // FIXME: It's more complicated than this and we don't really support
+ // interworking.
+ if ('5' <= CPUArch[0] && CPUArch[0] <= '7')
Define(Defs, "__THUMB_INTERWORK__");
+
+ if (ABI == "aapcs" || ABI == "aapcs-linux")
+ Define(Defs, "__ARM_EABI__");
+
+ if (SoftFloat)
Define(Defs, "__SOFTFP__");
- } else if (ArmArch == Armv4t) {
- Define(Defs, "__ARM_ARCH_4T__");
- Define(Defs, "__SOFTFP__");
- } else if (ArmArch == XScale) {
- Define(Defs, "__ARM_ARCH_5TE__");
- Define(Defs, "__XSCALE__");
- Define(Defs, "__SOFTFP__");
- }
- Define(Defs, "__ARMEL__");
+ if (CPU == "xscale")
+ Define(Defs, "__XSCALE__");
+ bool IsThumb2 = IsThumb && (CPUArch == "6T2" || CPUArch.startswith("7"));
if (IsThumb) {
Define(Defs, "__THUMBEL__");
Define(Defs, "__thumb__");
- if (ArmArch == Armv7a)
+ if (IsThumb2)
Define(Defs, "__thumb2__");
}
// Note, this is always on in gcc, even though it doesn't make sense.
Define(Defs, "__APCS_32__");
- // FIXME: This should be conditional on VFP instruction support.
- Define(Defs, "__VFP_FP__");
- Define(Defs, "__USING_SJLJ_EXCEPTIONS__");
+ if (FPUModeIsVFP((FPUMode) FPU))
+ Define(Defs, "__VFP_FP__");
+
+ // This only gets set when Neon instructions are actually available, unlike
+ // 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)
+ Define(Defs, "__ARM_NEON__");
+
+ if (getTriple().getOS() == llvm::Triple::Darwin)
+ Define(Defs, "__USING_SJLJ_EXCEPTIONS__");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -1602,7 +1683,7 @@ namespace {
IntPtrType = SignedShort;
PtrDiffType = SignedInt;
SigAtomicType = SignedLong;
- DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-n8:16";
+ DescriptionString = "e-p:16:16:16-i8:8:8-i16:16:16-i32:16:32-n8:16";
}
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defines) const {
@@ -2111,7 +2192,7 @@ static TargetInfo *AllocateTarget(const std::string &T) {
/// CreateTargetInfo - Return the target info object for the specified target
/// triple.
TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags,
- const TargetOptions &Opts) {
+ TargetOptions &Opts) {
llvm::Triple Triple(Opts.Triple);
// Construct the target
@@ -2121,6 +2202,12 @@ TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags,
return 0;
}
+ // Set the target CPU if specified.
+ if (!Opts.CPU.empty() && !Target->setCPU(Opts.CPU)) {
+ Diags.Report(diag::err_target_unknown_cpu) << Opts.CPU;
+ return 0;
+ }
+
// Set the target ABI if specified.
if (!Opts.ABI.empty() && !Target->setABI(Opts.ABI)) {
Diags.Report(diag::err_target_unknown_abi) << Opts.ABI;
@@ -2149,11 +2236,11 @@ TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags,
//
// FIXME: If we are completely confident that we have the right set, we only
// need to pass the minuses.
- std::vector<std::string> StrFeatures;
+ Opts.Features.clear();
for (llvm::StringMap<bool>::const_iterator it = Features.begin(),
ie = Features.end(); it != ie; ++it)
- StrFeatures.push_back(std::string(it->second ? "+" : "-") + it->first());
- Target->HandleTargetFeatures(StrFeatures);
+ Opts.Features.push_back(std::string(it->second ? "+" : "-") + it->first());
+ Target->HandleTargetFeatures(Opts.Features);
return Target.take();
}
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 9e44db0..1bece7f 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -460,7 +460,8 @@ const llvm::Type *BlockModule::getGenericExtendedBlockLiteralType() {
return GenericExtendedBlockLiteralType;
}
-RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) {
+RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
+ ReturnValueSlot ReturnValue) {
const BlockPointerType *BPT =
E->getCallee()->getType()->getAs<BlockPointerType>();
@@ -509,7 +510,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) {
Func = Builder.CreateBitCast(Func, BlockFTyPtr);
// And call the block.
- return EmitCall(FnInfo, Func, Args);
+ return EmitCall(FnInfo, Func, ReturnValue, Args);
}
uint64_t CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index c704432..866c587 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -209,10 +209,19 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
const llvm::Type *ResType[] = {
ConvertType(E->getType())
};
+
+ // LLVM only supports 0 and 2, make sure that we pass along that
+ // as a boolean.
+ Value *Ty = EmitScalarExpr(E->getArg(1));
+ ConstantInt *CI = dyn_cast<ConstantInt>(Ty);
+ assert(CI);
+ uint64_t val = CI->getZExtValue();
+ CI = ConstantInt::get(llvm::Type::getInt1Ty(VMContext), (val & 0x2) >> 1);
+
Value *F = CGM.getIntrinsic(Intrinsic::objectsize, ResType, 1);
return RValue::get(Builder.CreateCall2(F,
EmitScalarExpr(E->getArg(0)),
- EmitScalarExpr(E->getArg(1))));
+ CI));
}
case Builtin::BI__builtin_prefetch: {
Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
@@ -229,6 +238,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Builder.CreateCall(F));
}
case Builtin::BI__builtin_unreachable: {
+ if (CatchUndefined && HaveInsertPoint())
+ EmitBranch(getTrapBB());
Value *V = Builder.CreateUnreachable();
Builder.ClearInsertionPoint();
return RValue::get(V);
@@ -300,6 +311,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1));
return RValue::get(Address);
}
+ case Builtin::BImemcpy:
case Builtin::BI__builtin_memcpy: {
Value *Address = EmitScalarExpr(E->getArg(0));
Builder.CreateCall4(CGM.getMemCpyFn(), Address,
@@ -308,6 +320,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1));
return RValue::get(Address);
}
+ case Builtin::BImemmove:
case Builtin::BI__builtin_memmove: {
Value *Address = EmitScalarExpr(E->getArg(0));
Builder.CreateCall4(CGM.getMemMoveFn(), Address,
@@ -316,6 +329,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1));
return RValue::get(Address);
}
+ case Builtin::BImemset:
case Builtin::BI__builtin_memset: {
Value *Address = EmitScalarExpr(E->getArg(0));
Builder.CreateCall4(CGM.getMemSetFn(), Address,
@@ -326,12 +340,20 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Address);
}
case Builtin::BI__builtin_return_address: {
+ Value *Depth = EmitScalarExpr(E->getArg(0));
+ Depth = Builder.CreateIntCast(Depth,
+ llvm::Type::getInt32Ty(VMContext),
+ false, "tmp");
Value *F = CGM.getIntrinsic(Intrinsic::returnaddress, 0, 0);
- return RValue::get(Builder.CreateCall(F, EmitScalarExpr(E->getArg(0))));
+ return RValue::get(Builder.CreateCall(F, Depth));
}
case Builtin::BI__builtin_frame_address: {
+ Value *Depth = EmitScalarExpr(E->getArg(0));
+ Depth = Builder.CreateIntCast(Depth,
+ llvm::Type::getInt32Ty(VMContext),
+ false, "tmp");
Value *F = CGM.getIntrinsic(Intrinsic::frameaddress, 0, 0);
- return RValue::get(Builder.CreateCall(F, EmitScalarExpr(E->getArg(0))));
+ return RValue::get(Builder.CreateCall(F, Depth));
}
case Builtin::BI__builtin_extract_return_addr: {
// FIXME: There should be a target hook for this
@@ -565,9 +587,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// that function.
if (getContext().BuiltinInfo.isLibFunction(BuiltinID) ||
getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID))
- return EmitCall(CGM.getBuiltinLibFunction(FD, BuiltinID),
- E->getCallee()->getType(), E->arg_begin(),
- E->arg_end());
+ return EmitCall(E->getCallee()->getType(),
+ CGM.getBuiltinLibFunction(FD, BuiltinID),
+ ReturnValueSlot(),
+ E->arg_begin(), E->arg_end());
// See if we have a target specific intrinsic.
const char *Name = getContext().BuiltinInfo.GetName(BuiltinID);
@@ -848,7 +871,5 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
- switch (BuiltinID) {
- default: return 0;
- }
+ return 0;
}
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 0d11be2..cc006d9 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -28,6 +28,7 @@ using namespace CodeGen;
RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
llvm::Value *Callee,
+ ReturnValueSlot ReturnValue,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
@@ -46,8 +47,8 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
- return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args),
- Callee, Args, MD);
+ return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
+ ReturnValue, Args, MD);
}
/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
@@ -78,9 +79,10 @@ static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) {
return false;
}
-RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
+RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
+ ReturnValueSlot ReturnValue) {
if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens()))
- return EmitCXXMemberPointerCallExpr(CE);
+ return EmitCXXMemberPointerCallExpr(CE, ReturnValue);
const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens());
const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
@@ -88,9 +90,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
if (MD->isStatic()) {
// The method is static, emit it as we would a regular call.
llvm::Value *Callee = CGM.GetAddrOfFunction(MD);
- return EmitCall(Callee, getContext().getPointerType(MD->getType()),
- CE->arg_begin(), CE->arg_end(), 0);
-
+ return EmitCall(getContext().getPointerType(MD->getType()), Callee,
+ ReturnValue, CE->arg_begin(), CE->arg_end());
}
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
@@ -139,12 +140,13 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
Callee = CGM.GetAddrOfFunction(MD, Ty);
}
- return EmitCXXMemberCall(MD, Callee, This,
+ return EmitCXXMemberCall(MD, Callee, ReturnValue, This,
CE->arg_begin(), CE->arg_end());
}
RValue
-CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E) {
+CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
+ ReturnValueSlot ReturnValue) {
const BinaryOperator *BO =
cast<BinaryOperator>(E->getCallee()->IgnoreParens());
const Expr *BaseExpr = BO->getLHS();
@@ -247,13 +249,14 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E) {
// And the rest of the call args
EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
QualType ResultType = BO->getType()->getAs<FunctionType>()->getResultType();
- return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args),
- Callee, Args, 0);
+ return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
+ ReturnValue, Args);
}
RValue
CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
- const CXXMethodDecl *MD) {
+ const CXXMethodDecl *MD,
+ ReturnValueSlot ReturnValue) {
assert(MD->isInstance() &&
"Trying to emit a member call expr on a static method!");
@@ -283,7 +286,7 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
else
Callee = CGM.GetAddrOfFunction(MD, Ty);
- return EmitCXXMemberCall(MD, Callee, This,
+ return EmitCXXMemberCall(MD, Callee, ReturnValue, This,
E->arg_begin() + 1, E->arg_end());
}
@@ -508,7 +511,7 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
- if (D->isCopyConstructor(getContext())) {
+ if (D->isCopyConstructor()) {
const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D->getDeclContext());
if (ClassDecl->hasTrivialCopyConstructor()) {
assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
@@ -527,7 +530,7 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
- EmitCXXMemberCall(D, Callee, This, ArgBeg, ArgEnd);
+ EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, ArgBeg, ArgEnd);
}
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
@@ -552,7 +555,8 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
// FIXME: We should try to share this code with EmitCXXMemberCall.
QualType ResultType = DD->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, Args, DD);
+ EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
+ ReturnValueSlot(), Args, DD);
}
void
@@ -564,22 +568,33 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
getContext().getAsConstantArrayType(E->getType());
// For a copy constructor, even if it is trivial, must fall thru so
// its argument is code-gen'ed.
- if (!CD->isCopyConstructor(getContext())) {
+ if (!CD->isCopyConstructor()) {
QualType InitType = E->getType();
if (Array)
InitType = getContext().getBaseElementType(Array);
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(InitType->getAs<RecordType>()->getDecl());
if (RD->hasTrivialConstructor())
- return;
+ return;
}
// Code gen optimization to eliminate copy constructor and return
// its first argument instead.
if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
const Expr *Arg = E->getArg(0);
-
+
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
+ assert((ICE->getCastKind() == CastExpr::CK_NoOp ||
+ ICE->getCastKind() == CastExpr::CK_ConstructorConversion ||
+ ICE->getCastKind() == CastExpr::CK_UserDefinedConversion) &&
+ "Unknown implicit cast kind in constructor elision");
+ Arg = ICE->getSubExpr();
+ }
+
+ if (const CXXFunctionalCastExpr *FCE = dyn_cast<CXXFunctionalCastExpr>(Arg))
+ Arg = FCE->getSubExpr();
+
if (const CXXBindTemporaryExpr *BindExpr =
- dyn_cast<CXXBindTemporaryExpr>(Arg))
+ dyn_cast<CXXBindTemporaryExpr>(Arg))
Arg = BindExpr->getSubExpr();
EmitAggExpr(Arg, Dest, false);
@@ -591,6 +606,7 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr =
Builder.CreateBitCast(Dest, BasePtr);
+
EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
E->arg_begin(), E->arg_end());
}
@@ -793,7 +809,7 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
}
RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
- Callee, CallArgs, MD);
+ Callee, ReturnValueSlot(), CallArgs, MD);
if (ShouldAdjustReturnPointer && !Adjustment.ReturnAdjustment.isEmpty()) {
bool CanBeZero = !(ResultType->isReferenceType()
// FIXME: attr nonnull can't be zero either
@@ -1043,765 +1059,70 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
}
-/// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class
-/// array of objects from SrcValue to DestValue. Copying can be either a bitwise
-/// copy or via a copy constructor call.
-// FIXME. Consolidate this with EmitCXXAggrConstructorCall.
-void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
- llvm::Value *Src,
- const ArrayType *Array,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty) {
- const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
- assert(CA && "VLA cannot be copied over");
- bool BitwiseCopy = BaseClassDecl->hasTrivialCopyConstructor();
-
- // Create a temporary for the loop index and initialize it with 0.
- llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
- "loop.index");
- llvm::Value* zeroConstant =
- llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
- Builder.CreateStore(zeroConstant, IndexPtr);
- // Start the loop with a block that tests the condition.
- llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
- llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
-
- EmitBlock(CondBlock);
-
- llvm::BasicBlock *ForBody = createBasicBlock("for.body");
- // Generate: if (loop-index < number-of-elements fall to the loop body,
- // otherwise, go to the block after the for-loop.
- uint64_t NumElements = getContext().getConstantArrayElementCount(CA);
- llvm::Value * NumElementsPtr =
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements);
- llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
- llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr,
- "isless");
- // If the condition is true, execute the body.
- Builder.CreateCondBr(IsLess, ForBody, AfterFor);
-
- EmitBlock(ForBody);
- llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
- // Inside the loop body, emit the constructor call on the array element.
- Counter = Builder.CreateLoad(IndexPtr);
- Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress");
- Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress");
- if (BitwiseCopy)
- EmitAggregateCopy(Dest, Src, Ty);
- else if (CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(getContext(), 0)) {
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor,
- Ctor_Complete);
- CallArgList CallArgs;
- // Push the this (Dest) ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Dest),
- BaseCopyCtor->getThisType(getContext())));
-
- // Push the Src ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Src),
- BaseCopyCtor->getParamDecl(0)->getType()));
- QualType ResultType =
- BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
- Callee, CallArgs, BaseCopyCtor);
- }
- EmitBlock(ContinueBlock);
-
- // Emit the increment of the loop counter.
- llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
- Counter = Builder.CreateLoad(IndexPtr);
- NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
- Builder.CreateStore(NextVal, IndexPtr);
-
- // Finally, branch back up to the condition for the next iteration.
- EmitBranch(CondBlock);
-
- // Emit the fall-through block.
- EmitBlock(AfterFor, true);
-}
-
-/// EmitClassAggrCopyAssignment - This routine generates code to assign a class
-/// array of objects from SrcValue to DestValue. Assignment can be either a
-/// bitwise assignment or via a copy assignment operator function call.
-/// FIXME. This can be consolidated with EmitClassAggrMemberwiseCopy
-void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
- llvm::Value *Src,
- const ArrayType *Array,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty) {
- const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
- assert(CA && "VLA cannot be asssigned");
- bool BitwiseAssign = BaseClassDecl->hasTrivialCopyAssignment();
-
- // Create a temporary for the loop index and initialize it with 0.
- llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
- "loop.index");
- llvm::Value* zeroConstant =
- llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
- Builder.CreateStore(zeroConstant, IndexPtr);
- // Start the loop with a block that tests the condition.
- llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
- llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
-
- EmitBlock(CondBlock);
-
- llvm::BasicBlock *ForBody = createBasicBlock("for.body");
- // Generate: if (loop-index < number-of-elements fall to the loop body,
- // otherwise, go to the block after the for-loop.
- uint64_t NumElements = getContext().getConstantArrayElementCount(CA);
- llvm::Value * NumElementsPtr =
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements);
- llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
- llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr,
- "isless");
- // If the condition is true, execute the body.
- Builder.CreateCondBr(IsLess, ForBody, AfterFor);
-
- EmitBlock(ForBody);
- llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
- // Inside the loop body, emit the assignment operator call on array element.
- Counter = Builder.CreateLoad(IndexPtr);
- Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress");
- Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress");
- const CXXMethodDecl *MD = 0;
- if (BitwiseAssign)
- EmitAggregateCopy(Dest, Src, Ty);
- else {
- bool hasCopyAssign = BaseClassDecl->hasConstCopyAssignment(getContext(),
- MD);
- assert(hasCopyAssign && "EmitClassAggrCopyAssignment - No user assign");
- (void)hasCopyAssign;
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *LTy =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
- llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy);
-
- CallArgList CallArgs;
- // Push the this (Dest) ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Dest),
- MD->getThisType(getContext())));
-
- // Push the Src ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Src),
- MD->getParamDecl(0)->getType()));
- QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
- Callee, CallArgs, MD);
- }
- EmitBlock(ContinueBlock);
-
- // Emit the increment of the loop counter.
- llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
- Counter = Builder.CreateLoad(IndexPtr);
- NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
- Builder.CreateStore(NextVal, IndexPtr);
-
- // Finally, branch back up to the condition for the next iteration.
- EmitBranch(CondBlock);
-
- // Emit the fall-through block.
- EmitBlock(AfterFor, true);
-}
-
-/// EmitClassMemberwiseCopy - This routine generates code to copy a class
-/// object from SrcValue to DestValue. Copying can be either a bitwise copy
-/// or via a copy constructor call.
-void CodeGenFunction::EmitClassMemberwiseCopy(
- llvm::Value *Dest, llvm::Value *Src,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl, QualType Ty) {
- if (ClassDecl) {
- Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- }
- if (BaseClassDecl->hasTrivialCopyConstructor()) {
- EmitAggregateCopy(Dest, Src, Ty);
- return;
- }
-
- if (CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(getContext(), 0)) {
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor,
- Ctor_Complete);
- CallArgList CallArgs;
- // Push the this (Dest) ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Dest),
- BaseCopyCtor->getThisType(getContext())));
-
- // Push the Src ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Src),
- BaseCopyCtor->getParamDecl(0)->getType()));
- QualType ResultType =
- BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
- Callee, CallArgs, BaseCopyCtor);
- }
-}
-
-/// EmitClassCopyAssignment - This routine generates code to copy assign a class
-/// object from SrcValue to DestValue. Assignment can be either a bitwise
-/// assignment of via an assignment operator call.
-// FIXME. Consolidate this with EmitClassMemberwiseCopy as they share a lot.
-void CodeGenFunction::EmitClassCopyAssignment(
- llvm::Value *Dest, llvm::Value *Src,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty) {
- if (ClassDecl) {
- Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- }
- if (BaseClassDecl->hasTrivialCopyAssignment()) {
- EmitAggregateCopy(Dest, Src, Ty);
+void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) {
+ if (!ClassDecl->isDynamicClass())
return;
- }
-
- const CXXMethodDecl *MD = 0;
- bool ConstCopyAssignOp = BaseClassDecl->hasConstCopyAssignment(getContext(),
- MD);
- assert(ConstCopyAssignOp && "EmitClassCopyAssignment - missing copy assign");
- (void)ConstCopyAssignOp;
-
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *LTy =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
- llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy);
-
- CallArgList CallArgs;
- // Push the this (Dest) ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Dest),
- MD->getThisType(getContext())));
-
- // Push the Src ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Src),
- MD->getParamDecl(0)->getType()));
- QualType ResultType =
- MD->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
- Callee, CallArgs, MD);
-}
-
-/// SynthesizeDefaultConstructor - synthesize a default constructor
-void
-CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor,
- CXXCtorType Type,
- llvm::Function *Fn,
- const FunctionArgList &Args) {
- assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor");
- StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args,
- SourceLocation());
- EmitCtorPrologue(Ctor, Type);
- FinishFunction();
-}
-
-/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a
-/// copy constructor, in accordance with section 12.8 (p7 and p8) of C++03
-/// The implicitly-defined copy constructor for class X performs a memberwise
-/// copy of its subobjects. The order of copying is the same as the order of
-/// initialization of bases and members in a user-defined constructor
-/// Each subobject is copied in the manner appropriate to its type:
-/// if the subobject is of class type, the copy constructor for the class is
-/// used;
-/// if the subobject is an array, each element is copied, in the manner
-/// appropriate to the element type;
-/// if the subobject is of scalar type, the built-in assignment operator is
-/// used.
-/// Virtual base class subobjects shall be copied only once by the
-/// implicitly-defined copy constructor
-
-void
-CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
- CXXCtorType Type,
- llvm::Function *Fn,
- const FunctionArgList &Args) {
- const CXXRecordDecl *ClassDecl = Ctor->getParent();
- assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
- "SynthesizeCXXCopyConstructor - copy constructor has definition already");
- assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor");
- StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args,
- SourceLocation());
-
- FunctionArgList::const_iterator i = Args.begin();
- const VarDecl *ThisArg = i->first;
- llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg);
- llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this");
- const VarDecl *SrcArg = (i+1)->first;
- llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg);
- llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj);
-
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- // FIXME. copy constrution of virtual base NYI
- if (Base->isVirtual())
- continue;
-
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- EmitClassMemberwiseCopy(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl,
- Base->getType());
- }
- for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
- E = ClassDecl->field_end(); I != E; ++I) {
- const FieldDecl *Field = *I;
-
- QualType FieldType = getContext().getCanonicalType(Field->getType());
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
-
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0);
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *DestBaseAddrPtr =
- Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- llvm::Value *SrcBaseAddrPtr =
- Builder.CreateBitCast(RHS.getAddress(), BasePtr);
- EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array,
- FieldClassDecl, FieldType);
- }
- else
- EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(),
- 0 /*ClassDecl*/, FieldClassDecl, FieldType);
- continue;
- }
-
- if (Field->getType()->isReferenceType()) {
- unsigned FieldIndex = CGM.getTypes().getLLVMFieldNo(Field);
-
- llvm::Value *LHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex,
- "lhs.ref");
-
- llvm::Value *RHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex,
- "rhs.ref");
-
- // Load the value in RHS.
- RHS = Builder.CreateLoad(RHS);
-
- // And store it in the LHS
- Builder.CreateStore(RHS, LHS);
-
- continue;
- }
- // Do a built-in assignment of scalar data members.
- LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0);
-
- if (!hasAggregateLLVMType(Field->getType())) {
- RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
- EmitStoreThroughLValue(RVRHS, LHS, Field->getType());
- } else if (Field->getType()->isAnyComplexType()) {
- ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(),
- RHS.isVolatileQualified());
- StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified());
- } else {
- EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType());
- }
- }
-
- InitializeVtablePtrs(ClassDecl);
- FinishFunction();
-}
-
-/// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator.
-/// Before the implicitly-declared copy assignment operator for a class is
-/// implicitly defined, all implicitly- declared copy assignment operators for
-/// its direct base classes and its nonstatic data members shall have been
-/// implicitly defined. [12.8-p12]
-/// The implicitly-defined copy assignment operator for class X performs
-/// memberwise assignment of its subob- jects. The direct base classes of X are
-/// assigned first, in the order of their declaration in
-/// the base-specifier-list, and then the immediate nonstatic data members of X
-/// are assigned, in the order in which they were declared in the class
-/// definition.Each subobject is assigned in the manner appropriate to its type:
-/// if the subobject is of class type, the copy assignment operator for the
-/// class is used (as if by explicit qualification; that is, ignoring any
-/// possible virtual overriding functions in more derived classes);
-///
-/// if the subobject is an array, each element is assigned, in the manner
-/// appropriate to the element type;
-///
-/// if the subobject is of scalar type, the built-in assignment operator is
-/// used.
-void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD,
- llvm::Function *Fn,
- const FunctionArgList &Args) {
-
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
- assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
- "SynthesizeCXXCopyAssignment - copy assignment has user declaration");
- StartFunction(CD, CD->getResultType(), Fn, Args, SourceLocation());
-
- FunctionArgList::const_iterator i = Args.begin();
- const VarDecl *ThisArg = i->first;
- llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg);
- llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this");
- const VarDecl *SrcArg = (i+1)->first;
- llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg);
- llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj);
-
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- // FIXME. copy assignment of virtual base NYI
- if (Base->isVirtual())
- continue;
+ llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl);
+ CodeGenModule::AddrSubMap_t& AddressPoints =
+ *(*CGM.AddressPoints[ClassDecl])[ClassDecl];
+ llvm::Value *ThisPtr = LoadCXXThis();
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl);
+ // Store address points for virtual bases
+ for (CXXRecordDecl::base_class_const_iterator I =
+ ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); I != E; ++I) {
+ const CXXBaseSpecifier &Base = *I;
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- EmitClassCopyAssignment(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl,
- Base->getType());
- }
-
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = getContext().getCanonicalType((*Field)->getType());
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
-
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *DestBaseAddrPtr =
- Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- llvm::Value *SrcBaseAddrPtr =
- Builder.CreateBitCast(RHS.getAddress(), BasePtr);
- EmitClassAggrCopyAssignment(DestBaseAddrPtr, SrcBaseAddrPtr, Array,
- FieldClassDecl, FieldType);
- }
- else
- EmitClassCopyAssignment(LHS.getAddress(), RHS.getAddress(),
- 0 /*ClassDecl*/, FieldClassDecl, FieldType);
- continue;
- }
- // Do a built-in assignment of scalar data members.
- LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
- if (!hasAggregateLLVMType(Field->getType())) {
- RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
- EmitStoreThroughLValue(RVRHS, LHS, Field->getType());
- } else if (Field->getType()->isAnyComplexType()) {
- ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(),
- RHS.isVolatileQualified());
- StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified());
- } else {
- EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType());
- }
- }
-
- // return *this;
- Builder.CreateStore(LoadOfThis, ReturnValue);
-
- FinishFunction();
-}
-
-static void EmitBaseInitializer(CodeGenFunction &CGF,
- const CXXRecordDecl *ClassDecl,
- CXXBaseOrMemberInitializer *BaseInit,
- CXXCtorType CtorType) {
- assert(BaseInit->isBaseInitializer() &&
- "Must have base initializer!");
-
- llvm::Value *ThisPtr = CGF.LoadCXXThis();
-
- const Type *BaseType = BaseInit->getBaseClass();
- CXXRecordDecl *BaseClassDecl =
- cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
- llvm::Value *V = CGF.GetAddressOfBaseClass(ThisPtr, ClassDecl,
- BaseClassDecl,
- /*NullCheckValue=*/false);
- CGF.EmitCXXConstructorCall(BaseInit->getConstructor(),
- CtorType, V,
- BaseInit->const_arg_begin(),
- BaseInit->const_arg_end());
-}
-
-static void EmitMemberInitializer(CodeGenFunction &CGF,
- const CXXRecordDecl *ClassDecl,
- CXXBaseOrMemberInitializer *MemberInit) {
- assert(MemberInit->isMemberInitializer() &&
- "Must have member initializer!");
-
- // non-static data member initializers.
- FieldDecl *Field = MemberInit->getMember();
- QualType FieldType = CGF.getContext().getCanonicalType(Field->getType());
-
- llvm::Value *ThisPtr = CGF.LoadCXXThis();
- LValue LHS;
- if (FieldType->isReferenceType()) {
- // FIXME: This is really ugly; should be refactored somehow
- unsigned idx = CGF.CGM.getTypes().getLLVMFieldNo(Field);
- llvm::Value *V = CGF.Builder.CreateStructGEP(ThisPtr, idx, "tmp");
- assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
- LHS = LValue::MakeAddr(V, CGF.MakeQualifiers(FieldType));
- } else {
- LHS = CGF.EmitLValueForField(ThisPtr, Field, ClassDecl->isUnion(), 0);
- }
-
- // If we are initializing an anonymous union field, drill down to the field.
- if (MemberInit->getAnonUnionMember()) {
- Field = MemberInit->getAnonUnionMember();
- LHS = CGF.EmitLValueForField(LHS.getAddress(), Field,
- /*IsUnion=*/true, 0);
- FieldType = Field->getType();
- }
-
- // If the field is an array, branch based on the element type.
- const ConstantArrayType *Array =
- CGF.getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = CGF.getContext().getBaseElementType(FieldType);
-
- // We lose the constructor for anonymous union members, so handle them
- // explicitly.
- // FIXME: This is somwhat ugly.
- if (MemberInit->getAnonUnionMember() && FieldType->getAs<RecordType>()) {
- if (MemberInit->getNumArgs())
- CGF.EmitAggExpr(*MemberInit->arg_begin(), LHS.getAddress(),
- LHS.isVolatileQualified());
- else
- CGF.EmitAggregateClear(LHS.getAddress(), Field->getType());
- return;
- }
-
- if (FieldType->getAs<RecordType>()) {
- assert(MemberInit->getConstructor() &&
- "EmitCtorPrologue - no constructor to initialize member");
- if (Array) {
- const llvm::Type *BasePtr = CGF.ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- CGF.EmitCXXAggrConstructorCall(MemberInit->getConstructor(),
- Array, BaseAddrPtr,
- MemberInit->const_arg_begin(),
- MemberInit->const_arg_end());
- }
- else
- CGF.EmitCXXConstructorCall(MemberInit->getConstructor(),
- Ctor_Complete, LHS.getAddress(),
- MemberInit->const_arg_begin(),
- MemberInit->const_arg_end());
- return;
- }
-
- assert(MemberInit->getNumArgs() == 1 && "Initializer count must be 1 only");
- Expr *RhsExpr = *MemberInit->arg_begin();
- RValue RHS;
- if (FieldType->isReferenceType()) {
- RHS = CGF.EmitReferenceBindingToExpr(RhsExpr, FieldType,
- /*IsInitializer=*/true);
- CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
- } else if (Array) {
- CGF.EmitMemSetToZero(LHS.getAddress(), Field->getType());
- } else if (!CGF.hasAggregateLLVMType(RhsExpr->getType())) {
- RHS = RValue::get(CGF.EmitScalarExpr(RhsExpr, true));
- CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
- } else if (RhsExpr->getType()->isAnyComplexType()) {
- CGF.EmitComplexExprIntoAddr(RhsExpr, LHS.getAddress(),
- LHS.isVolatileQualified());
- } else {
- // Handle member function pointers; other aggregates shouldn't get this far.
- CGF.EmitAggExpr(RhsExpr, LHS.getAddress(), LHS.isVolatileQualified());
- }
-}
-
-/// EmitCtorPrologue - This routine generates necessary code to initialize
-/// base classes and non-static data members belonging to this constructor.
-/// FIXME: This needs to take a CXXCtorType.
-void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
- CXXCtorType CtorType) {
- const CXXRecordDecl *ClassDecl = CD->getParent();
-
- // FIXME: Add vbase initialization
-
- for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(),
- E = CD->init_end();
- B != E; ++B) {
- CXXBaseOrMemberInitializer *Member = (*B);
-
- assert(LiveTemporaries.empty() &&
- "Should not have any live temporaries at initializer start!");
-
- if (Member->isBaseInitializer())
- EmitBaseInitializer(*this, ClassDecl, Member, CtorType);
- else
- EmitMemberInitializer(*this, ClassDecl, Member);
-
- // Pop any live temporaries that the initializers might have pushed.
- while (!LiveTemporaries.empty())
- PopCXXTemporary();
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+ uint64_t Offset = Layout.getVBaseClassOffset(BaseClassDecl);
+ InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
+ ThisPtr, Offset);
}
- InitializeVtablePtrs(ClassDecl);
+ // Store address points for non-virtual bases and current class
+ InitializeVtablePtrsRecursive(ClassDecl, Vtable, AddressPoints, ThisPtr, 0);
}
-void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) {
+void CodeGenFunction::InitializeVtablePtrsRecursive(
+ const CXXRecordDecl *ClassDecl,
+ llvm::Constant *Vtable,
+ CodeGenModule::AddrSubMap_t& AddressPoints,
+ llvm::Value *ThisPtr,
+ uint64_t Offset) {
if (!ClassDecl->isDynamicClass())
return;
-
- // Initialize the vtable pointer.
- // FIXME: This needs to initialize secondary vtable pointers too.
- llvm::Value *ThisPtr = LoadCXXThis();
- llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl);
- uint64_t AddressPoint = CGM.getVtableInfo().getVtableAddressPoint(ClassDecl);
-
- llvm::Value *VtableAddressPoint =
- Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint);
-
- llvm::Value *VtableField =
- Builder.CreateBitCast(ThisPtr,
- VtableAddressPoint->getType()->getPointerTo());
-
- Builder.CreateStore(VtableAddressPoint, VtableField);
-}
-
-/// EmitDtorEpilogue - Emit all code that comes at the end of class's
-/// destructor. This is to call destructors on members and base classes
-/// in reverse order of their construction.
-/// FIXME: This needs to take a CXXDtorType.
-void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
- CXXDtorType DtorType) {
- assert(!DD->isTrivial() &&
- "Should not emit dtor epilogue for trivial dtor!");
-
- const CXXRecordDecl *ClassDecl = DD->getParent();
-
- // Collect the fields.
- llvm::SmallVector<const FieldDecl *, 16> FieldDecls;
- for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
- E = ClassDecl->field_end(); I != E; ++I) {
- const FieldDecl *Field = *I;
-
- QualType FieldType = getContext().getCanonicalType(Field->getType());
- FieldType = getContext().getBaseElementType(FieldType);
-
- const RecordType *RT = FieldType->getAs<RecordType>();
- if (!RT)
- continue;
-
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (FieldClassDecl->hasTrivialDestructor())
- continue;
-
- FieldDecls.push_back(Field);
- }
-
- // Now destroy the fields.
- for (size_t i = FieldDecls.size(); i > 0; --i) {
- const FieldDecl *Field = FieldDecls[i - 1];
-
- QualType FieldType = Field->getType();
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
-
- const RecordType *RT = FieldType->getAs<RecordType>();
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
-
- llvm::Value *ThisPtr = LoadCXXThis();
-
- LValue LHS = EmitLValueForField(ThisPtr, Field,
- /*isUnion=*/false,
- // FIXME: Qualifiers?
- /*CVRQualifiers=*/0);
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()),
- Array, BaseAddrPtr);
- } else
- EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()),
- Dtor_Complete, LHS.getAddress());
- }
-
- // Destroy non-virtual bases.
- for (CXXRecordDecl::reverse_base_class_const_iterator I =
- ClassDecl->bases_rbegin(), E = ClassDecl->bases_rend(); I != E; ++I) {
+ // Store address points for non-virtual bases
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl);
+ for (CXXRecordDecl::base_class_const_iterator I =
+ ClassDecl->bases_begin(), E = ClassDecl->bases_end(); I != E; ++I) {
const CXXBaseSpecifier &Base = *I;
-
- // Ignore virtual bases.
if (Base.isVirtual())
continue;
-
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
-
- // Ignore trivial destructors.
- if (BaseClassDecl->hasTrivialDestructor())
- continue;
- const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
-
- llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(),
- ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- EmitCXXDestructorCall(D, Dtor_Base, V);
+ uint64_t NewOffset = Offset + Layout.getBaseClassOffset(BaseClassDecl);
+ InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
+ ThisPtr, NewOffset);
}
- // If we're emitting a base destructor, we don't want to emit calls to the
- // virtual bases.
- if (DtorType == Dtor_Base)
- return;
-
- // Handle virtual bases.
- for (CXXRecordDecl::reverse_base_class_const_iterator I =
- ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) {
- const CXXBaseSpecifier &Base = *I;
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
-
- // Ignore trivial destructors.
- if (BaseClassDecl->hasTrivialDestructor())
- continue;
- const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
- llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(),
- ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- EmitCXXDestructorCall(D, Dtor_Base, V);
- }
-
- // If we have a deleting destructor, emit a call to the delete operator.
- if (DtorType == Dtor_Deleting) {
- assert(DD->getOperatorDelete() &&
- "operator delete missing - EmitDtorEpilogue");
- EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(),
- getContext().getTagDeclType(ClassDecl));
- }
-}
-
-void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType,
- llvm::Function *Fn,
- const FunctionArgList &Args) {
- assert(!Dtor->getParent()->hasUserDeclaredDestructor() &&
- "SynthesizeDefaultDestructor - destructor has user declaration");
+ // Compute the address point
+ assert(AddressPoints.count(std::make_pair(ClassDecl, Offset)) &&
+ "Missing address point for class");
+ uint64_t AddressPoint = AddressPoints[std::make_pair(ClassDecl, Offset)];
+ llvm::Value *VtableAddressPoint =
+ Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint);
- StartFunction(GlobalDecl(Dtor, DtorType), Dtor->getResultType(), Fn, Args,
- SourceLocation());
+ // Compute the address to store the address point
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ llvm::Value *VtableField = Builder.CreateBitCast(ThisPtr, Int8PtrTy);
+ VtableField = Builder.CreateConstInBoundsGEP1_64(VtableField, Offset/8);
+ const llvm::Type *AddressPointPtrTy =
+ VtableAddressPoint->getType()->getPointerTo();
+ VtableField = Builder.CreateBitCast(VtableField, AddressPointPtrTy);
- EmitDtorEpilogue(Dtor, DtorType);
- FinishFunction();
+ // Store address point
+ Builder.CreateStore(VtableAddressPoint, VtableField);
}
+
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 4856f54..2dda0b8 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -346,6 +346,7 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
/// destination type; the upper bits of the src will be lost.
static void CreateCoercedStore(llvm::Value *Src,
llvm::Value *DstPtr,
+ bool DstIsVolatile,
CodeGenFunction &CGF) {
const llvm::Type *SrcTy = Src->getType();
const llvm::Type *DstTy =
@@ -359,7 +360,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)->setAlignment(1);
+ CGF.Builder.CreateStore(Src, Casted, DstIsVolatile)->setAlignment(1);
} else {
// Otherwise do coercion through memory. This is stupid, but
// simple.
@@ -377,7 +378,7 @@ static void CreateCoercedStore(llvm::Value *Src,
llvm::LoadInst *Load = CGF.Builder.CreateLoad(Casted);
// FIXME: Use better alignment / avoid requiring aligned load.
Load->setAlignment(1);
- CGF.Builder.CreateStore(Load, DstPtr);
+ CGF.Builder.CreateStore(Load, DstPtr, DstIsVolatile);
}
}
@@ -732,7 +733,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// result in a new alloca anyway, so we could just store into that
// directly if we broke the abstraction down more.
llvm::Value *V = CreateTempAlloca(ConvertTypeForMem(Ty), "coerce");
- CreateCoercedStore(AI, V, *this);
+ CreateCoercedStore(AI, V, /*DestIsVolatile=*/false, *this);
// Match to what EmitParmDecl is expecting for this type.
if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
V = EmitLoadOfScalar(V, false, Ty);
@@ -809,6 +810,7 @@ RValue CodeGenFunction::EmitCallArg(const Expr *E, QualType ArgType) {
RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::Value *Callee,
+ ReturnValueSlot ReturnValue,
const CallArgList &CallArgs,
const Decl *TargetDecl) {
// FIXME: We no longer need the types from CallArgs; lift up and simplify.
@@ -821,9 +823,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// If the call returns a temporary with struct return, create a temporary
- // alloca to hold the result.
- if (CGM.ReturnTypeUsesSret(CallInfo))
- Args.push_back(CreateTempAlloca(ConvertTypeForMem(RetTy)));
+ // alloca to hold the result, unless one is given to us.
+ if (CGM.ReturnTypeUsesSret(CallInfo)) {
+ llvm::Value *Value = ReturnValue.getValue();
+ if (!Value)
+ Value = CreateTempAlloca(ConvertTypeForMem(RetTy));
+ Args.push_back(Value);
+ }
assert(CallInfo.arg_size() == CallArgs.size() &&
"Mismatch between function signature & arguments.");
@@ -972,9 +978,15 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
return RValue::getComplex(std::make_pair(Real, Imag));
}
if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
- llvm::Value *V = CreateTempAlloca(ConvertTypeForMem(RetTy), "agg.tmp");
- Builder.CreateStore(CI, V);
- return RValue::getAggregate(V);
+ llvm::Value *DestPtr = ReturnValue.getValue();
+ bool DestIsVolatile = ReturnValue.isVolatile();
+
+ if (!DestPtr) {
+ DestPtr = CreateTempAlloca(ConvertTypeForMem(RetTy), "agg.tmp");
+ DestIsVolatile = false;
+ }
+ Builder.CreateStore(CI, DestPtr, DestIsVolatile);
+ return RValue::getAggregate(DestPtr);
}
return RValue::get(CI);
@@ -984,14 +996,20 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
return GetUndefRValue(RetTy);
case ABIArgInfo::Coerce: {
- // FIXME: Avoid the conversion through memory if possible.
- llvm::Value *V = CreateTempAlloca(ConvertTypeForMem(RetTy), "coerce");
- CreateCoercedStore(CI, V, *this);
+ llvm::Value *DestPtr = ReturnValue.getValue();
+ bool DestIsVolatile = ReturnValue.isVolatile();
+
+ if (!DestPtr) {
+ DestPtr = CreateTempAlloca(ConvertTypeForMem(RetTy), "coerce");
+ DestIsVolatile = false;
+ }
+
+ CreateCoercedStore(CI, DestPtr, DestIsVolatile, *this);
if (RetTy->isAnyComplexType())
- return RValue::getComplex(LoadComplexFromAddr(V, false));
+ return RValue::getComplex(LoadComplexFromAddr(DestPtr, false));
if (CodeGenFunction::hasAggregateLLVMType(RetTy))
- return RValue::getAggregate(V);
- return RValue::get(EmitLoadOfScalar(V, false, RetTy));
+ return RValue::getAggregate(DestPtr);
+ return RValue::get(EmitLoadOfScalar(DestPtr, false, RetTy));
}
case ABIArgInfo::Expand:
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index ebf801d..427ab5f 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -15,7 +15,8 @@
#ifndef CLANG_CODEGEN_CGCALL_H
#define CLANG_CODEGEN_CGCALL_H
-#include <llvm/ADT/FoldingSet.h>
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Value.h"
#include "clang/AST/Type.h"
#include "CGValue.h"
@@ -123,6 +124,23 @@ namespace CodeGen {
begin->Profile(ID);
}
};
+
+ /// ReturnValueSlot - Contains the address where the return value of a
+ /// function can be stored, and whether the address is volatile or not.
+ class ReturnValueSlot {
+ llvm::PointerIntPair<llvm::Value *, 1, bool> Value;
+
+ public:
+ ReturnValueSlot() {}
+ ReturnValueSlot(llvm::Value *Value, bool IsVolatile)
+ : Value(Value, IsVolatile) {}
+
+ bool isNull() const { return !getValue(); }
+
+ bool isVolatile() const { return Value.getInt(); }
+ llvm::Value *getValue() const { return Value.getPointer(); }
+ };
+
} // end namespace CodeGen
} // end namespace clang
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index fd2afe7..953b8c8 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -269,3 +269,778 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
return Value;
}
+
+/// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class
+/// array of objects from SrcValue to DestValue. Copying can be either a bitwise
+/// copy or via a copy constructor call.
+// FIXME. Consolidate this with EmitCXXAggrConstructorCall.
+void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
+ llvm::Value *Src,
+ const ArrayType *Array,
+ const CXXRecordDecl *BaseClassDecl,
+ QualType Ty) {
+ const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
+ assert(CA && "VLA cannot be copied over");
+ bool BitwiseCopy = BaseClassDecl->hasTrivialCopyConstructor();
+
+ // Create a temporary for the loop index and initialize it with 0.
+ llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
+ "loop.index");
+ llvm::Value* zeroConstant =
+ llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
+ Builder.CreateStore(zeroConstant, IndexPtr);
+ // Start the loop with a block that tests the condition.
+ llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
+ llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
+
+ EmitBlock(CondBlock);
+
+ llvm::BasicBlock *ForBody = createBasicBlock("for.body");
+ // Generate: if (loop-index < number-of-elements fall to the loop body,
+ // otherwise, go to the block after the for-loop.
+ uint64_t NumElements = getContext().getConstantArrayElementCount(CA);
+ llvm::Value * NumElementsPtr =
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements);
+ llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
+ llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr,
+ "isless");
+ // If the condition is true, execute the body.
+ Builder.CreateCondBr(IsLess, ForBody, AfterFor);
+
+ EmitBlock(ForBody);
+ llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
+ // Inside the loop body, emit the constructor call on the array element.
+ Counter = Builder.CreateLoad(IndexPtr);
+ Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress");
+ Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress");
+ if (BitwiseCopy)
+ EmitAggregateCopy(Dest, Src, Ty);
+ else if (CXXConstructorDecl *BaseCopyCtor =
+ BaseClassDecl->getCopyConstructor(getContext(), 0)) {
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor,
+ Ctor_Complete);
+ CallArgList CallArgs;
+ // Push the this (Dest) ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Dest),
+ BaseCopyCtor->getThisType(getContext())));
+
+ // Push the Src ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Src),
+ BaseCopyCtor->getParamDecl(0)->getType()));
+ QualType ResultType =
+ BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType();
+ EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor);
+ }
+ EmitBlock(ContinueBlock);
+
+ // Emit the increment of the loop counter.
+ llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
+ Counter = Builder.CreateLoad(IndexPtr);
+ NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
+ Builder.CreateStore(NextVal, IndexPtr);
+
+ // Finally, branch back up to the condition for the next iteration.
+ EmitBranch(CondBlock);
+
+ // Emit the fall-through block.
+ EmitBlock(AfterFor, true);
+}
+
+/// EmitClassAggrCopyAssignment - This routine generates code to assign a class
+/// array of objects from SrcValue to DestValue. Assignment can be either a
+/// bitwise assignment or via a copy assignment operator function call.
+/// FIXME. This can be consolidated with EmitClassAggrMemberwiseCopy
+void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
+ llvm::Value *Src,
+ const ArrayType *Array,
+ const CXXRecordDecl *BaseClassDecl,
+ QualType Ty) {
+ const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
+ assert(CA && "VLA cannot be asssigned");
+ bool BitwiseAssign = BaseClassDecl->hasTrivialCopyAssignment();
+
+ // Create a temporary for the loop index and initialize it with 0.
+ llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
+ "loop.index");
+ llvm::Value* zeroConstant =
+ llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
+ Builder.CreateStore(zeroConstant, IndexPtr);
+ // Start the loop with a block that tests the condition.
+ llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
+ llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
+
+ EmitBlock(CondBlock);
+
+ llvm::BasicBlock *ForBody = createBasicBlock("for.body");
+ // Generate: if (loop-index < number-of-elements fall to the loop body,
+ // otherwise, go to the block after the for-loop.
+ uint64_t NumElements = getContext().getConstantArrayElementCount(CA);
+ llvm::Value * NumElementsPtr =
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements);
+ llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
+ llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr,
+ "isless");
+ // If the condition is true, execute the body.
+ Builder.CreateCondBr(IsLess, ForBody, AfterFor);
+
+ EmitBlock(ForBody);
+ llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
+ // Inside the loop body, emit the assignment operator call on array element.
+ Counter = Builder.CreateLoad(IndexPtr);
+ Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress");
+ Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress");
+ const CXXMethodDecl *MD = 0;
+ if (BitwiseAssign)
+ EmitAggregateCopy(Dest, Src, Ty);
+ else {
+ bool hasCopyAssign = BaseClassDecl->hasConstCopyAssignment(getContext(),
+ MD);
+ assert(hasCopyAssign && "EmitClassAggrCopyAssignment - No user assign");
+ (void)hasCopyAssign;
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const llvm::Type *LTy =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+ llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy);
+
+ CallArgList CallArgs;
+ // Push the this (Dest) ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Dest),
+ MD->getThisType(getContext())));
+
+ // Push the Src ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Src),
+ MD->getParamDecl(0)->getType()));
+ QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
+ EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ Callee, ReturnValueSlot(), CallArgs, MD);
+ }
+ EmitBlock(ContinueBlock);
+
+ // Emit the increment of the loop counter.
+ llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
+ Counter = Builder.CreateLoad(IndexPtr);
+ NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
+ Builder.CreateStore(NextVal, IndexPtr);
+
+ // Finally, branch back up to the condition for the next iteration.
+ EmitBranch(CondBlock);
+
+ // Emit the fall-through block.
+ EmitBlock(AfterFor, true);
+}
+
+/// EmitClassMemberwiseCopy - This routine generates code to copy a class
+/// object from SrcValue to DestValue. Copying can be either a bitwise copy
+/// or via a copy constructor call.
+void CodeGenFunction::EmitClassMemberwiseCopy(
+ llvm::Value *Dest, llvm::Value *Src,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl, QualType Ty) {
+ if (ClassDecl) {
+ Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ }
+ if (BaseClassDecl->hasTrivialCopyConstructor()) {
+ EmitAggregateCopy(Dest, Src, Ty);
+ return;
+ }
+
+ if (CXXConstructorDecl *BaseCopyCtor =
+ BaseClassDecl->getCopyConstructor(getContext(), 0)) {
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor,
+ Ctor_Complete);
+ CallArgList CallArgs;
+ // Push the this (Dest) ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Dest),
+ BaseCopyCtor->getThisType(getContext())));
+
+ // Push the Src ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Src),
+ BaseCopyCtor->getParamDecl(0)->getType()));
+ QualType ResultType =
+ BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType();
+ EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor);
+ }
+}
+
+/// EmitClassCopyAssignment - This routine generates code to copy assign a class
+/// object from SrcValue to DestValue. Assignment can be either a bitwise
+/// assignment of via an assignment operator call.
+// FIXME. Consolidate this with EmitClassMemberwiseCopy as they share a lot.
+void CodeGenFunction::EmitClassCopyAssignment(
+ llvm::Value *Dest, llvm::Value *Src,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl,
+ QualType Ty) {
+ if (ClassDecl) {
+ Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ }
+ if (BaseClassDecl->hasTrivialCopyAssignment()) {
+ EmitAggregateCopy(Dest, Src, Ty);
+ return;
+ }
+
+ const CXXMethodDecl *MD = 0;
+ bool ConstCopyAssignOp = BaseClassDecl->hasConstCopyAssignment(getContext(),
+ MD);
+ assert(ConstCopyAssignOp && "EmitClassCopyAssignment - missing copy assign");
+ (void)ConstCopyAssignOp;
+
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const llvm::Type *LTy =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+ llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy);
+
+ CallArgList CallArgs;
+ // Push the this (Dest) ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Dest),
+ MD->getThisType(getContext())));
+
+ // Push the Src ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Src),
+ MD->getParamDecl(0)->getType()));
+ QualType ResultType =
+ MD->getType()->getAs<FunctionType>()->getResultType();
+ EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ Callee, ReturnValueSlot(), CallArgs, MD);
+}
+
+/// SynthesizeDefaultConstructor - synthesize a default constructor
+void
+CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor,
+ CXXCtorType Type,
+ llvm::Function *Fn,
+ const FunctionArgList &Args) {
+ assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor");
+ StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args,
+ SourceLocation());
+ EmitCtorPrologue(Ctor, Type);
+ FinishFunction();
+}
+
+/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a
+/// copy constructor, in accordance with section 12.8 (p7 and p8) of C++03
+/// The implicitly-defined copy constructor for class X performs a memberwise
+/// copy of its subobjects. The order of copying is the same as the order of
+/// initialization of bases and members in a user-defined constructor
+/// Each subobject is copied in the manner appropriate to its type:
+/// if the subobject is of class type, the copy constructor for the class is
+/// used;
+/// if the subobject is an array, each element is copied, in the manner
+/// appropriate to the element type;
+/// if the subobject is of scalar type, the built-in assignment operator is
+/// used.
+/// Virtual base class subobjects shall be copied only once by the
+/// implicitly-defined copy constructor
+
+void
+CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
+ CXXCtorType Type,
+ llvm::Function *Fn,
+ const FunctionArgList &Args) {
+ const CXXRecordDecl *ClassDecl = Ctor->getParent();
+ assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
+ "SynthesizeCXXCopyConstructor - copy constructor has definition already");
+ assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor");
+ StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args,
+ SourceLocation());
+
+ FunctionArgList::const_iterator i = Args.begin();
+ const VarDecl *ThisArg = i->first;
+ llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg);
+ llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this");
+ const VarDecl *SrcArg = (i+1)->first;
+ llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg);
+ llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj);
+
+ for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ // FIXME. copy constrution of virtual base NYI
+ if (Base->isVirtual())
+ continue;
+
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ EmitClassMemberwiseCopy(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl,
+ Base->getType());
+ }
+
+ for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); I != E; ++I) {
+ const FieldDecl *Field = *I;
+
+ QualType FieldType = getContext().getCanonicalType(Field->getType());
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = getContext().getBaseElementType(FieldType);
+
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
+ CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0);
+ if (Array) {
+ const llvm::Type *BasePtr = ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *DestBaseAddrPtr =
+ Builder.CreateBitCast(LHS.getAddress(), BasePtr);
+ llvm::Value *SrcBaseAddrPtr =
+ Builder.CreateBitCast(RHS.getAddress(), BasePtr);
+ EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array,
+ FieldClassDecl, FieldType);
+ }
+ else
+ EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(),
+ 0 /*ClassDecl*/, FieldClassDecl, FieldType);
+ continue;
+ }
+
+ if (Field->getType()->isReferenceType()) {
+ unsigned FieldIndex = CGM.getTypes().getLLVMFieldNo(Field);
+
+ llvm::Value *LHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex,
+ "lhs.ref");
+
+ llvm::Value *RHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex,
+ "rhs.ref");
+
+ // Load the value in RHS.
+ RHS = Builder.CreateLoad(RHS);
+
+ // And store it in the LHS
+ Builder.CreateStore(RHS, LHS);
+
+ continue;
+ }
+ // Do a built-in assignment of scalar data members.
+ LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0);
+
+ if (!hasAggregateLLVMType(Field->getType())) {
+ RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
+ EmitStoreThroughLValue(RVRHS, LHS, Field->getType());
+ } else if (Field->getType()->isAnyComplexType()) {
+ ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(),
+ RHS.isVolatileQualified());
+ StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified());
+ } else {
+ EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType());
+ }
+ }
+
+ InitializeVtablePtrs(ClassDecl);
+ FinishFunction();
+}
+
+/// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator.
+/// Before the implicitly-declared copy assignment operator for a class is
+/// implicitly defined, all implicitly- declared copy assignment operators for
+/// its direct base classes and its nonstatic data members shall have been
+/// implicitly defined. [12.8-p12]
+/// The implicitly-defined copy assignment operator for class X performs
+/// memberwise assignment of its subob- jects. The direct base classes of X are
+/// assigned first, in the order of their declaration in
+/// the base-specifier-list, and then the immediate nonstatic data members of X
+/// are assigned, in the order in which they were declared in the class
+/// definition.Each subobject is assigned in the manner appropriate to its type:
+/// if the subobject is of class type, the copy assignment operator for the
+/// class is used (as if by explicit qualification; that is, ignoring any
+/// possible virtual overriding functions in more derived classes);
+///
+/// if the subobject is an array, each element is assigned, in the manner
+/// appropriate to the element type;
+///
+/// if the subobject is of scalar type, the built-in assignment operator is
+/// used.
+void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD,
+ llvm::Function *Fn,
+ const FunctionArgList &Args) {
+
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
+ assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
+ "SynthesizeCXXCopyAssignment - copy assignment has user declaration");
+ StartFunction(CD, CD->getResultType(), Fn, Args, SourceLocation());
+
+ FunctionArgList::const_iterator i = Args.begin();
+ const VarDecl *ThisArg = i->first;
+ llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg);
+ llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this");
+ const VarDecl *SrcArg = (i+1)->first;
+ llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg);
+ llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj);
+
+ for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ // FIXME. copy assignment of virtual base NYI
+ if (Base->isVirtual())
+ continue;
+
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ EmitClassCopyAssignment(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl,
+ Base->getType());
+ }
+
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ FieldEnd = ClassDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ QualType FieldType = getContext().getCanonicalType((*Field)->getType());
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = getContext().getBaseElementType(FieldType);
+
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
+ CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
+ if (Array) {
+ const llvm::Type *BasePtr = ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *DestBaseAddrPtr =
+ Builder.CreateBitCast(LHS.getAddress(), BasePtr);
+ llvm::Value *SrcBaseAddrPtr =
+ Builder.CreateBitCast(RHS.getAddress(), BasePtr);
+ EmitClassAggrCopyAssignment(DestBaseAddrPtr, SrcBaseAddrPtr, Array,
+ FieldClassDecl, FieldType);
+ }
+ else
+ EmitClassCopyAssignment(LHS.getAddress(), RHS.getAddress(),
+ 0 /*ClassDecl*/, FieldClassDecl, FieldType);
+ continue;
+ }
+ // Do a built-in assignment of scalar data members.
+ LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
+ if (!hasAggregateLLVMType(Field->getType())) {
+ RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
+ EmitStoreThroughLValue(RVRHS, LHS, Field->getType());
+ } else if (Field->getType()->isAnyComplexType()) {
+ ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(),
+ RHS.isVolatileQualified());
+ StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified());
+ } else {
+ EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType());
+ }
+ }
+
+ // return *this;
+ Builder.CreateStore(LoadOfThis, ReturnValue);
+
+ FinishFunction();
+}
+
+static void EmitBaseInitializer(CodeGenFunction &CGF,
+ const CXXRecordDecl *ClassDecl,
+ CXXBaseOrMemberInitializer *BaseInit,
+ CXXCtorType CtorType) {
+ assert(BaseInit->isBaseInitializer() &&
+ "Must have base initializer!");
+
+ llvm::Value *ThisPtr = CGF.LoadCXXThis();
+
+ const Type *BaseType = BaseInit->getBaseClass();
+ CXXRecordDecl *BaseClassDecl =
+ cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
+
+ // FIXME: This method of determining whether a base is virtual is ridiculous;
+ // it should be part of BaseInit.
+ bool isBaseVirtual = false;
+ for (CXXRecordDecl::base_class_const_iterator I = ClassDecl->vbases_begin(),
+ E = ClassDecl->vbases_end(); I != E; ++I)
+ if (I->getType()->getAs<RecordType>()->getDecl() == BaseClassDecl) {
+ isBaseVirtual = true;
+ break;
+ }
+
+ // The base constructor doesn't construct virtual bases.
+ if (CtorType == Ctor_Base && isBaseVirtual)
+ return;
+
+ // Compute the offset to the base; we do this directly instead of using
+ // GetAddressOfBaseClass because the class doesn't have a vtable pointer
+ // at this point.
+ // FIXME: This could be refactored back into GetAddressOfBaseClass if it took
+ // an extra parameter for whether the derived class is the complete object
+ // class.
+ const ASTRecordLayout &Layout =
+ CGF.getContext().getASTRecordLayout(ClassDecl);
+ uint64_t Offset;
+ if (isBaseVirtual)
+ Offset = Layout.getVBaseClassOffset(BaseClassDecl);
+ else
+ Offset = Layout.getBaseClassOffset(BaseClassDecl);
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ const llvm::Type *BaseClassType = CGF.ConvertType(QualType(BaseType, 0));
+ llvm::Value *V = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy);
+ V = CGF.Builder.CreateConstInBoundsGEP1_64(V, Offset/8);
+ V = CGF.Builder.CreateBitCast(V, BaseClassType->getPointerTo());
+
+ // FIXME: This should always use Ctor_Base as the ctor type! (But that
+ // causes crashes in tests.)
+ CGF.EmitCXXConstructorCall(BaseInit->getConstructor(),
+ CtorType, V,
+ BaseInit->const_arg_begin(),
+ BaseInit->const_arg_end());
+}
+
+static void EmitMemberInitializer(CodeGenFunction &CGF,
+ const CXXRecordDecl *ClassDecl,
+ CXXBaseOrMemberInitializer *MemberInit) {
+ assert(MemberInit->isMemberInitializer() &&
+ "Must have member initializer!");
+
+ // non-static data member initializers.
+ FieldDecl *Field = MemberInit->getMember();
+ QualType FieldType = CGF.getContext().getCanonicalType(Field->getType());
+
+ llvm::Value *ThisPtr = CGF.LoadCXXThis();
+ LValue LHS;
+ if (FieldType->isReferenceType()) {
+ // FIXME: This is really ugly; should be refactored somehow
+ unsigned idx = CGF.CGM.getTypes().getLLVMFieldNo(Field);
+ llvm::Value *V = CGF.Builder.CreateStructGEP(ThisPtr, idx, "tmp");
+ assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
+ LHS = LValue::MakeAddr(V, CGF.MakeQualifiers(FieldType));
+ } else {
+ LHS = CGF.EmitLValueForField(ThisPtr, Field, ClassDecl->isUnion(), 0);
+ }
+
+ // If we are initializing an anonymous union field, drill down to the field.
+ if (MemberInit->getAnonUnionMember()) {
+ Field = MemberInit->getAnonUnionMember();
+ LHS = CGF.EmitLValueForField(LHS.getAddress(), Field,
+ /*IsUnion=*/true, 0);
+ FieldType = Field->getType();
+ }
+
+ // If the field is an array, branch based on the element type.
+ const ConstantArrayType *Array =
+ CGF.getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = CGF.getContext().getBaseElementType(FieldType);
+
+ // We lose the constructor for anonymous union members, so handle them
+ // explicitly.
+ // FIXME: This is somwhat ugly.
+ if (MemberInit->getAnonUnionMember() && FieldType->getAs<RecordType>()) {
+ if (MemberInit->getNumArgs())
+ CGF.EmitAggExpr(*MemberInit->arg_begin(), LHS.getAddress(),
+ LHS.isVolatileQualified());
+ else
+ CGF.EmitAggregateClear(LHS.getAddress(), Field->getType());
+ return;
+ }
+
+ if (FieldType->getAs<RecordType>()) {
+ assert(MemberInit->getConstructor() &&
+ "EmitCtorPrologue - no constructor to initialize member");
+ if (Array) {
+ const llvm::Type *BasePtr = CGF.ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr);
+ CGF.EmitCXXAggrConstructorCall(MemberInit->getConstructor(),
+ Array, BaseAddrPtr,
+ MemberInit->const_arg_begin(),
+ MemberInit->const_arg_end());
+ }
+ else
+ CGF.EmitCXXConstructorCall(MemberInit->getConstructor(),
+ Ctor_Complete, LHS.getAddress(),
+ MemberInit->const_arg_begin(),
+ MemberInit->const_arg_end());
+ return;
+ }
+
+ assert(MemberInit->getNumArgs() == 1 && "Initializer count must be 1 only");
+ Expr *RhsExpr = *MemberInit->arg_begin();
+ RValue RHS;
+ if (FieldType->isReferenceType()) {
+ RHS = CGF.EmitReferenceBindingToExpr(RhsExpr, FieldType,
+ /*IsInitializer=*/true);
+ CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
+ } else if (Array) {
+ CGF.EmitMemSetToZero(LHS.getAddress(), Field->getType());
+ } else if (!CGF.hasAggregateLLVMType(RhsExpr->getType())) {
+ RHS = RValue::get(CGF.EmitScalarExpr(RhsExpr, true));
+ CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
+ } else if (RhsExpr->getType()->isAnyComplexType()) {
+ CGF.EmitComplexExprIntoAddr(RhsExpr, LHS.getAddress(),
+ LHS.isVolatileQualified());
+ } else {
+ // Handle member function pointers; other aggregates shouldn't get this far.
+ CGF.EmitAggExpr(RhsExpr, LHS.getAddress(), LHS.isVolatileQualified());
+ }
+}
+
+/// EmitCtorPrologue - This routine generates necessary code to initialize
+/// base classes and non-static data members belonging to this constructor.
+/// FIXME: This needs to take a CXXCtorType.
+void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
+ CXXCtorType CtorType) {
+ const CXXRecordDecl *ClassDecl = CD->getParent();
+
+ // FIXME: Add vbase initialization
+
+ for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(),
+ E = CD->init_end();
+ B != E; ++B) {
+ CXXBaseOrMemberInitializer *Member = (*B);
+
+ assert(LiveTemporaries.empty() &&
+ "Should not have any live temporaries at initializer start!");
+
+ if (Member->isBaseInitializer())
+ EmitBaseInitializer(*this, ClassDecl, Member, CtorType);
+ else
+ EmitMemberInitializer(*this, ClassDecl, Member);
+
+ // Pop any live temporaries that the initializers might have pushed.
+ while (!LiveTemporaries.empty())
+ PopCXXTemporary();
+ }
+
+ InitializeVtablePtrs(ClassDecl);
+}
+
+/// EmitDtorEpilogue - Emit all code that comes at the end of class's
+/// destructor. This is to call destructors on members and base classes
+/// in reverse order of their construction.
+/// FIXME: This needs to take a CXXDtorType.
+void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
+ CXXDtorType DtorType) {
+ assert(!DD->isTrivial() &&
+ "Should not emit dtor epilogue for trivial dtor!");
+
+ const CXXRecordDecl *ClassDecl = DD->getParent();
+
+ // Collect the fields.
+ llvm::SmallVector<const FieldDecl *, 16> FieldDecls;
+ for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); I != E; ++I) {
+ const FieldDecl *Field = *I;
+
+ QualType FieldType = getContext().getCanonicalType(Field->getType());
+ FieldType = getContext().getBaseElementType(FieldType);
+
+ const RecordType *RT = FieldType->getAs<RecordType>();
+ if (!RT)
+ continue;
+
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (FieldClassDecl->hasTrivialDestructor())
+ continue;
+
+ FieldDecls.push_back(Field);
+ }
+
+ // Now destroy the fields.
+ for (size_t i = FieldDecls.size(); i > 0; --i) {
+ const FieldDecl *Field = FieldDecls[i - 1];
+
+ QualType FieldType = Field->getType();
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = getContext().getBaseElementType(FieldType);
+
+ const RecordType *RT = FieldType->getAs<RecordType>();
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+
+ llvm::Value *ThisPtr = LoadCXXThis();
+
+ LValue LHS = EmitLValueForField(ThisPtr, Field,
+ /*isUnion=*/false,
+ // FIXME: Qualifiers?
+ /*CVRQualifiers=*/0);
+ if (Array) {
+ const llvm::Type *BasePtr = ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ Builder.CreateBitCast(LHS.getAddress(), BasePtr);
+ EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()),
+ Array, BaseAddrPtr);
+ } else
+ EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()),
+ Dtor_Complete, LHS.getAddress());
+ }
+
+ // Destroy non-virtual bases.
+ for (CXXRecordDecl::reverse_base_class_const_iterator I =
+ ClassDecl->bases_rbegin(), E = ClassDecl->bases_rend(); I != E; ++I) {
+ const CXXBaseSpecifier &Base = *I;
+
+ // Ignore virtual bases.
+ if (Base.isVirtual())
+ continue;
+
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore trivial destructors.
+ if (BaseClassDecl->hasTrivialDestructor())
+ continue;
+ const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
+
+ llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(),
+ ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ EmitCXXDestructorCall(D, Dtor_Base, V);
+ }
+
+ // If we're emitting a base destructor, we don't want to emit calls to the
+ // virtual bases.
+ if (DtorType == Dtor_Base)
+ return;
+
+ // Handle virtual bases.
+ for (CXXRecordDecl::reverse_base_class_const_iterator I =
+ ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) {
+ const CXXBaseSpecifier &Base = *I;
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore trivial destructors.
+ if (BaseClassDecl->hasTrivialDestructor())
+ continue;
+ const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
+ llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(),
+ ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ EmitCXXDestructorCall(D, Dtor_Base, V);
+ }
+
+ // If we have a deleting destructor, emit a call to the delete operator.
+ if (DtorType == Dtor_Deleting) {
+ assert(DD->getOperatorDelete() &&
+ "operator delete missing - EmitDtorEpilogue");
+ EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(),
+ getContext().getTagDeclType(ClassDecl));
+ }
+}
+
+void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ llvm::Function *Fn,
+ const FunctionArgList &Args) {
+ assert(!Dtor->getParent()->hasUserDeclaredDestructor() &&
+ "SynthesizeDefaultDestructor - destructor has user declaration");
+
+ StartFunction(GlobalDecl(Dtor, DtorType), Dtor->getResultType(), Fn, Args,
+ SourceLocation());
+
+ EmitDtorEpilogue(Dtor, DtorType);
+ FinishFunction();
+}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 2238c89..19695c8 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -123,8 +123,6 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
CLANG_VENDOR
#endif
"clang " CLANG_VERSION_STRING;
- bool isOptimized = LO.Optimize;
- const char *Flags = ""; // FIXME: Encode command line options.
// Figure out which version of the ObjC runtime we have.
unsigned RuntimeVers = 0;
@@ -132,11 +130,9 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
RuntimeVers = LO.ObjCNonFragileABI ? 2 : 1;
// Create new compile unit.
- return Unit = DebugFactory.CreateCompileUnit(LangTag,
- AbsFileName.getLast(),
- AbsFileName.getDirname(),
- Producer, isMain,
- isOptimized, Flags, RuntimeVers);
+ return Unit = DebugFactory.CreateCompileUnit(
+ LangTag, AbsFileName.getLast(), AbsFileName.getDirname(), Producer, isMain,
+ LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers);
}
/// CreateType - Get the Basic type from the cache or create a new
@@ -834,27 +830,43 @@ llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
0, 0, 0, llvm::DIType(), Elements);
}
-static QualType CanonicalizeTypeForDebugInfo(QualType T) {
- switch (T->getTypeClass()) {
- default:
- return T;
- case Type::TemplateSpecialization:
- return cast<TemplateSpecializationType>(T)->desugar();
- case Type::TypeOfExpr: {
- TypeOfExprType *Ty = cast<TypeOfExprType>(T);
- return CanonicalizeTypeForDebugInfo(Ty->getUnderlyingExpr()->getType());
- }
- case Type::TypeOf:
- return cast<TypeOfType>(T)->getUnderlyingType();
- case Type::Decltype:
- return cast<DecltypeType>(T)->getUnderlyingType();
- case Type::QualifiedName:
- return cast<QualifiedNameType>(T)->getNamedType();
- case Type::SubstTemplateTypeParm:
- return cast<SubstTemplateTypeParmType>(T)->getReplacementType();
- case Type::Elaborated:
- return cast<ElaboratedType>(T)->getUnderlyingType();
- }
+static QualType UnwrapTypeForDebugInfo(QualType T) {
+ do {
+ QualType LastT = T;
+ switch (T->getTypeClass()) {
+ default:
+ return T;
+ case Type::TemplateSpecialization:
+ T = cast<TemplateSpecializationType>(T)->desugar();
+ break;
+ case Type::TypeOfExpr: {
+ TypeOfExprType *Ty = cast<TypeOfExprType>(T);
+ T = Ty->getUnderlyingExpr()->getType();
+ break;
+ }
+ case Type::TypeOf:
+ T = cast<TypeOfType>(T)->getUnderlyingType();
+ break;
+ case Type::Decltype:
+ T = cast<DecltypeType>(T)->getUnderlyingType();
+ break;
+ case Type::QualifiedName:
+ T = cast<QualifiedNameType>(T)->getNamedType();
+ break;
+ case Type::SubstTemplateTypeParm:
+ T = cast<SubstTemplateTypeParmType>(T)->getReplacementType();
+ break;
+ case Type::Elaborated:
+ T = cast<ElaboratedType>(T)->getUnderlyingType();
+ break;
+ }
+
+ assert(T != LastT && "Type unwrapping failed to unwrap!");
+ if (T == LastT)
+ return T;
+ } while (true);
+
+ return T;
}
/// getOrCreateType - Get the type from the cache or create a new
@@ -864,8 +876,8 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
if (Ty.isNull())
return llvm::DIType();
- // Canonicalize the type.
- Ty = CanonicalizeTypeForDebugInfo(Ty);
+ // Unwrap the type as needed for debug information.
+ Ty = UnwrapTypeForDebugInfo(Ty);
// Check for existing entry.
std::map<void *, llvm::WeakVH>::iterator it =
@@ -891,6 +903,8 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
if (Ty.hasLocalQualifiers())
return CreateQualifiedType(Ty, Unit);
+ const char *Diag = 0;
+
// Work out details of type.
switch (Ty->getTypeClass()) {
#define TYPE(Class, Base)
@@ -903,11 +917,8 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
// FIXME: Handle these.
case Type::ExtVector:
case Type::Vector:
- case Type::FixedWidthInt:
- return llvm::DIType();
- default:
- assert(false && "Unhandled type class!");
return llvm::DIType();
+
case Type::ObjCObjectPointer:
return CreateType(cast<ObjCObjectPointerType>(Ty), Unit);
case Type::ObjCInterface:
@@ -934,7 +945,29 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
case Type::MemberPointer:
return CreateType(cast<MemberPointerType>(Ty), Unit);
+
+ case Type::TemplateSpecialization:
+ case Type::Elaborated:
+ case Type::QualifiedName:
+ case Type::SubstTemplateTypeParm:
+ case Type::TypeOfExpr:
+ case Type::TypeOf:
+ case Type::Decltype:
+ llvm_unreachable("type should have been unwrapped!");
+ return llvm::DIType();
+
+ case Type::RValueReference:
+ // FIXME: Implement!
+ Diag = "rvalue references";
+ break;
}
+
+ assert(Diag && "Fall through without a diagnostic?");
+ unsigned DiagID = CGM.getDiags().getCustomDiagID(Diagnostic::Error,
+ "debug information for %0 is not yet supported");
+ CGM.getDiags().Report(FullSourceLoc(), DiagID)
+ << Diag;
+ return llvm::DIType();
}
/// EmitFunctionStart - Constructs the debug code for entering a function -
@@ -1067,7 +1100,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty;
+ FType = CGM.getContext().IntTy;
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = CGM.getContext().getTypeAlign(FType);
@@ -1078,7 +1111,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty;
+ FType = CGM.getContext().IntTy;
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = CGM.getContext().getTypeAlign(FType);
@@ -1182,9 +1215,9 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
llvm::DIScope DS(RegionStack.back());
llvm::DILocation DO(NULL);
- llvm::DILocation DL =
- DebugFactory.CreateLocation(Line, Column, DS, DO);
- Builder.SetDebugLocation(Call, DL.getNode());
+ llvm::DILocation DL = DebugFactory.CreateLocation(Line, Column, DS, DO);
+
+ Call->setMetadata("dbg", DL.getNode());
}
/// EmitDeclare - Emit local variable declaration debug info.
@@ -1244,7 +1277,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty;
+ FType = CGM.getContext().IntTy;
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = CGM.getContext().getTypeAlign(FType);
@@ -1255,7 +1288,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty;
+ FType = CGM.getContext().IntTy;
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = CGM.getContext().getTypeAlign(FType);
@@ -1385,7 +1418,8 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
llvm::DILocation DO(NULL);
llvm::DILocation DL =
DebugFactory.CreateLocation(Line, PLoc.getColumn(), DS, DO);
- Builder.SetDebugLocation(Call, DL.getNode());
+
+ Call->setMetadata("dbg", DL.getNode());
}
void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *Decl,
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 14ee90d..602cc9e 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -15,6 +15,7 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/SourceManager.h"
@@ -471,7 +472,8 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
const llvm::Type *IntPtr =
llvm::IntegerType::get(VMContext, LLVMPointerWidth);
llvm::Value *SizeVal =
- llvm::ConstantInt::get(IntPtr, getContext().getTypeSizeInBytes(Ty));
+ llvm::ConstantInt::get(IntPtr,
+ getContext().getTypeSizeInChars(Ty).getRaw());
const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext);
if (Loc->getType() != BP)
@@ -641,7 +643,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr,
ConvertType(ArgTy))),
getContext().getPointerType(D.getType())));
- EmitCall(Info, F, Args);
+ EmitCall(Info, F, ReturnValueSlot(), Args);
}
if (Exceptions) {
EHCleanupBlock Cleanup(*this);
@@ -650,7 +652,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr,
ConvertType(ArgTy))),
getContext().getPointerType(D.getType())));
- EmitCall(Info, F, Args);
+ EmitCall(Info, F, ReturnValueSlot(), Args);
}
}
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index b15b2e9..bd0461f 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -149,21 +149,39 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E,
CGF.EmitAggExpr(E, This, false);
} else if (CXXConstructorDecl *CopyCtor
= RD->getCopyConstructor(CGF.getContext(), 0)) {
- llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest();
+ llvm::Value *CondPtr = 0;
if (CGF.Exceptions) {
CodeGenFunction::EHCleanupBlock Cleanup(CGF);
llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF);
+ llvm::BasicBlock *CondBlock = CGF.createBasicBlock("cond.free");
+ llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
+ CondPtr = CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()),
+ "doEHfree");
+
+ CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CondPtr),
+ CondBlock, Cont);
+ CGF.EmitBlock(CondBlock);
+
// Load the exception pointer.
llvm::Value *ExceptionPtr = CGF.Builder.CreateLoad(ExceptionPtrPtr);
CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr);
+
+ CGF.EmitBlock(Cont);
}
+ if (CondPtr)
+ CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()),
+ CondPtr);
+
llvm::Value *Src = CGF.EmitLValue(E).getAddress();
- CGF.setInvokeDest(PrevLandingPad);
+
+ if (CondPtr)
+ CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()),
+ CondPtr);
llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler();
- PrevLandingPad = CGF.getInvokeDest();
+ llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest();
CGF.setInvokeDest(TerminateHandler);
// Stolen from EmitClassAggrMemberwiseCopy
@@ -179,7 +197,7 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E,
QualType ResultType =
CopyCtor->getType()->getAs<FunctionType>()->getResultType();
CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
- Callee, CallArgs, CopyCtor);
+ Callee, ReturnValueSlot(), CallArgs, CopyCtor);
CGF.setInvokeDest(PrevLandingPad);
} else
llvm_unreachable("uncopyable object");
@@ -189,14 +207,22 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E,
// CopyObject - Utility to copy an object. Calls copy constructor as necessary.
// N is casted to the right type.
static void CopyObject(CodeGenFunction &CGF, QualType ObjectType,
- bool WasPointer, llvm::Value *E, llvm::Value *N) {
+ bool WasPointer, bool WasPointerReference,
+ llvm::Value *E, llvm::Value *N) {
// Store the throw exception in the exception object.
if (WasPointer || !CGF.hasAggregateLLVMType(ObjectType)) {
llvm::Value *Value = E;
if (!WasPointer)
Value = CGF.Builder.CreateLoad(Value);
const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0);
- CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy));
+ if (WasPointerReference) {
+ llvm::Value *Tmp = CGF.CreateTempAlloca(Value->getType(), "catch.param");
+ CGF.Builder.CreateStore(Value, Tmp);
+ Value = Tmp;
+ ValuePtrTy = Value->getType()->getPointerTo(0);
+ }
+ N = CGF.Builder.CreateBitCast(N, ValuePtrTy);
+ CGF.Builder.CreateStore(Value, N);
} else {
const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0);
const CXXRecordDecl *RD;
@@ -221,7 +247,7 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType,
QualType ResultType =
CopyCtor->getType()->getAs<FunctionType>()->getResultType();
CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
- Callee, CallArgs, CopyCtor);
+ Callee, ReturnValueSlot(), CallArgs, CopyCtor);
} else
llvm_unreachable("uncopyable object");
}
@@ -264,7 +290,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
// Now throw the exception.
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
- llvm::Constant *TypeInfo = CGM.GenerateRTTI(ThrowType);
+ llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType);
llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy);
if (getInvokeDest()) {
@@ -347,8 +373,9 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
for (unsigned i = 0; i < Proto->getNumExceptions(); ++i) {
QualType Ty = Proto->getExceptionType(i);
- llvm::Value *EHType
- = CGM.GenerateRTTI(Ty.getNonReferenceType());
+ QualType ExceptType
+ = Ty.getNonReferenceType().getUnqualifiedType();
+ llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType);
SelectorArgs.push_back(EHType);
}
if (Proto->getNumExceptions())
@@ -487,9 +514,12 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
const CXXCatchStmt *C = S.getHandler(i);
VarDecl *CatchParam = C->getExceptionDecl();
if (CatchParam) {
- llvm::Value *EHType
- = CGM.GenerateRTTI(C->getCaughtType().getNonReferenceType());
- SelectorArgs.push_back(EHType);
+ // C++ [except.handle]p3 indicates that top-level cv-qualifiers
+ // are ignored.
+ QualType CaughtType = C->getCaughtType().getNonReferenceType();
+ llvm::Value *EHTypeInfo
+ = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType());
+ SelectorArgs.push_back(EHTypeInfo);
} else {
// null indicates catch all
SelectorArgs.push_back(Null);
@@ -541,7 +571,12 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
QualType CatchType = CatchParam->getType().getNonReferenceType();
setInvokeDest(TerminateHandler);
bool WasPointer = true;
- if (!CatchType.getTypePtr()->isPointerType()) {
+ bool WasPointerReference = false;
+ CatchType = CGM.getContext().getCanonicalType(CatchType);
+ if (CatchType.getTypePtr()->isPointerType()) {
+ if (isa<ReferenceType>(CatchParam->getType()))
+ WasPointerReference = true;
+ } else {
if (!isa<ReferenceType>(CatchParam->getType()))
WasPointer = false;
CatchType = getContext().getPointerType(CatchType);
@@ -552,7 +587,8 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
// cleanup doesn't start until after the ctor completes, use a decl
// init?
CopyObject(*this, CatchParam->getType().getNonReferenceType(),
- WasPointer, ExcObject, GetAddrOfLocalVar(CatchParam));
+ WasPointer, WasPointerReference, ExcObject,
+ GetAddrOfLocalVar(CatchParam));
setInvokeDest(MatchHandler);
}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index e6bbfa8..ab451cf 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -97,13 +97,15 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
bool IsInitializer) {
bool ShouldDestroyTemporaries = false;
unsigned OldNumLiveTemporaries = 0;
-
- if (const CXXExprWithTemporaries *TE = dyn_cast<CXXExprWithTemporaries>(E)) {
- ShouldDestroyTemporaries = TE->shouldDestroyTemporaries();
+ if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E))
+ E = DAE->getExpr();
+
+ if (const CXXExprWithTemporaries *TE = dyn_cast<CXXExprWithTemporaries>(E)) {
+ ShouldDestroyTemporaries = true;
+
// Keep track of the current cleanup stack depth.
- if (ShouldDestroyTemporaries)
- OldNumLiveTemporaries = LiveTemporaries.size();
+ OldNumLiveTemporaries = LiveTemporaries.size();
E = TE->getSubExpr();
}
@@ -209,6 +211,34 @@ unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx,
return cast<llvm::ConstantInt>(Elts->getOperand(Idx))->getZExtValue();
}
+void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) {
+ if (!CatchUndefined)
+ return;
+
+ const llvm::IntegerType *Size_tTy
+ = llvm::IntegerType::get(VMContext, LLVMPointerWidth);
+ Address = Builder.CreateBitCast(Address, PtrToInt8Ty);
+
+ const llvm::Type *ResType[] = {
+ Size_tTy
+ };
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, ResType, 1);
+ const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(
+ CGM.getTypes().ConvertType(CGM.getContext().IntTy));
+ // In time, people may want to control this and use a 1 here.
+ llvm::Value *Arg = llvm::ConstantInt::get(IntTy, 0);
+ llvm::Value *C = Builder.CreateCall2(F, Address, Arg);
+ llvm::BasicBlock *Cont = createBasicBlock();
+ llvm::BasicBlock *Check = createBasicBlock();
+ llvm::Value *NegativeOne = llvm::ConstantInt::get(Size_tTy, -1ULL);
+ Builder.CreateCondBr(Builder.CreateICmpEQ(C, NegativeOne), Cont, Check);
+
+ EmitBlock(Check);
+ Builder.CreateCondBr(Builder.CreateICmpUGE(C,
+ llvm::ConstantInt::get(Size_tTy, Size)),
+ Cont, getTrapBB());
+ EmitBlock(Cont);
+}
//===----------------------------------------------------------------------===//
// LValue Expression Emission
@@ -246,6 +276,13 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E,
MakeQualifiers(E->getType()));
}
+LValue CodeGenFunction::EmitCheckedLValue(const Expr *E) {
+ LValue LV = EmitLValue(E);
+ if (!isa<DeclRefExpr>(E) && !LV.isBitfield() && LV.isSimple())
+ EmitCheck(LV.getAddress(), getContext().getTypeSize(E->getType()) / 8);
+ return LV;
+}
+
/// EmitLValue - Emit code to compute a designator that specifies the location
/// of the expression.
///
@@ -1072,8 +1109,9 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
llvm::IntegerType::get(VMContext, LLVMPointerWidth),
IdxSigned, "idxprom");
+ // FIXME: As llvm implements the object size checking, this can come out.
if (CatchUndefined) {
- if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E->getBase())) {
+ if (const ImplicitCastExpr *ICE=dyn_cast<ImplicitCastExpr>(E->getBase())) {
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr())) {
if (ICE->getCastKind() == CastExpr::CK_ArrayToPointerDecay) {
if (const ConstantArrayType *CAT
@@ -1141,7 +1179,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
static
llvm::Constant *GenerateConstantVector(llvm::LLVMContext &VMContext,
llvm::SmallVector<unsigned, 4> &Elts) {
- llvm::SmallVector<llvm::Constant *, 4> CElts;
+ llvm::SmallVector<llvm::Constant*, 4> CElts;
for (unsigned i = 0, e = Elts.size(); i != e; ++i)
CElts.push_back(llvm::ConstantInt::get(
@@ -1152,21 +1190,37 @@ llvm::Constant *GenerateConstantVector(llvm::LLVMContext &VMContext,
LValue CodeGenFunction::
EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
+ const llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext);
+
// Emit the base vector as an l-value.
LValue Base;
// ExtVectorElementExpr's base can either be a vector or pointer to vector.
- if (!E->isArrow()) {
- assert(E->getBase()->getType()->isVectorType());
- Base = EmitLValue(E->getBase());
- } else {
- const PointerType *PT = E->getBase()->getType()->getAs<PointerType>();
+ if (E->isArrow()) {
+ // If it is a pointer to a vector, emit the address and form an lvalue with
+ // it.
llvm::Value *Ptr = EmitScalarExpr(E->getBase());
+ const PointerType *PT = E->getBase()->getType()->getAs<PointerType>();
Qualifiers Quals = MakeQualifiers(PT->getPointeeType());
Quals.removeObjCGCAttr();
Base = LValue::MakeAddr(Ptr, Quals);
+ } else if (E->getBase()->isLvalue(getContext()) == Expr::LV_Valid) {
+ // Otherwise, if the base is an lvalue ( as in the case of foo.x.x),
+ // emit the base as an lvalue.
+ assert(E->getBase()->getType()->isVectorType());
+ Base = EmitLValue(E->getBase());
+ } else {
+ // Otherwise, the base is a normal rvalue (as in (V+V).x), emit it as such.
+ const VectorType *VT = E->getBase()->getType()->getAs<VectorType>();
+ assert(VT && "Result must be a vector");
+ llvm::Value *Vec = EmitScalarExpr(E->getBase());
+
+ // Store the vector to memory (because LValue wants an address).
+ llvm::Value *VecMem =CreateTempAlloca(ConvertType(E->getBase()->getType()));
+ Builder.CreateStore(Vec, VecMem);
+ Base = LValue::MakeAddr(VecMem, Qualifiers());
}
-
+
// Encode the element access list into a vector of unsigned indices.
llvm::SmallVector<unsigned, 4> Indices;
E->getEncodedElementAccess(Indices);
@@ -1181,7 +1235,6 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
llvm::Constant *BaseElts = Base.getExtVectorElts();
llvm::SmallVector<llvm::Constant *, 4> CElts;
- const llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext);
for (unsigned i = 0, e = Indices.size(); i != e; ++i) {
if (isa<llvm::ConstantAggregateZero>(BaseElts))
CElts.push_back(llvm::ConstantInt::get(Int32Ty, 0));
@@ -1325,12 +1378,20 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){
LValue
CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) {
if (E->isLvalue(getContext()) == Expr::LV_Valid) {
+ if (int Cond = ConstantFoldsToSimpleInteger(E->getCond())) {
+ Expr *Live = Cond == 1 ? E->getLHS() : E->getRHS();
+ if (Live)
+ return EmitLValue(Live);
+ }
+
+ if (!E->getLHS())
+ return EmitUnsupportedLValue(E, "conditional operator with missing LHS");
+
llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true");
llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false");
llvm::BasicBlock *ContBlock = createBasicBlock("cond.end");
- llvm::Value *Cond = EvaluateExprAsBool(E->getCond());
- Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
+ EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
EmitBlock(LHSBlock);
@@ -1390,6 +1451,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CastExpr::CK_NoOp:
case CastExpr::CK_ConstructorConversion:
case CastExpr::CK_UserDefinedConversion:
+ case CastExpr::CK_AnyPointerToObjCPointerCast:
return EmitLValue(E->getSubExpr());
case CastExpr::CK_DerivedToBase: {
@@ -1464,13 +1526,14 @@ LValue CodeGenFunction::EmitNullInitializationLValue(
//===--------------------------------------------------------------------===//
-RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) {
+RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
+ ReturnValueSlot ReturnValue) {
// Builtins never have block type.
if (E->getCallee()->getType()->isBlockPointerType())
- return EmitBlockCallExpr(E);
+ return EmitBlockCallExpr(E, ReturnValue);
if (const CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(E))
- return EmitCXXMemberCallExpr(CE);
+ return EmitCXXMemberCallExpr(CE, ReturnValue);
const Decl *TargetDecl = 0;
if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E->getCallee())) {
@@ -1484,7 +1547,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) {
if (const CXXOperatorCallExpr *CE = dyn_cast<CXXOperatorCallExpr>(E))
if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(TargetDecl))
- return EmitCXXOperatorMemberCallExpr(CE, MD);
+ return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue);
if (isa<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) {
// C++ [expr.pseudo]p1:
@@ -1497,7 +1560,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) {
}
llvm::Value *Callee = EmitScalarExpr(E->getCallee());
- return EmitCall(Callee, E->getCallee()->getType(),
+ return EmitCall(E->getCallee()->getType(), Callee, ReturnValue,
E->arg_begin(), E->arg_end(), TargetDecl);
}
@@ -1658,7 +1721,8 @@ LValue CodeGenFunction::EmitPointerToDataMemberLValue(const FieldDecl *Field) {
return LValue::MakeAddr(V, MakeQualifiers(Field->getType()));
}
-RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType,
+RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
+ ReturnValueSlot ReturnValue,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd,
const Decl *TargetDecl) {
@@ -1683,7 +1747,7 @@ RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType,
CallingConvention = F->getCallingConv();
return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
CallingConvention),
- Callee, Args, TargetDecl);
+ Callee, ReturnValue, Args, TargetDecl);
}
LValue CodeGenFunction::
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 2c122eb..b95fd79 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -106,6 +106,7 @@ public:
void VisitConditionalOperator(const ConditionalOperator *CO);
void VisitChooseExpr(const ChooseExpr *CE);
void VisitInitListExpr(InitListExpr *E);
+ void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
Visit(DAE->getExpr());
}
@@ -271,6 +272,13 @@ void AggExprEmitter::VisitCallExpr(const CallExpr *E) {
return;
}
+ // If the struct doesn't require GC, we can just pass the destination
+ // directly to EmitCall.
+ if (!RequiresGCollection) {
+ CGF.EmitCallExpr(E, ReturnValueSlot(DestPtr, VolatileDest));
+ return;
+ }
+
RValue RV = CGF.EmitCallExpr(E);
EmitFinalDestCopy(E, RV);
}
@@ -388,12 +396,16 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
}
void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) {
+ if (!E->getLHS()) {
+ CGF.ErrorUnsupported(E, "conditional operator with missing LHS");
+ return;
+ }
+
llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true");
llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
- llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond());
- Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
+ CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
CGF.StartConditionalBranch();
CGF.EmitBlock(LHSBlock);
@@ -457,16 +469,45 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
}
+ if (E->requiresZeroInitialization())
+ EmitNullInitializationToLValue(LValue::MakeAddr(Val,
+ // FIXME: Qualifiers()?
+ E->getType().getQualifiers()),
+ E->getType());
+
CGF.EmitCXXConstructExpr(Val, E);
}
void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
- CGF.EmitCXXExprWithTemporaries(E, DestPtr, VolatileDest, IsInitializer);
+ llvm::Value *Val = DestPtr;
+
+ if (!Val) {
+ // Create a temporary variable.
+ Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
+ }
+ CGF.EmitCXXExprWithTemporaries(E, Val, VolatileDest, IsInitializer);
}
void AggExprEmitter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
- LValue lvalue = LValue::MakeAddr(DestPtr, Qualifiers());
- EmitNullInitializationToLValue(lvalue, E->getType());
+ llvm::Value *Val = DestPtr;
+
+ if (!Val) {
+ // Create a temporary variable.
+ Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
+ }
+ LValue LV = LValue::MakeAddr(Val, Qualifiers());
+ EmitNullInitializationToLValue(LV, E->getType());
+}
+
+void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
+ llvm::Value *Val = DestPtr;
+
+ if (!Val) {
+ // Create a temporary variable.
+ Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
+ }
+ LValue LV = LValue::MakeAddr(Val, Qualifiers());
+ EmitNullInitializationToLValue(LV, E->getType());
}
void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 150f11e..7992322 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -78,7 +78,6 @@ static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) {
}
return CalculateCookiePadding(Ctx, E->getAllocatedType());
- QualType T = E->getAllocatedType();
}
static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
@@ -212,7 +211,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// Emit the call to new.
RValue RV =
EmitCall(CGM.getTypes().getFunctionInfo(NewFTy->getResultType(), NewArgs),
- CGM.GetAddrOfFunction(NewFD), NewArgs, NewFD);
+ CGM.GetAddrOfFunction(NewFD), ReturnValueSlot(), NewArgs, NewFD);
// If an allocation function is declared with an empty exception specification
// it returns null to indicate failure to allocate storage. [expr.new]p13.
@@ -354,7 +353,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
// Emit the call to delete.
EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(),
DeleteArgs),
- CGM.GetAddrOfFunction(DeleteFD),
+ CGM.GetAddrOfFunction(DeleteFD), ReturnValueSlot(),
DeleteArgs, DeleteFD);
}
@@ -406,7 +405,7 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
/*isVariadic=*/false);
llvm::Value *Callee = BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty);
- EmitCXXMemberCall(Dtor, Callee, Ptr, 0, 0);
+ EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, 0, 0);
// The dtor took care of deleting the object.
ShouldCallDelete = false;
@@ -426,9 +425,12 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
QualType Ty = E->getType();
const llvm::Type *LTy = ConvertType(Ty)->getPointerTo();
- if (E->isTypeOperand())
- return Builder.CreateBitCast(CGM.GetAddrOfRTTI(E->getTypeOperand()), LTy);
-
+ if (E->isTypeOperand()) {
+ llvm::Constant *TypeInfo =
+ CGM.GetAddrOfRTTIDescriptor(E->getTypeOperand());
+ return Builder.CreateBitCast(TypeInfo, LTy);
+ }
+
Expr *subE = E->getExprOperand();
Ty = subE->getType();
CanQualType CanTy = CGM.getContext().getCanonicalType(Ty);
@@ -468,24 +470,23 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
V = Builder.CreateConstInBoundsGEP1_64(V, -1ULL);
V = Builder.CreateLoad(V);
return V;
- }
- return Builder.CreateBitCast(CGM.GenerateRTTI(RD), LTy);
+ }
}
- return Builder.CreateBitCast(CGM.GenerateRTTI(Ty), LTy);
+ return Builder.CreateBitCast(CGM.GetAddrOfRTTIDescriptor(Ty), LTy);
}
llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
const CXXDynamicCastExpr *DCE) {
- QualType CastTy = DCE->getTypeAsWritten();
- QualType InnerType = CastTy->getPointeeType();
- QualType ArgTy = DCE->getSubExpr()->getType();
- const llvm::Type *LArgTy = ConvertType(ArgTy);
+ QualType SrcTy = DCE->getSubExpr()->getType();
+ QualType DestTy = DCE->getTypeAsWritten();
+ QualType InnerType = DestTy->getPointeeType();
+
const llvm::Type *LTy = ConvertType(DCE->getType());
bool CanBeZero = false;
bool ToVoid = false;
bool ThrowOnBad = false;
- if (CastTy->isPointerType()) {
+ if (DestTy->isPointerType()) {
// FIXME: if PointerType->hasAttr<NonNullAttr>(), we don't set this
CanBeZero = true;
if (InnerType->isVoidType())
@@ -495,14 +496,13 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
ThrowOnBad = true;
}
- CXXRecordDecl *SrcTy;
- QualType Ty = ArgTy;
- if (ArgTy.getTypePtr()->isPointerType()
- || ArgTy.getTypePtr()->isReferenceType())
- Ty = Ty.getTypePtr()->getPointeeType();
- CanQualType CanTy = CGM.getContext().getCanonicalType(Ty);
- Ty = CanTy.getUnqualifiedType();
- SrcTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl());
+ if (SrcTy->isPointerType() || SrcTy->isReferenceType())
+ SrcTy = SrcTy->getPointeeType();
+ SrcTy = SrcTy.getUnqualifiedType();
+
+ if (DestTy->isPointerType() || DestTy->isReferenceType())
+ DestTy = DestTy->getPointeeType();
+ DestTy = DestTy.getUnqualifiedType();
llvm::BasicBlock *ContBlock = createBasicBlock();
llvm::BasicBlock *NullBlock = 0;
@@ -510,15 +510,13 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
if (CanBeZero) {
NonZeroBlock = createBasicBlock();
NullBlock = createBasicBlock();
- llvm::Value *Zero = llvm::Constant::getNullValue(LArgTy);
- Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero),
- NonZeroBlock, NullBlock);
+ Builder.CreateCondBr(Builder.CreateIsNotNull(V), NonZeroBlock, NullBlock);
EmitBlock(NonZeroBlock);
}
llvm::BasicBlock *BadCastBlock = 0;
- const llvm::Type *PtrDiffTy = ConvertType(getContext().getSizeType());
+ const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
// See if this is a dynamic_cast(void*)
if (ToVoid) {
@@ -542,27 +540,27 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
ArgTys.push_back(PtrToInt8Ty);
ArgTys.push_back(PtrDiffTy);
FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
- CXXRecordDecl *DstTy;
- Ty = CastTy.getTypePtr()->getPointeeType();
- CanTy = CGM.getContext().getCanonicalType(Ty);
- Ty = CanTy.getUnqualifiedType();
- DstTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl());
// FIXME: Calculate better hint.
llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL);
- llvm::Value *SrcArg = CGM.GenerateRTTIRef(SrcTy);
- llvm::Value *DstArg = CGM.GenerateRTTIRef(DstTy);
+
+ assert(SrcTy->isRecordType() && "Src type must be record type!");
+ assert(DestTy->isRecordType() && "Dest type must be record type!");
+
+ llvm::Value *SrcArg
+ = CGM.GetAddrOfRTTIDescriptor(SrcTy.getUnqualifiedType());
+ llvm::Value *DestArg
+ = CGM.GetAddrOfRTTIDescriptor(DestTy.getUnqualifiedType());
+
V = Builder.CreateBitCast(V, PtrToInt8Ty);
V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"),
- V, SrcArg, DstArg, hint);
+ V, SrcArg, DestArg, hint);
V = Builder.CreateBitCast(V, LTy);
if (ThrowOnBad) {
BadCastBlock = createBasicBlock();
- llvm::Value *Zero = llvm::Constant::getNullValue(LTy);
- Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero),
- ContBlock, BadCastBlock);
+ Builder.CreateCondBr(Builder.CreateIsNotNull(V), ContBlock, BadCastBlock);
EmitBlock(BadCastBlock);
/// Call __cxa_bad_cast
ResultType = llvm::Type::getVoidTy(VMContext);
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 7fa8ffb..be2239f 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -626,6 +626,14 @@ ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) {
ComplexPairTy ComplexExprEmitter::
VisitConditionalOperator(const ConditionalOperator *E) {
+ if (!E->getLHS()) {
+ CGF.ErrorUnsupported(E, "conditional operator with missing LHS");
+ const llvm::Type *EltTy =
+ CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType());
+ llvm::Value *U = llvm::UndefValue::get(EltTy);
+ return ComplexPairTy(U, U);
+ }
+
TestAndClearIgnoreReal();
TestAndClearIgnoreImag();
TestAndClearIgnoreRealAssign();
@@ -634,8 +642,7 @@ VisitConditionalOperator(const ConditionalOperator *E) {
llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
- llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond());
- Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
+ CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
CGF.EmitBlock(LHSBlock);
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 2f31c05..93646d6 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -69,6 +69,7 @@ public:
const llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); }
LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); }
+ LValue EmitCheckedLValue(const Expr *E) { return CGF.EmitCheckedLValue(E); }
Value *EmitLoadOfLValue(LValue LV, QualType T) {
return CGF.EmitLoadOfLValue(LV, T).getScalarVal();
@@ -78,7 +79,7 @@ public:
/// value l-value, this method emits the address of the l-value, then loads
/// and returns the result.
Value *EmitLoadOfLValue(const Expr *E) {
- return EmitLoadOfLValue(EmitLValue(E), E->getType());
+ return EmitLoadOfLValue(EmitCheckedLValue(E), E->getType());
}
/// EmitConversionToBool - Convert the specified expression value to a
@@ -327,16 +328,16 @@ public:
Value *VisitBin ## OP ## Assign(const CompoundAssignOperator *E) { \
return EmitCompoundAssign(E, &ScalarExprEmitter::Emit ## OP); \
}
- HANDLEBINOP(Mul);
- HANDLEBINOP(Div);
- HANDLEBINOP(Rem);
- HANDLEBINOP(Add);
- HANDLEBINOP(Sub);
- HANDLEBINOP(Shl);
- HANDLEBINOP(Shr);
- HANDLEBINOP(And);
- HANDLEBINOP(Xor);
- HANDLEBINOP(Or);
+ HANDLEBINOP(Mul)
+ HANDLEBINOP(Div)
+ HANDLEBINOP(Rem)
+ HANDLEBINOP(Add)
+ HANDLEBINOP(Sub)
+ HANDLEBINOP(Shl)
+ HANDLEBINOP(Shr)
+ HANDLEBINOP(And)
+ HANDLEBINOP(Xor)
+ HANDLEBINOP(Or)
#undef HANDLEBINOP
// Comparisons.
@@ -346,12 +347,12 @@ public:
Value *VisitBin##CODE(const BinaryOperator *E) { \
return EmitCompare(E, llvm::ICmpInst::UI, llvm::ICmpInst::SI, \
llvm::FCmpInst::FP); }
- VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT);
- VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT);
- VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE);
- VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE);
- VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ);
- VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE);
+ VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT)
+ VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT)
+ VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE)
+ VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE)
+ VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ)
+ VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE)
#undef VISITCOMP
Value *VisitBinAssign (const BinaryOperator *E);
@@ -815,6 +816,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
return Builder.CreateBitCast(Src, ConvertType(DestTy));
}
case CastExpr::CK_NoOp:
+ case CastExpr::CK_UserDefinedConversion:
return Visit(const_cast<Expr*>(E));
case CastExpr::CK_BaseToDerived: {
@@ -902,7 +904,6 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
return Src;
}
- case CastExpr::CK_UserDefinedConversion:
case CastExpr::CK_ConstructorConversion:
assert(0 && "Should be unreachable!");
break;
@@ -1198,7 +1199,7 @@ BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) {
Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
bool Ignore = TestAndClearIgnoreResultAssign();
- QualType LHSTy = E->getLHS()->getType(), RHSTy = E->getRHS()->getType();
+ QualType LHSTy = E->getLHS()->getType();
BinOpInfo OpInfo;
@@ -1217,7 +1218,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
OpInfo.Ty = E->getComputationResultType();
OpInfo.E = E;
// Load/convert the LHS.
- LValue LHSLV = EmitLValue(E->getLHS());
+ LValue LHSLV = EmitCheckedLValue(E->getLHS());
OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy);
OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy,
E->getComputationLHSType());
@@ -1654,7 +1655,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
// __block variables need to have the rhs evaluated first, plus this should
// improve codegen just a little.
Value *RHS = Visit(E->getRHS());
- LValue LHS = EmitLValue(E->getLHS());
+ LValue LHS = EmitCheckedLValue(E->getLHS());
// Store the value into the LHS. Bit-fields are handled specially
// because the result is altered by the store, i.e., [C99 6.5.16p1]
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 2fe3f5b..ac391d9 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -190,7 +190,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
// FIXME: We shouldn't need to get the function info here, the
// runtime already should have computed it to build the function.
RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args),
- GetPropertyFn, Args);
+ GetPropertyFn, ReturnValueSlot(), Args);
// We need to fix the type here. Ivars with copy & retain are
// always objects so we don't need to worry about complex or
// aggregates.
@@ -277,8 +277,8 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
getContext().BoolTy));
// FIXME: We shouldn't need to get the function info here, the runtime
// already should have computed it to build the function.
- EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args),
- SetPropertyFn, Args);
+ EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args), SetPropertyFn,
+ ReturnValueSlot(), Args);
} else {
// FIXME: Find a clean way to avoid AST node creation.
SourceLocation Loc = PD->getLocation();
@@ -553,7 +553,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// FIXME: We shouldn't need to get the function info here, the runtime already
// should have computed it to build the function.
EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2),
- EnumerationMutationFn, Args2);
+ EnumerationMutationFn, ReturnValueSlot(), Args2);
EmitBlock(WasNotMutated);
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index be772c7..95f67ae 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -450,7 +450,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
llvm::Value *imp = CGF.Builder.CreateCall(lookupFunction, lookupArgs,
lookupArgs+2);
- return CGF.EmitCall(FnInfo, imp, ActualArgs);
+ return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs);
}
/// Generate code for a message send expression.
@@ -536,7 +536,7 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
imp = Builder.CreateCall2(lookupFunction, Receiver, cmd);
}
- return CGF.EmitCall(FnInfo, imp, ActualArgs);
+ return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs);
}
/// Generates a MethodList. Used in construction of a objc_class and
@@ -1607,7 +1607,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
Params.push_back(PtrTy);
llvm::Value *RethrowFn =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- Params, false), "_Unwind_Resume_or_Rethrow");
+ Params, false), "objc_exception_throw");
bool isTry = isa<ObjCAtTryStmt>(S);
llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try");
@@ -1618,7 +1618,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::BasicBlock *FinallyRethrow = CGF.createBasicBlock("finally.throw");
llvm::BasicBlock *FinallyEnd = CGF.createBasicBlock("finally.end");
- // GNU runtime does not currently support @synchronized()
+ // @synchronized()
if (!isTry) {
std::vector<const llvm::Type*> Args(1, IdTy);
llvm::FunctionType *FTy =
@@ -1770,7 +1770,13 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
ESelArgs.clear();
ESelArgs.push_back(Exc);
ESelArgs.push_back(Personality);
- ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0));
+ // If there is a @catch or @finally clause in outside of this one then we
+ // need to make sure that we catch and rethrow it.
+ if (PrevLandingPad) {
+ ESelArgs.push_back(NULLPtr);
+ } else {
+ ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0));
+ }
CGF.Builder.CreateCall(llvm_eh_selector, ESelArgs.begin(), ESelArgs.end(),
"selector");
CGF.Builder.CreateCall(llvm_eh_typeid_for,
@@ -1811,11 +1817,23 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.EmitBranch(FinallyEnd);
CGF.EmitBlock(FinallyRethrow);
- CGF.Builder.CreateCall(RethrowFn, CGF.Builder.CreateLoad(RethrowPtr));
- CGF.Builder.CreateUnreachable();
- CGF.EmitBlock(FinallyEnd);
+ llvm::Value *ExceptionObject = CGF.Builder.CreateLoad(RethrowPtr);
+ llvm::BasicBlock *UnwindBB = CGF.getInvokeDest();
+ if (!UnwindBB) {
+ CGF.Builder.CreateCall(RethrowFn, ExceptionObject);
+ // Exception always thrown, next instruction is never reached.
+ CGF.Builder.CreateUnreachable();
+ } else {
+ // If there is a @catch block outside this scope, we invoke instead of
+ // calling because we may return to this function. This is very slow, but
+ // some people still do it. It would be nice to add an optimised path for
+ // this.
+ CGF.Builder.CreateInvoke(RethrowFn, UnwindBB, UnwindBB, &ExceptionObject,
+ &ExceptionObject+1);
+ }
+ CGF.EmitBlock(FinallyEnd);
}
void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index fb920f0..727746f 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -1581,7 +1581,7 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
assert(Fn && "EmitLegacyMessageSend - unknown API");
Fn = llvm::ConstantExpr::getBitCast(Fn,
llvm::PointerType::getUnqual(FTy));
- return CGF.EmitCall(FnInfo, Fn, ActualArgs);
+ return CGF.EmitCall(FnInfo, Fn, ReturnValueSlot(), ActualArgs);
}
llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder,
@@ -3351,7 +3351,6 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
SkipScanIvars.push_back(SkScan);
}
- bool BytesSkipped = false;
if (!SkipIvars.empty()) {
unsigned int LastIndex = SkipIvars.size()-1;
int LastByteSkipped =
@@ -3360,9 +3359,8 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
int LastByteScanned =
IvarsInfo[LastIndex].ivar_bytepos +
IvarsInfo[LastIndex].ivar_size * WordSize;
- BytesSkipped = (LastByteSkipped > LastByteScanned);
// Compute number of bytes to skip at the tail end of the last ivar scanned.
- if (BytesSkipped) {
+ if (LastByteSkipped > LastByteScanned) {
unsigned int TotalWords = (LastByteSkipped + (WordSize -1)) / WordSize;
SKIP_SCAN SkScan;
SkScan.skip = TotalWords - (LastByteScanned/WordSize);
@@ -3393,8 +3391,6 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
unsigned int skip_big = SkipScanIvars[i].skip / 0xf;
unsigned int scan_big = SkipScanIvars[i].scan / 0xf;
- if (skip_small > 0 || skip_big > 0)
- BytesSkipped = true;
// first skip big.
for (unsigned int ix = 0; ix < skip_big; ix++)
BitMap += (unsigned char)(0xf0);
@@ -5169,7 +5165,7 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo1, true);
Callee = CGF.Builder.CreateBitCast(Callee,
llvm::PointerType::getUnqual(FTy));
- return CGF.EmitCall(FnInfo1, Callee, ActualArgs);
+ return CGF.EmitCall(FnInfo1, Callee, ReturnValueSlot(), ActualArgs);
}
/// Generate code for a message send expression in the nonfragile abi.
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 02de00e..db6c507 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -21,76 +21,48 @@ namespace {
class RTTIBuilder {
CodeGenModule &CGM; // Per-module state.
llvm::LLVMContext &VMContext;
+
const llvm::Type *Int8PtrTy;
- llvm::SmallSet<const CXXRecordDecl *, 16> SeenVBase;
- llvm::SmallSet<const CXXRecordDecl *, 32> SeenBase;
-
- // Type info flags.
- enum {
- /// TI_Const - Type has const qualifier.
- TI_Const = 0x1,
-
- /// TI_Volatile - Type has volatile qualifier.
- TI_Volatile = 0x2,
-
- /// TI_Restrict - Type has restrict qualifier.
- TI_Restrict = 0x4,
-
- /// TI_Incomplete - Type is incomplete.
- TI_Incomplete = 0x8,
+
+ /// Fields - The fields of the RTTI descriptor currently being built.
+ llvm::SmallVector<llvm::Constant *, 16> Fields;
- /// TI_ContainingClassIncomplete - Containing class is incomplete.
- /// (in pointer to member).
- TI_ContainingClassIncomplete = 0x10
- };
+ /// GetAddrOfExternalRTTIDescriptor - Returns the constant for the RTTI
+ /// descriptor of the given type.
+ llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty);
+
+ /// BuildVtablePointer - Build the vtable pointer for the given type.
+ void BuildVtablePointer(const Type *Ty);
+
+ /// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
+ /// inheritance, according to the Itanium C++ ABI, 2.9.5p6b.
+ void BuildSIClassTypeInfo(const CXXRecordDecl *RD);
+
+ /// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
+ /// classes with bases that do not satisfy the abi::__si_class_type_info
+ /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
+ void BuildVMIClassTypeInfo(const CXXRecordDecl *RD);
+
+ /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, used
+ /// for pointer types.
+ void BuildPointerTypeInfo(const PointerType *Ty);
+
+ /// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
+ /// struct, used for member pointer types.
+ void BuildPointerToMemberTypeInfo(const MemberPointerType *Ty);
public:
RTTIBuilder(CodeGenModule &cgm)
: CGM(cgm), VMContext(cgm.getModule().getContext()),
Int8PtrTy(llvm::Type::getInt8PtrTy(VMContext)) { }
- /// BuildVtableRef - Build a reference to a vtable.
- llvm::Constant *BuildVtableRef(const char *Name) {
- // Build a descriptor for Name
- llvm::Constant *GV = CGM.getModule().getGlobalVariable(Name);
- if (GV)
- GV = llvm::ConstantExpr::getBitCast(GV,
- llvm::PointerType::get(Int8PtrTy, 0));
- else {
- llvm::GlobalVariable::LinkageTypes linktype;
- linktype = llvm::GlobalValue::ExternalLinkage;
- GV = new llvm::GlobalVariable(CGM.getModule(), Int8PtrTy,
- true, linktype, 0, Name);
- }
- llvm::Constant *C;
- C = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 2);
- C = llvm::ConstantExpr::getInBoundsGetElementPtr(GV, &C, 1);
- return llvm::ConstantExpr::getBitCast(C, Int8PtrTy);
- }
-
- // FIXME: This should be removed, and clients should pass in the linkage
- // directly instead.
- static inline llvm::GlobalVariable::LinkageTypes
- GetLinkageFromExternFlag(bool Extern) {
- if (Extern)
- return llvm::GlobalValue::WeakODRLinkage;
-
- return llvm::GlobalValue::InternalLinkage;
- }
-
- // FIXME: This should be removed, and clients should pass in the linkage
- // directly instead.
- llvm::Constant *BuildName(QualType Ty, bool Hidden, bool Extern) {
- return BuildName(Ty, Hidden, GetLinkageFromExternFlag(Extern));
- }
-
llvm::Constant *BuildName(QualType Ty, bool Hidden,
llvm::GlobalVariable::LinkageTypes Linkage) {
llvm::SmallString<256> OutName;
CGM.getMangleContext().mangleCXXRTTIName(Ty, OutName);
llvm::StringRef Name = OutName.str();
- llvm::GlobalVariable *OGV = CGM.getModule().getGlobalVariable(Name);
+ llvm::GlobalVariable *OGV = CGM.getModule().getNamedGlobal(Name);
if (OGV && !OGV->isDeclaration())
return llvm::ConstantExpr::getBitCast(OGV, Int8PtrTy);
@@ -109,397 +81,789 @@ public:
if (Hidden)
GV->setVisibility(llvm::GlobalVariable::HiddenVisibility);
return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
- };
-
- /// - BuildFlags - Build a psABI __flags value for __vmi_class_type_info.
- llvm::Constant *BuildFlags(int f) {
- return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), f);
}
- /// BuildBaseCount - Build a psABI __base_count value for
- /// __vmi_class_type_info.
- llvm::Constant *BuildBaseCount(unsigned c) {
- return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), c);
+ // FIXME: unify with DecideExtern
+ bool DecideHidden(QualType Ty) {
+ // For this type, see if all components are never hidden.
+ if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>())
+ return (DecideHidden(MPT->getPointeeType())
+ && DecideHidden(QualType(MPT->getClass(), 0)));
+ if (const PointerType *PT = Ty->getAs<PointerType>())
+ return DecideHidden(PT->getPointeeType());
+ if (const FunctionType *FT = Ty->getAs<FunctionType>()) {
+ if (DecideHidden(FT->getResultType()) == false)
+ return false;
+ if (const FunctionProtoType *FPT = Ty->getAs<FunctionProtoType>()) {
+ for (unsigned i = 0; i <FPT->getNumArgs(); ++i)
+ if (DecideHidden(FPT->getArgType(i)) == false)
+ return false;
+ for (unsigned i = 0; i <FPT->getNumExceptions(); ++i)
+ if (DecideHidden(FPT->getExceptionType(i)) == false)
+ return false;
+ return true;
+ }
+ }
+ if (const RecordType *RT = Ty->getAs<RecordType>())
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
+ return CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden;
+ return false;
}
+
+ // Pointer type info flags.
+ enum {
+ /// PTI_Const - Type has const qualifier.
+ PTI_Const = 0x1,
+
+ /// PTI_Volatile - Type has volatile qualifier.
+ PTI_Volatile = 0x2,
+
+ /// PTI_Restrict - Type has restrict qualifier.
+ PTI_Restrict = 0x4,
+
+ /// PTI_Incomplete - Type is incomplete.
+ PTI_Incomplete = 0x8,
+
+ /// PTI_ContainingClassIncomplete - Containing class is incomplete.
+ /// (in pointer to member).
+ PTI_ContainingClassIncomplete = 0x10
+ };
+
+ // VMI type info flags.
+ enum {
+ /// VMI_NonDiamondRepeat - Class has non-diamond repeated inheritance.
+ VMI_NonDiamondRepeat = 0x1,
+
+ /// VMI_DiamondShaped - Class is diamond shaped.
+ VMI_DiamondShaped = 0x2
+ };
+
+ // Base class type info flags.
+ enum {
+ /// BCTI_Virtual - Base class is virtual.
+ BCTI_Virtual = 0x1,
+
+ /// BCTI_Public - Base class is public.
+ BCTI_Public = 0x2
+ };
+
+ /// BuildTypeInfo - Build the RTTI type info struct for the given type.
+ llvm::Constant *BuildTypeInfo(QualType Ty);
+};
+}
- llvm::Constant *BuildTypeRef(QualType Ty) {
- llvm::Constant *C;
-
- llvm::SmallString<256> OutName;
- CGM.getMangleContext().mangleCXXRTTI(Ty, OutName);
- llvm::StringRef Name = OutName.str();
-
- C = CGM.getModule().getGlobalVariable(Name);
- if (C)
- return llvm::ConstantExpr::getBitCast(C, Int8PtrTy);
-
- llvm::GlobalVariable::LinkageTypes linktype;
- linktype = llvm::GlobalValue::ExternalLinkage;;
+llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
+ // Mangle the RTTI name.
+ llvm::SmallString<256> OutName;
+ CGM.getMangleContext().mangleCXXRTTI(Ty, OutName);
+ llvm::StringRef Name = OutName.str();
- C = new llvm::GlobalVariable(CGM.getModule(), Int8PtrTy, true, linktype,
- 0, Name);
- return llvm::ConstantExpr::getBitCast(C, Int8PtrTy);
+ // Look for an existing global.
+ llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name);
+
+ if (!GV) {
+ // Create a new global variable.
+ GV = new llvm::GlobalVariable(CGM.getModule(), Int8PtrTy, /*Constant=*/true,
+ llvm::GlobalValue::ExternalLinkage, 0, Name);
}
+
+ return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+}
- llvm::Constant *Buildclass_type_infoRef(const CXXRecordDecl *RD) {
- return BuildTypeRef(CGM.getContext().getTagDeclType(RD));
- }
+/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type
+/// info for that type is defined in the standard library.
+static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
+ // Itanium C++ ABI 2.9.2:
+ // Basic type information (e.g. for "int", "bool", etc.) will be kept in
+ // the run-time support library. Specifically, the run-time support
+ // library should contain type_info objects for the types X, X* and
+ // X const*, for every X in: void, bool, wchar_t, char, unsigned char,
+ // signed char, short, unsigned short, int, unsigned int, long,
+ // unsigned long, long long, unsigned long long, float, double, long double,
+ // char16_t, char32_t, and the IEEE 754r decimal and half-precision
+ // floating point types.
+ switch (Ty->getKind()) {
+ case BuiltinType::Void:
+ case BuiltinType::Bool:
+ case BuiltinType::WChar:
+ case BuiltinType::Char_U:
+ case BuiltinType::Char_S:
+ case BuiltinType::UChar:
+ case BuiltinType::SChar:
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ case BuiltinType::Long:
+ case BuiltinType::ULong:
+ case BuiltinType::LongLong:
+ case BuiltinType::ULongLong:
+ case BuiltinType::Float:
+ case BuiltinType::Double:
+ case BuiltinType::LongDouble:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::Int128:
+ case BuiltinType::UInt128:
+ return true;
+
+ case BuiltinType::Overload:
+ case BuiltinType::Dependent:
+ case BuiltinType::UndeducedAuto:
+ assert(false && "Should not see this type here!");
+
+ case BuiltinType::NullPtr:
+ assert(false && "FIXME: nullptr_t is not handled!");
- /// CalculateFlags - Calculate the flags for the __vmi_class_type_info
- /// datastructure. 1 for non-diamond repeated inheritance, 2 for a dimond
- /// shaped class.
- int CalculateFlags(const CXXRecordDecl*RD) {
- int flags = 0;
- if (SeenBase.count(RD))
- flags |= 1;
- else
- SeenBase.insert(RD);
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (i->isVirtual()) {
- if (SeenVBase.count(Base))
- flags |= 2;
- else
- SeenVBase.insert(Base);
- }
- flags |= CalculateFlags(Base);
- }
- return flags;
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ assert(false && "FIXME: Objective-C types are unsupported!");
}
+
+ // Silent gcc.
+ return false;
+}
- bool SimpleInheritance(const CXXRecordDecl *RD) {
- if (RD->getNumBases() != 1)
- return false;
- CXXRecordDecl::base_class_const_iterator i = RD->bases_begin();
- if (i->isVirtual())
- return false;
- if (i->getAccessSpecifier() != AS_public)
- return false;
+static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) {
+ QualType PointeeTy = PointerTy->getPointeeType();
+ const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(PointeeTy);
+ if (!BuiltinTy)
+ return false;
+
+ // Check the qualifiers.
+ Qualifiers Quals = PointeeTy.getQualifiers();
+ Quals.removeConst();
+
+ if (!Quals.empty())
+ return false;
+
+ return TypeInfoIsInStandardLibrary(BuiltinTy);
+}
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (Layout.getBaseClassOffset(Base) != 0)
+/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
+/// the given type exists somewhere else, and that we should not emit the typ
+/// information in this translation unit.
+bool ShouldUseExternalRTTIDescriptor(QualType Ty) {
+ // Type info for builtin types is defined in the standard library.
+ if (const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Ty))
+ return TypeInfoIsInStandardLibrary(BuiltinTy);
+
+ // Type info for some pointer types to builtin types is defined in the
+ // standard library.
+ if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
+ return TypeInfoIsInStandardLibrary(PointerTy);
+
+ if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (!RD->isDynamicClass())
return false;
- return true;
- }
- llvm::Constant *finish(llvm::Constant *const *Values, unsigned NumValues,
- llvm::GlobalVariable *GV,
- llvm::StringRef Name, bool Hidden,
- llvm::GlobalVariable::LinkageTypes Linkage) {
- llvm::Constant *C =
- llvm::ConstantStruct::get(VMContext, Values, NumValues, /*Packed=*/false);
-
- llvm::GlobalVariable *OGV = GV;
- GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, Linkage,
- C, Name);
- if (OGV) {
- GV->takeName(OGV);
- llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV,
- OGV->getType());
- OGV->replaceAllUsesWith(NewPtr);
- OGV->eraseFromParent();
+ // Get the key function.
+ const CXXMethodDecl *KeyFunction = RD->getASTContext().getKeyFunction(RD);
+ if (KeyFunction && !KeyFunction->getBody()) {
+ // The class has a key function, but it is not defined in this translation
+ // unit, so we should use the external descriptor for it.
+ return true;
}
- if (Hidden)
- GV->setVisibility(llvm::GlobalVariable::HiddenVisibility);
- return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
}
+
+ return false;
+}
+/// IsIncompleteClassType - Returns whether the given record type is incomplete.
+static bool IsIncompleteClassType(const RecordType *RecordTy) {
+ return !RecordTy->getDecl()->isDefinition();
+}
+
+/// ContainsIncompleteClassType - Returns whether the given type contains an
+/// incomplete class type. This is true if
+///
+/// * The given type is an incomplete class type.
+/// * The given type is a pointer type whose pointee type contains an
+/// incomplete class type.
+/// * The given type is a member pointer type whose class is an incomplete
+/// class type.
+/// * The given type is a member pointer type whoise pointee type contains an
+/// incomplete class type.
+/// is an indirect or direct pointer to an incomplete class type.
+static bool ContainsIncompleteClassType(QualType Ty) {
+ if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
+ if (IsIncompleteClassType(RecordTy))
+ return true;
+ }
+
+ if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
+ return ContainsIncompleteClassType(PointerTy->getPointeeType());
+
+ if (const MemberPointerType *MemberPointerTy =
+ dyn_cast<MemberPointerType>(Ty)) {
+ // Check if the class type is incomplete.
+ const RecordType *ClassType = cast<RecordType>(MemberPointerTy->getClass());
+ if (IsIncompleteClassType(ClassType))
+ return true;
+
+ return ContainsIncompleteClassType(MemberPointerTy->getPointeeType());
+ }
+
+ return false;
+}
- llvm::Constant *
- Buildclass_type_info(const CXXRecordDecl *RD,
- llvm::GlobalVariable::LinkageTypes Linkage) {
- std::vector<llvm::Constant *> info;
- assert(info.empty() && "Info vector must be empty!");
+/// getTypeInfoLinkage - Return the linkage that the type info and type info
+/// name constants should have for the given type.
+static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(QualType Ty) {
+ // Itanium C++ ABI 2.9.5p7:
+ // In addition, it and all of the intermediate abi::__pointer_type_info
+ // structs in the chain down to the abi::__class_type_info for the
+ // incomplete class type must be prevented from resolving to the
+ // corresponding type_info structs for the complete class type, possibly
+ // by making them local static objects. Finally, a dummy class RTTI is
+ // generated for the incomplete type that will not resolve to the final
+ // complete class RTTI (because the latter need not exist), possibly by
+ // making it a local static object.
+ if (ContainsIncompleteClassType(Ty))
+ return llvm::GlobalValue::InternalLinkage;
+
+ switch (Ty->getTypeClass()) {
+ default:
+ // FIXME: We need to add code to handle all types.
+ assert(false && "Unhandled type!");
+ break;
+
+ case Type::Pointer: {
+ const PointerType *PointerTy = cast<PointerType>(Ty);
+
+ // If the pointee type has internal linkage, then the pointer type needs to
+ // have it as well.
+ if (getTypeInfoLinkage(PointerTy->getPointeeType()) ==
+ llvm::GlobalVariable::InternalLinkage)
+ return llvm::GlobalVariable::InternalLinkage;
- llvm::Constant *C;
+ return llvm::GlobalVariable::WeakODRLinkage;
+ }
- llvm::SmallString<256> OutName;
- CGM.getMangleContext().mangleCXXRTTI(CGM.getContext().getTagDeclType(RD),
- OutName);
- llvm::StringRef Name = OutName.str();
+ case Type::Enum: {
+ const EnumType *EnumTy = cast<EnumType>(Ty);
+ const EnumDecl *ED = EnumTy->getDecl();
+
+ // If we're in an anonymous namespace, then we always want internal linkage.
+ if (ED->isInAnonymousNamespace() || !ED->hasLinkage())
+ return llvm::GlobalVariable::InternalLinkage;
+
+ return llvm::GlobalValue::WeakODRLinkage;
+ }
- llvm::GlobalVariable *GV;
- GV = CGM.getModule().getGlobalVariable(Name);
- if (GV && !GV->isDeclaration())
- return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+ case Type::Record: {
+ const RecordType *RecordTy = cast<RecordType>(Ty);
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
// If we're in an anonymous namespace, then we always want internal linkage.
if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
- Linkage = llvm::GlobalVariable::InternalLinkage;
+ return llvm::GlobalVariable::InternalLinkage;
- bool Hidden = CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden;
-
- bool simple = false;
- if (RD->getNumBases() == 0)
- C = BuildVtableRef("_ZTVN10__cxxabiv117__class_type_infoE");
- else if (SimpleInheritance(RD)) {
- simple = true;
- C = BuildVtableRef("_ZTVN10__cxxabiv120__si_class_type_infoE");
- } else
- C = BuildVtableRef("_ZTVN10__cxxabiv121__vmi_class_type_infoE");
- info.push_back(C);
- info.push_back(BuildName(CGM.getContext().getTagDeclType(RD), Hidden,
- Linkage));
-
- // If we have no bases, there are no more fields.
- if (RD->getNumBases()) {
- if (!simple) {
- info.push_back(BuildFlags(CalculateFlags(RD)));
- info.push_back(BuildBaseCount(RD->getNumBases()));
- }
-
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- info.push_back(CGM.GetAddrOfRTTI(Base));
- if (simple)
- break;
- int64_t offset;
- if (!i->isVirtual())
- offset = Layout.getBaseClassOffset(Base)/8;
- else
- offset = CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, Base);
- offset <<= 8;
- // Now set the flags.
- offset += i->isVirtual() ? 1 : 0;;
- offset += i->getAccessSpecifier() == AS_public ? 2 : 0;
- const llvm::Type *LongTy =
- CGM.getTypes().ConvertType(CGM.getContext().LongTy);
- C = llvm::ConstantInt::get(LongTy, offset);
- info.push_back(C);
- }
+ if (!RD->isDynamicClass())
+ return llvm::GlobalValue::WeakODRLinkage;
+
+ // Get the key function.
+ const CXXMethodDecl *KeyFunction = RD->getASTContext().getKeyFunction(RD);
+ if (!KeyFunction) {
+ // There is no key function, the RTTI descriptor is emitted with weak_odr
+ // linkage.
+ return llvm::GlobalValue::WeakODRLinkage;
}
- return finish(&info[0], info.size(), GV, Name, Hidden, Linkage);
- }
+ // If the key function is defined, but inlined, then the RTTI descriptor is
+ // emitted with weak_odr linkage.
+ const FunctionDecl* KeyFunctionDefinition;
+ KeyFunction->getBody(KeyFunctionDefinition);
- /// - BuildFlags - Build a __flags value for __pbase_type_info.
- llvm::Constant *BuildInt(unsigned n) {
- return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), n);
+ if (KeyFunctionDefinition->isInlined())
+ return llvm::GlobalValue::WeakODRLinkage;
+
+ // Otherwise, the RTTI descriptor is emitted with external linkage.
+ return llvm::GlobalValue::ExternalLinkage;
}
- bool DecideExtern(QualType Ty) {
- // For this type, see if all components are never in an anonymous namespace.
- if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>())
- return (DecideExtern(MPT->getPointeeType())
- && DecideExtern(QualType(MPT->getClass(), 0)));
- if (const PointerType *PT = Ty->getAs<PointerType>())
- return DecideExtern(PT->getPointeeType());
- if (const RecordType *RT = Ty->getAs<RecordType>())
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
- return !RD->isInAnonymousNamespace() && RD->hasLinkage();
- return true;
- }
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::Builtin:
+ return llvm::GlobalValue::WeakODRLinkage;
- bool DecideHidden(QualType Ty) {
- // For this type, see if all components are never hidden.
- if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>())
- return (DecideHidden(MPT->getPointeeType())
- && DecideHidden(QualType(MPT->getClass(), 0)));
- if (const PointerType *PT = Ty->getAs<PointerType>())
- return DecideHidden(PT->getPointeeType());
- if (const RecordType *RT = Ty->getAs<RecordType>())
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
- return CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden;
- return false;
- }
+ case Type::FunctionProto: {
+ const FunctionProtoType *FPT = cast<FunctionProtoType>(Ty);
- llvm::Constant *BuildPointerType(QualType Ty) {
- std::vector<llvm::Constant *> info;
- assert(info.empty() && "Info vector must be empty!");
+ // Check the return type.
+ if (getTypeInfoLinkage(FPT->getResultType()) ==
+ llvm::GlobalValue::InternalLinkage)
+ return llvm::GlobalValue::InternalLinkage;
+
+ // Check the parameter types.
+ for (unsigned i = 0; i != FPT->getNumArgs(); ++i) {
+ if (getTypeInfoLinkage(FPT->getArgType(i)) ==
+ llvm::GlobalValue::InternalLinkage)
+ return llvm::GlobalValue::InternalLinkage;
+ }
- llvm::Constant *C;
+ return llvm::GlobalValue::WeakODRLinkage;
+ }
+
+ case Type::ConstantArray:
+ case Type::IncompleteArray: {
+ const ArrayType *AT = cast<ArrayType>(Ty);
+
+ // Check the element type.
+ if (getTypeInfoLinkage(AT->getElementType()) ==
+ llvm::GlobalValue::InternalLinkage)
+ return llvm::GlobalValue::InternalLinkage;
+ }
- llvm::SmallString<256> OutName;
- CGM.getMangleContext().mangleCXXRTTI(Ty, OutName);
- llvm::StringRef Name = OutName.str();
+ }
- llvm::GlobalVariable *GV;
- GV = CGM.getModule().getGlobalVariable(Name);
- if (GV && !GV->isDeclaration())
- return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+ return llvm::GlobalValue::WeakODRLinkage;
+}
- bool Extern = DecideExtern(Ty);
- bool Hidden = DecideHidden(Ty);
+// CanUseSingleInheritance - Return whether the given record decl has a "single,
+// public, non-virtual base at offset zero (i.e. the derived class is dynamic
+// iff the base is)", according to Itanium C++ ABI, 2.95p6b.
+static bool CanUseSingleInheritance(const CXXRecordDecl *RD) {
+ // Check the number of bases.
+ if (RD->getNumBases() != 1)
+ return false;
+
+ // Get the base.
+ CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin();
+
+ // Check that the base is not virtual.
+ if (Base->isVirtual())
+ return false;
+
+ // Check that the base is public.
+ if (Base->getAccessSpecifier() != AS_public)
+ return false;
+
+ // Check that the class is dynamic iff the base is.
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (!BaseDecl->isEmpty() &&
+ BaseDecl->isDynamicClass() != RD->isDynamicClass())
+ return false;
+
+ return true;
+}
- const MemberPointerType *PtrMemTy = dyn_cast<MemberPointerType>(Ty);
- QualType PointeeTy;
-
- if (PtrMemTy)
- PointeeTy = PtrMemTy->getPointeeType();
- else
- PointeeTy = Ty->getPointeeType();
-
- if (PtrMemTy)
- C = BuildVtableRef("_ZTVN10__cxxabiv129__pointer_to_member_type_infoE");
- else
- C = BuildVtableRef("_ZTVN10__cxxabiv119__pointer_type_infoE");
-
- info.push_back(C);
- info.push_back(BuildName(Ty, Hidden, Extern));
- Qualifiers Q = PointeeTy.getQualifiers();
-
- PointeeTy =
- CGM.getContext().getCanonicalType(PointeeTy).getUnqualifiedType();
-
- unsigned Flags = 0;
- if (Q.hasConst())
- Flags |= TI_Const;
- if (Q.hasVolatile())
- Flags |= TI_Volatile;
- if (Q.hasRestrict())
- Flags |= TI_Restrict;
+void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
+ const char *VtableName;
+
+ switch (Ty->getTypeClass()) {
+ default: assert(0 && "Unhandled type!");
+
+ // GCC treats vector types as fundamental types.
+ case Type::Vector:
+ case Type::ExtVector:
+ // abi::__fundamental_type_info.
+ VtableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE";
+ break;
+
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ // abi::__array_type_info.
+ VtableName = "_ZTVN10__cxxabiv117__array_type_infoE";
+ break;
+
+ case Type::FunctionNoProto:
+ case Type::FunctionProto:
+ // abi::__function_type_info.
+ VtableName = "_ZTVN10__cxxabiv120__function_type_infoE";
+ break;
+
+ case Type::Enum:
+ // abi::__enum_type_info.
+ VtableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
+ break;
+
+ case Type::Record: {
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
- if (Ty->isIncompleteType())
- Flags |= TI_Incomplete;
-
- if (PtrMemTy && PtrMemTy->getClass()->isIncompleteType())
- Flags |= TI_ContainingClassIncomplete;
+ if (!RD->getNumBases()) {
+ // abi::__class_type_info.
+ VtableName = "_ZTVN10__cxxabiv117__class_type_infoE";
+ } else if (CanUseSingleInheritance(RD)) {
+ // abi::__si_class_type_info.
+ VtableName = "_ZTVN10__cxxabiv120__si_class_type_infoE";
+ } else {
+ // abi::__vmi_class_type_info.
+ VtableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
+ }
- info.push_back(BuildInt(Flags));
- info.push_back(BuildInt(0));
- info.push_back(BuildType(PointeeTy));
+ break;
+ }
- if (PtrMemTy)
- info.push_back(BuildType(QualType(PtrMemTy->getClass(), 0)));
+ case Type::Pointer:
+ // abi::__pointer_type_info.
+ VtableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
+ break;
- // We always generate these as hidden, only the name isn't hidden.
- return finish(&info[0], info.size(), GV, Name, /*Hidden=*/true,
- GetLinkageFromExternFlag(Extern));
+ case Type::MemberPointer:
+ // abi::__pointer_to_member_type_info.
+ VtableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
+ break;
}
- llvm::Constant *BuildSimpleType(QualType Ty, const char *vtbl) {
- llvm::SmallString<256> OutName;
- CGM.getMangleContext().mangleCXXRTTI(Ty, OutName);
- llvm::StringRef Name = OutName.str();
+ llvm::Constant *Vtable =
+ CGM.getModule().getOrInsertGlobal(VtableName, Int8PtrTy);
+
+ const llvm::Type *PtrDiffTy =
+ CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
+
+ // The vtable address point is 2.
+ llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2);
+ Vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, &Two, 1);
+ Vtable = llvm::ConstantExpr::getBitCast(Vtable, Int8PtrTy);
- llvm::GlobalVariable *GV;
- GV = CGM.getModule().getGlobalVariable(Name);
- if (GV && !GV->isDeclaration())
- return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+ Fields.push_back(Vtable);
+}
- bool Extern = DecideExtern(Ty);
- bool Hidden = DecideHidden(Ty);
+llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) {
+ // We want to operate on the canonical type.
+ Ty = CGM.getContext().getCanonicalType(Ty);
- llvm::Constant *Info[] = {
- BuildVtableRef(vtbl), BuildName(Ty, Hidden, Extern)
- };
+ // Check if we've already emitted an RTTI descriptor for this type.
+ llvm::SmallString<256> OutName;
+ CGM.getMangleContext().mangleCXXRTTI(Ty, OutName);
+ llvm::StringRef Name = OutName.str();
+
+ llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name);
+ if (OldGV && !OldGV->isDeclaration())
+ return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy);
+
+ // Check if there is already an external RTTI descriptor for this type.
+ if (ShouldUseExternalRTTIDescriptor(Ty))
+ return GetAddrOfExternalRTTIDescriptor(Ty);
+
+ llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(Ty);
+
+ // Add the vtable pointer.
+ BuildVtablePointer(cast<Type>(Ty));
+
+ // And the name.
+ Fields.push_back(BuildName(Ty, DecideHidden(Ty), Linkage));
+
+ switch (Ty->getTypeClass()) {
+ default: assert(false && "Unhandled type class!");
+ case Type::Builtin:
+ assert(false && "Builtin type info must be in the standard library!");
+ break;
+
+ // GCC treats vector types as fundamental types.
+ case Type::Vector:
+ case Type::ExtVector:
+ // Itanium C++ ABI 2.9.5p4:
+ // abi::__fundamental_type_info adds no data members to std::type_info.
+ break;
+
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ // Itanium C++ ABI 2.9.5p5:
+ // abi::__array_type_info adds no data members to std::type_info.
+ break;
+
+ case Type::FunctionNoProto:
+ case Type::FunctionProto:
+ // Itanium C++ ABI 2.9.5p5:
+ // abi::__function_type_info adds no data members to std::type_info.
+ break;
+
+ case Type::Enum:
+ // Itanium C++ ABI 2.9.5p5:
+ // abi::__enum_type_info adds no data members to std::type_info.
+ break;
+
+ case Type::Record: {
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
+ if (!RD->getNumBases()) {
+ // We don't need to emit any fields.
+ break;
+ }
- // We always generate these as hidden, only the name isn't hidden.
- return finish(&Info[0], llvm::array_lengthof(Info), GV, Name,
- /*Hidden=*/true, GetLinkageFromExternFlag(Extern));
+ if (CanUseSingleInheritance(RD))
+ BuildSIClassTypeInfo(RD);
+ else
+ BuildVMIClassTypeInfo(RD);
+
+ break;
+ }
+
+ case Type::Pointer:
+ BuildPointerTypeInfo(cast<PointerType>(Ty));
+ break;
+
+ case Type::MemberPointer:
+ BuildPointerToMemberTypeInfo(cast<MemberPointerType>(Ty));
+ break;
}
- /// BuildType - Builds the type info for the given type.
- llvm::Constant *BuildType(QualType Ty) {
- const clang::Type &Type
- = *CGM.getContext().getCanonicalType(Ty).getTypePtr();
+ llvm::Constant *Init =
+ llvm::ConstantStruct::get(VMContext, &Fields[0], Fields.size(),
+ /*Packed=*/false);
- if (const RecordType *RT = Ty.getTypePtr()->getAs<RecordType>())
- if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()))
- return BuildClassTypeInfo(RD);
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
+ /*Constant=*/true, Linkage, Init, Name);
+
+ // If there's already an old global variable, replace it with the new one.
+ if (OldGV) {
+ GV->takeName(OldGV);
+ llvm::Constant *NewPtr =
+ llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
+ OldGV->replaceAllUsesWith(NewPtr);
+ OldGV->eraseFromParent();
+ }
+
+ return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+}
- switch (Type.getTypeClass()) {
- default: {
- assert(0 && "typeid expression");
- return llvm::Constant::getNullValue(Int8PtrTy);
- }
+/// ComputeQualifierFlags - Compute the pointer type info flags from the
+/// given qualifier.
+static unsigned ComputeQualifierFlags(Qualifiers Quals) {
+ unsigned Flags = 0;
- case Type::Builtin: {
- // We expect all type_info objects for builtin types to be in the library.
- return BuildTypeRef(Ty);
- }
+ if (Quals.hasConst())
+ Flags |= RTTIBuilder::PTI_Const;
+ if (Quals.hasVolatile())
+ Flags |= RTTIBuilder::PTI_Volatile;
+ if (Quals.hasRestrict())
+ Flags |= RTTIBuilder::PTI_Restrict;
+
+ return Flags;
+}
- case Type::Pointer: {
- QualType PTy = Ty->getPointeeType();
- Qualifiers Q = PTy.getQualifiers();
- Q.removeConst();
- // T* and const T* for all builtin types T are expected in the library.
- if (isa<BuiltinType>(PTy) && Q.empty())
- return BuildTypeRef(Ty);
+/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
+/// inheritance, according to the Itanium C++ ABI, 2.95p6b.
+void RTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) {
+ // Itanium C++ ABI 2.9.5p6b:
+ // It adds to abi::__class_type_info a single member pointing to the
+ // type_info structure for the base type,
+ llvm::Constant *BaseTypeInfo =
+ RTTIBuilder(CGM).BuildTypeInfo(RD->bases_begin()->getType());
+ Fields.push_back(BaseTypeInfo);
+}
+
+/// SeenBases - Contains virtual and non-virtual bases seen when traversing
+/// a class hierarchy.
+struct SeenBases {
+ llvm::SmallPtrSet<const CXXRecordDecl *, 16> NonVirtualBases;
+ llvm::SmallPtrSet<const CXXRecordDecl *, 16> VirtualBases;
+};
- return BuildPointerType(Ty);
+/// ComputeVMIClassTypeInfoFlags - Compute the value of the flags member in
+/// abi::__vmi_class_type_info.
+///
+static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
+ SeenBases &Bases) {
+
+ unsigned Flags = 0;
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+
+ if (Base->isVirtual()) {
+ if (Bases.VirtualBases.count(BaseDecl)) {
+ // If this virtual base has been seen before, then the class is diamond
+ // shaped.
+ Flags |= RTTIBuilder::VMI_DiamondShaped;
+ } else {
+ if (Bases.NonVirtualBases.count(BaseDecl))
+ Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
+
+ // Mark the virtual base as seen.
+ Bases.VirtualBases.insert(BaseDecl);
}
- case Type::MemberPointer:
- return BuildPointerType(Ty);
- case Type::FunctionProto:
- case Type::FunctionNoProto:
- return BuildSimpleType(Ty, "_ZTVN10__cxxabiv120__function_type_infoE");
- case Type::ConstantArray:
- case Type::IncompleteArray:
- case Type::VariableArray:
- case Type::Vector:
- case Type::ExtVector:
- return BuildSimpleType(Ty, "_ZTVN10__cxxabiv117__array_type_infoE");
- case Type::Enum:
- return BuildSimpleType(Ty, "_ZTVN10__cxxabiv116__enum_type_infoE");
+ } else {
+ if (Bases.NonVirtualBases.count(BaseDecl)) {
+ // If this non-virtual base has been seen before, then the class has non-
+ // diamond shaped repeated inheritance.
+ Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
+ } else {
+ if (Bases.VirtualBases.count(BaseDecl))
+ Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
+
+ // Mark the non-virtual base as seen.
+ Bases.NonVirtualBases.insert(BaseDecl);
}
}
+
+ // Walk all bases.
+ for (CXXRecordDecl::base_class_const_iterator I = BaseDecl->bases_begin(),
+ E = BaseDecl->bases_end(); I != E; ++I)
+ Flags |= ComputeVMIClassTypeInfoFlags(I, Bases);
- /// BuildClassTypeInfo - Builds the class type info (or a reference to it)
- /// for the given record decl.
- llvm::Constant *BuildClassTypeInfo(const CXXRecordDecl *RD) {
- const CXXMethodDecl *KeyFunction = 0;
+ return Flags;
+}
- if (RD->isDynamicClass())
- KeyFunction = CGM.getContext().getKeyFunction(RD);
+static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) {
+ unsigned Flags = 0;
+ SeenBases Bases;
+
+ // Walk all bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I)
+ Flags |= ComputeVMIClassTypeInfoFlags(I, Bases);
+
+ return Flags;
+}
+
+/// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
+/// classes with bases that do not satisfy the abi::__si_class_type_info
+/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
+void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
+ const llvm::Type *UnsignedIntLTy =
+ CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
+
+ // Itanium C++ ABI 2.9.5p6c:
+ // __flags is a word with flags describing details about the class
+ // structure, which may be referenced by using the __flags_masks
+ // enumeration. These flags refer to both direct and indirect bases.
+ unsigned Flags = ComputeVMIClassTypeInfoFlags(RD);
+ Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
+
+ // Itanium C++ ABI 2.9.5p6c:
+ // __base_count is a word with the number of direct proper base class
+ // descriptions that follow.
+ Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, RD->getNumBases()));
+
+ if (!RD->getNumBases())
+ return;
+
+ const llvm::Type *LongLTy =
+ CGM.getTypes().ConvertType(CGM.getContext().LongTy);
+
+ // Now add the base class descriptions.
+
+ // Itanium C++ ABI 2.9.5p6c:
+ // __base_info[] is an array of base class descriptions -- one for every
+ // direct proper base. Each description is of the type:
+ //
+ // struct abi::__base_class_type_info {
+ // public:
+ // const __class_type_info *__base_type;
+ // long __offset_flags;
+ //
+ // enum __offset_flags_masks {
+ // __virtual_mask = 0x1,
+ // __public_mask = 0x2,
+ // __offset_shift = 8
+ // };
+ // };
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXBaseSpecifier *Base = I;
+
+ // The __base_type member points to the RTTI for the base type.
+ Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(Base->getType()));
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+
+ int64_t OffsetFlags = 0;
- if (KeyFunction) {
- // If the key function is defined in this translation unit, then the RTTI
- // related constants should also be emitted here, with external linkage.
- if (KeyFunction->getBody())
- return Buildclass_type_info(RD, llvm::GlobalValue::ExternalLinkage);
-
- // Otherwise, we just want a reference to the type info.
- return Buildclass_type_infoRef(RD);
- }
+ // All but the lower 8 bits of __offset_flags are a signed offset.
+ // For a non-virtual base, this is the offset in the object of the base
+ // subobject. For a virtual base, this is the offset in the virtual table of
+ // the virtual base offset for the virtual base referenced (negative).
+ if (Base->isVirtual())
+ OffsetFlags = CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, BaseDecl);
+ else {
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ OffsetFlags = Layout.getBaseClassOffset(BaseDecl) / 8;
+ };
+
+ OffsetFlags <<= 8;
- // If there is no key function (or if the record doesn't have any virtual
- // member functions or virtual bases), emit the type info with weak_odr
- // linkage.
- return Buildclass_type_info(RD, llvm::GlobalValue::WeakODRLinkage);
+ // The low-order byte of __offset_flags contains flags, as given by the
+ // masks from the enumeration __offset_flags_masks.
+ if (Base->isVirtual())
+ OffsetFlags |= BCTI_Virtual;
+ if (Base->getAccessSpecifier() == AS_public)
+ OffsetFlags |= BCTI_Public;
+
+ Fields.push_back(llvm::ConstantInt::get(LongLTy, OffsetFlags));
}
-};
}
-llvm::Constant *CodeGenModule::GetAddrOfRTTI(const CXXRecordDecl *RD) {
- if (!getContext().getLangOptions().RTTI) {
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
- return llvm::Constant::getNullValue(Int8PtrTy);
- }
+/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct,
+/// used for pointer types.
+void RTTIBuilder::BuildPointerTypeInfo(const PointerType *Ty) {
+ QualType PointeeTy = Ty->getPointeeType();
- return RTTIBuilder(*this).BuildClassTypeInfo(RD);
-}
-
-llvm::Constant *CodeGenModule::GetAddrOfRTTI(QualType Ty) {
- if (!getContext().getLangOptions().RTTI) {
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
- return llvm::Constant::getNullValue(Int8PtrTy);
- }
+ // Itanium C++ ABI 2.9.5p7:
+ // __flags is a flag word describing the cv-qualification and other
+ // attributes of the type pointed to
+ unsigned Flags = ComputeQualifierFlags(PointeeTy.getQualifiers());
+
+ // Itanium C++ ABI 2.9.5p7:
+ // When the abi::__pbase_type_info is for a direct or indirect pointer to an
+ // incomplete class type, the incomplete target type flag is set.
+ if (ContainsIncompleteClassType(PointeeTy))
+ Flags |= PTI_Incomplete;
+
+ const llvm::Type *UnsignedIntLTy =
+ CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
+ Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
- return RTTIBuilder(*this).BuildType(Ty);
+ // Itanium C++ ABI 2.9.5p7:
+ // __pointee is a pointer to the std::type_info derivation for the
+ // unqualified type being pointed to.
+ llvm::Constant *PointeeTypeInfo =
+ RTTIBuilder(CGM).BuildTypeInfo(PointeeTy.getUnqualifiedType());
+ Fields.push_back(PointeeTypeInfo);
}
-llvm::Constant *CodeGenModule::GenerateRTTIRef(const CXXRecordDecl *RD) {
- RTTIBuilder b(*this);
+/// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
+/// struct, used for member pointer types.
+void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {
+ QualType PointeeTy = Ty->getPointeeType();
+
+ // Itanium C++ ABI 2.9.5p7:
+ // __flags is a flag word describing the cv-qualification and other
+ // attributes of the type pointed to.
+ unsigned Flags = ComputeQualifierFlags(PointeeTy.getQualifiers());
- return b.Buildclass_type_infoRef(RD);
-}
+ const RecordType *ClassType = cast<RecordType>(Ty->getClass());
-llvm::Constant *CodeGenModule::GenerateRTTI(const CXXRecordDecl *RD) {
- RTTIBuilder b(*this);
+ // Itanium C++ ABI 2.9.5p7:
+ // When the abi::__pbase_type_info is for a direct or indirect pointer to an
+ // incomplete class type, the incomplete target type flag is set.
+ if (ContainsIncompleteClassType(PointeeTy))
+ Flags |= PTI_Incomplete;
- return b.Buildclass_type_info(RD, llvm::GlobalValue::ExternalLinkage);
+ if (IsIncompleteClassType(ClassType))
+ Flags |= PTI_ContainingClassIncomplete;
+
+ const llvm::Type *UnsignedIntLTy =
+ CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
+ Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
+
+ // Itanium C++ ABI 2.9.5p7:
+ // __pointee is a pointer to the std::type_info derivation for the
+ // unqualified type being pointed to.
+ llvm::Constant *PointeeTypeInfo =
+ RTTIBuilder(CGM).BuildTypeInfo(PointeeTy.getUnqualifiedType());
+ Fields.push_back(PointeeTypeInfo);
+
+ // Itanium C++ ABI 2.9.5p9:
+ // __context is a pointer to an abi::__class_type_info corresponding to the
+ // class type containing the member pointed to
+ // (e.g., the "A" in "int A::*").
+ Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(QualType(ClassType, 0)));
}
-llvm::Constant *CodeGenModule::GenerateRTTI(QualType Ty) {
- RTTIBuilder b(*this);
-
- return b.BuildType(Ty);
+llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty) {
+ if (!getContext().getLangOptions().RTTI) {
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ return llvm::Constant::getNullValue(Int8PtrTy);
+ }
+
+ return RTTIBuilder(*this).BuildTypeInfo(Ty);
}
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 31784ed..9f90ec5 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -216,12 +216,28 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
AppendPadding(Layout.getSize() / 8, Align);
}
+void CGRecordLayoutBuilder::LayoutBases(const CXXRecordDecl *RD,
+ const ASTRecordLayout &Layout) {
+ // Check if we need to add a vtable pointer.
+ if (RD->isDynamicClass() && !Layout.getPrimaryBase()) {
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8PtrTy(Types.getLLVMContext());
+
+ assert(NextFieldOffsetInBytes == 0 &&
+ "Vtable pointer must come first!");
+ AppendField(NextFieldOffsetInBytes, Int8PtrTy->getPointerTo());
+ }
+}
+
bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
assert(!D->isUnion() && "Can't call LayoutFields on a union!");
assert(Alignment && "Did not set alignment!");
const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D);
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D))
+ LayoutBases(RD, Layout);
+
unsigned FieldNo = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.h b/lib/CodeGen/CGRecordLayoutBuilder.h
index 4ebf4e8..cf84053 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.h
+++ b/lib/CodeGen/CGRecordLayoutBuilder.h
@@ -23,6 +23,8 @@ namespace llvm {
}
namespace clang {
+ class ASTRecordLayout;
+ class CXXRecordDecl;
class FieldDecl;
class RecordDecl;
@@ -90,6 +92,9 @@ class CGRecordLayoutBuilder {
/// Returns false if the operation failed because the struct is not packed.
bool LayoutFields(const RecordDecl *D);
+ /// LayoutBases - layout the bases and vtable pointer of a record decl.
+ void LayoutBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout);
+
/// LayoutField - layout a single field. Returns false if the operation failed
/// because the current struct is not packed.
bool LayoutField(const FieldDecl *D, uint64_t FieldOffset);
diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp
index 5cfc7ef..bed8439 100644
--- a/lib/CodeGen/CGTemporaries.cpp
+++ b/lib/CodeGen/CGTemporaries.cpp
@@ -17,6 +17,10 @@ using namespace CodeGen;
void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
llvm::Value *Ptr) {
+ assert((LiveTemporaries.empty() ||
+ LiveTemporaries.back().ThisPtr != Ptr ||
+ ConditionalBranchLevel) &&
+ "Pushed the same temporary twice; AST is likely wrong");
llvm::BasicBlock *DtorBlock = createBasicBlock("temp.dtor");
llvm::Value *CondPtr = 0;
@@ -41,6 +45,33 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
CondPtr));
PushCleanupBlock(DtorBlock);
+
+ if (Exceptions) {
+ const CXXLiveTemporaryInfo& Info = LiveTemporaries.back();
+ llvm::BasicBlock *CondEnd = 0;
+
+ EHCleanupBlock Cleanup(*this);
+
+ // If this is a conditional temporary, we need to check the condition
+ // boolean and only call the destructor if it's true.
+ if (Info.CondPtr) {
+ llvm::BasicBlock *CondBlock = createBasicBlock("cond.dtor.call");
+ CondEnd = createBasicBlock("cond.dtor.end");
+
+ llvm::Value *Cond = Builder.CreateLoad(Info.CondPtr);
+ Builder.CreateCondBr(Cond, CondBlock, CondEnd);
+ EmitBlock(CondBlock);
+ }
+
+ EmitCXXDestructorCall(Info.Temporary->getDestructor(),
+ Dtor_Complete, Info.ThisPtr);
+
+ if (CondEnd) {
+ // Reset the condition. to false.
+ Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), Info.CondPtr);
+ EmitBlock(CondEnd);
+ }
+ }
}
void CodeGenFunction::PopCXXTemporary() {
@@ -92,12 +123,6 @@ CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
llvm::Value *AggLoc,
bool IsAggLocVolatile,
bool IsInitializer) {
- // If we shouldn't destroy the temporaries, just emit the
- // child expression.
- if (!E->shouldDestroyTemporaries())
- return EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile,
- /*IgnoreResult=*/false, IsInitializer);
-
// Keep track of the current cleanup stack depth.
size_t CleanupStackDepth = CleanupEntries.size();
(void) CleanupStackDepth;
@@ -119,11 +144,6 @@ CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
LValue CodeGenFunction::EmitCXXExprWithTemporariesLValue(
const CXXExprWithTemporaries *E) {
- // If we shouldn't destroy the temporaries, just emit the
- // child expression.
- if (!E->shouldDestroyTemporaries())
- return EmitLValue(E->getSubExpr());
-
// Keep track of the current cleanup stack depth.
size_t CleanupStackDepth = CleanupEntries.size();
(void) CleanupStackDepth;
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index 5283ed9..7930f71 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -202,8 +202,10 @@ public:
Extern(!l->isInAnonymousNamespace()),
LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) {
Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
- if (BuildVtable)
- rtti = CGM.GetAddrOfRTTI(MostDerivedClass);
+ if (BuildVtable) {
+ QualType ClassType = CGM.getContext().getTagDeclType(MostDerivedClass);
+ rtti = CGM.GetAddrOfRTTIDescriptor(ClassType);
+ }
}
// getVtableComponents - Returns a reference to the vtable components.
@@ -481,13 +483,13 @@ public:
}
- Index_t FinishGenerateVtable(const CXXRecordDecl *RD,
- const ASTRecordLayout &Layout,
- const CXXRecordDecl *PrimaryBase,
- bool PrimaryBaseWasVirtual,
- bool MorallyVirtual, int64_t Offset,
- bool ForVirtualBase, int64_t CurrentVBaseOffset,
- Path_t *Path) {
+ void FinishGenerateVtable(const CXXRecordDecl *RD,
+ const ASTRecordLayout &Layout,
+ const CXXRecordDecl *PrimaryBase,
+ bool PrimaryBaseWasVirtual,
+ bool MorallyVirtual, int64_t Offset,
+ bool ForVirtualBase, int64_t CurrentVBaseOffset,
+ Path_t *Path) {
bool alloc = false;
if (Path == 0) {
alloc = true;
@@ -535,7 +537,6 @@ public:
if (alloc) {
delete Path;
}
- return AddressPoint;
}
void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
@@ -600,19 +601,19 @@ public:
}
}
- int64_t GenerateVtableForBase(const CXXRecordDecl *RD, int64_t Offset = 0,
- bool MorallyVirtual = false,
- bool ForVirtualBase = false,
- int CurrentVBaseOffset = 0,
- Path_t *Path = 0) {
+ void GenerateVtableForBase(const CXXRecordDecl *RD, int64_t Offset = 0,
+ bool MorallyVirtual = false,
+ bool ForVirtualBase = false,
+ int CurrentVBaseOffset = 0,
+ Path_t *Path = 0) {
if (!RD->isDynamicClass())
- return 0;
+ return;
// Construction vtable don't need parts that have no virtual bases and
// aren't morally virtual.
if ((LayoutClass != MostDerivedClass) &&
RD->getNumVBases() == 0 && !MorallyVirtual)
- return 0;
+ return;
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
@@ -631,9 +632,9 @@ public:
if (Path)
OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset);
- return FinishGenerateVtable(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual,
- MorallyVirtual, Offset, ForVirtualBase,
- CurrentVBaseOffset, Path);
+ FinishGenerateVtable(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual,
+ MorallyVirtual, Offset, ForVirtualBase,
+ CurrentVBaseOffset, Path);
}
void GenerateVtableForVBases(const CXXRecordDecl *RD,
@@ -751,10 +752,10 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx,
}
const CXXRecordDecl *DerivedDecl =
- cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl());
+ cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl());
const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl());
+ cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl());
return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl);
}
@@ -1156,22 +1157,13 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
CGM.getMangleContext().mangleCXXVtable(RD, OutName);
llvm::StringRef Name = OutName.str();
- int64_t AddressPoint;
-
llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
- if (GV && CGM.AddressPoints[LayoutClass] && !GV->isDeclaration()) {
- AddressPoint=(*(*(CGM.AddressPoints[LayoutClass]))[RD])[std::make_pair(RD,
- Offset)];
- // FIXME: We can never have 0 address point. Do this for now so gepping
- // retains the same structure. Later, we'll just assert.
- if (AddressPoint == 0)
- AddressPoint = 1;
- } else {
+ if (GV == 0 || CGM.AddressPoints[LayoutClass] == 0 || GV->isDeclaration()) {
VtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition);
D1(printf("vtable %s\n", RD->getNameAsCString()));
// First comes the vtables for all the non-virtual bases...
- AddressPoint = b.GenerateVtableForBase(RD, Offset);
+ b.GenerateVtableForBase(RD, Offset);
// then the vtables for all the virtual bases.
b.GenerateVtableForVBases(RD, Offset);
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 28df9e4..f904f04 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -331,7 +331,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD,
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
// FIXME: For C++0x, we want to look for implicit *definitions* of
// these special member functions, rather than implicit *declarations*.
- if (CD->isCopyConstructor(getContext())) {
+ if (CD->isCopyConstructor()) {
assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
"Cannot synthesize a non-implicit copy constructor");
SynthesizeCXXCopyConstructor(CD, GD.getCtorType(), Fn, Args);
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 12e636c..273ddca 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -515,6 +515,12 @@ public:
void InitializeVtablePtrs(const CXXRecordDecl *ClassDecl);
+ void InitializeVtablePtrsRecursive(const CXXRecordDecl *ClassDecl,
+ llvm::Constant *Vtable,
+ CodeGenModule::AddrSubMap_t& AddressPoints,
+ llvm::Value *ThisPtr,
+ uint64_t Offset);
+
void SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
CXXCtorType Type,
llvm::Function *Fn,
@@ -807,6 +813,8 @@ public:
llvm::Value* EmitCXXTypeidExpr(const CXXTypeidExpr *E);
llvm::Value *EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE);
+ void EmitCheck(llvm::Value *, unsigned Size);
+
//===--------------------------------------------------------------------===//
// Declaration Emission
//===--------------------------------------------------------------------===//
@@ -921,6 +929,12 @@ public:
///
LValue EmitLValue(const Expr *E);
+ /// EmitCheckedLValue - Same as EmitLValue but additionally we generate
+ /// checking code to guard against undefined behavior. This is only
+ /// suitable when we know that the address will be used to access the
+ /// object.
+ LValue EmitCheckedLValue(const Expr *E);
+
/// EmitLoadOfScalar - Load a scalar value from an address, taking
/// care to appropriately convert from the memory representation to
/// the LLVM value representation.
@@ -1022,14 +1036,17 @@ public:
/// used to set attributes on the call (noreturn, etc.).
RValue EmitCall(const CGFunctionInfo &FnInfo,
llvm::Value *Callee,
+ ReturnValueSlot ReturnValue,
const CallArgList &Args,
const Decl *TargetDecl = 0);
- RValue EmitCall(llvm::Value *Callee, QualType FnType,
+ RValue EmitCall(QualType FnType, llvm::Value *Callee,
+ ReturnValueSlot ReturnValue,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd,
const Decl *TargetDecl = 0);
- RValue EmitCallExpr(const CallExpr *E);
+ RValue EmitCallExpr(const CallExpr *E,
+ ReturnValueSlot ReturnValue = ReturnValueSlot());
llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
const llvm::Type *Ty);
@@ -1038,20 +1055,24 @@ public:
RValue EmitCXXMemberCall(const CXXMethodDecl *MD,
llvm::Value *Callee,
+ ReturnValueSlot ReturnValue,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
- RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E);
- RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E);
+ RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E,
+ ReturnValueSlot ReturnValue);
+ RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
+ ReturnValueSlot ReturnValue);
RValue EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
- const CXXMethodDecl *MD);
+ const CXXMethodDecl *MD,
+ ReturnValueSlot ReturnValue);
RValue EmitBuiltinExpr(const FunctionDecl *FD,
unsigned BuiltinID, const CallExpr *E);
- RValue EmitBlockCallExpr(const CallExpr *E);
+ RValue EmitBlockCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue);
/// EmitTargetBuiltinExpr - Emit the given builtin call. Returns 0 if the call
/// is unhandled by the current target.
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 761f343..d497471 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -30,6 +30,7 @@
#include "llvm/CallingConv.h"
#include "llvm/Module.h"
#include "llvm/Intrinsics.h"
+#include "llvm/LLVMContext.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -546,7 +547,7 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
// static, static inline, always_inline, and extern inline functions can
// always be deferred. Normal inline functions can be deferred in C99/C++.
if (Linkage == GVA_Internal || Linkage == GVA_C99Inline ||
- Linkage == GVA_CXXInline)
+ Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation)
return true;
return false;
}
@@ -1089,9 +1090,8 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
CI->replaceAllUsesWith(NewCall);
// Copy any custom metadata attached with CI.
- llvm::MetadataContext &TheMetadata = CI->getContext().getMetadata();
- TheMetadata.copyMD(CI, NewCall);
-
+ if (llvm::MDNode *DbgNode = CI->getMetadata("dbg"))
+ NewCall->setMetadata("dbg", DbgNode);
CI->eraseFromParent();
}
}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index cc7ec9c..939c66c 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -212,24 +212,10 @@ public:
llvm::Constant *GetAddrOfFunction(GlobalDecl GD,
const llvm::Type *Ty = 0);
- /// GetAddrOfRTTI - Get the address of the RTTI structure for the given type.
- llvm::Constant *GetAddrOfRTTI(QualType Ty);
+ /// GetAddrOfRTTIDescriptor - Get the address of the RTTI descriptor
+ /// for the given type.
+ llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty);
- /// GetAddrOfRTTI - Get the address of the RTTI structure for the given record
- /// decl.
- llvm::Constant *GetAddrOfRTTI(const CXXRecordDecl *RD);
-
- /// GenerateRTTI - Generate the rtti information for the given type.
- llvm::Constant *GenerateRTTI(const CXXRecordDecl *RD);
-
- /// GenerateRTTIRef - Generate a reference to the rtti information for the
- /// given type.
- llvm::Constant *GenerateRTTIRef(const CXXRecordDecl *RD);
-
- /// GenerateRTTI - Generate the rtti information for the given
- /// non-class type.
- llvm::Constant *GenerateRTTI(QualType Ty);
-
llvm::Constant *GetAddrOfThunk(GlobalDecl GD,
const ThunkAdjustment &ThisAdjustment);
llvm::Constant *GetAddrOfCovariantThunk(GlobalDecl GD,
@@ -247,8 +233,8 @@ public:
const CovariantThunkAdjustment &Adjustment);
typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
- typedef llvm::DenseMap<const CXXRecordDecl *,
- llvm::DenseMap<CtorVtable_t, int64_t>*> AddrMap_t;
+ typedef llvm::DenseMap<CtorVtable_t, int64_t> AddrSubMap_t;
+ typedef llvm::DenseMap<const CXXRecordDecl *, AddrSubMap_t *> AddrMap_t;
llvm::DenseMap<const CXXRecordDecl *, AddrMap_t*> AddressPoints;
/// GetCXXBaseClassOffset - Returns the offset from a derived class to its
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index cd3575c..cd34e0c 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -199,7 +199,6 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
case Type::Builtin: {
switch (cast<BuiltinType>(Ty).getKind()) {
- default: assert(0 && "Unknown builtin type!");
case BuiltinType::Void:
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
@@ -245,12 +244,16 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
case BuiltinType::UInt128:
case BuiltinType::Int128:
return llvm::IntegerType::get(getLLVMContext(), 128);
+
+ case BuiltinType::Overload:
+ case BuiltinType::Dependent:
+ case BuiltinType::UndeducedAuto:
+ assert(0 && "Unexpected builtin type!");
+ break;
}
+ assert(0 && "Unknown builtin type!");
break;
}
- case Type::FixedWidthInt:
- return llvm::IntegerType::get(getLLVMContext(),
- cast<FixedWidthIntType>(T)->getWidth());
case Type::Complex: {
const llvm::Type *EltTy =
ConvertTypeRecursive(cast<ComplexType>(Ty).getElementType());
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index 90cc894..10fd1f5 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -125,8 +125,8 @@ private:
void mangleTemplateArgs(const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
- void mangleTemplateArgumentList(const TemplateArgumentList &L);
- void mangleTemplateArgument(const TemplateArgument &A);
+ void mangleTemplateArgs(const TemplateArgumentList &L);
+ void mangleTemplateArg(const TemplateArgument &A);
void mangleTemplateParameter(unsigned Index);
};
@@ -321,7 +321,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleUnscopedTemplateName(TD);
- mangleTemplateArgumentList(*TemplateArgs);
+ mangleTemplateArgs(*TemplateArgs);
return;
}
@@ -480,10 +480,17 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
mangleType(Context.getASTContext().getCanonicalType(Name.getCXXNameType()));
break;
- case DeclarationName::CXXOperatorName:
- mangleOperatorName(Name.getCXXOverloadedOperator(),
- cast<FunctionDecl>(ND)->getNumParams());
+ case DeclarationName::CXXOperatorName: {
+ unsigned Arity = cast<FunctionDecl>(ND)->getNumParams();
+
+ // If we have a C++ member function, we need to include the 'this' pointer.
+ // FIXME: This does not make sense for operators that are static, but their
+ // names stay the same regardless of the arity (operator new for instance).
+ if (isa<CXXMethodDecl>(ND))
+ Arity++;
+ mangleOperatorName(Name.getCXXOverloadedOperator(), Arity);
break;
+ }
case DeclarationName::CXXLiteralOperatorName:
// FIXME: This mangling is not yet official.
@@ -517,7 +524,7 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD);
- mangleTemplateArgumentList(*TemplateArgs);
+ mangleTemplateArgs(*TemplateArgs);
} else {
manglePrefix(DC);
mangleUnqualifiedName(ND);
@@ -573,7 +580,7 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC) {
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) {
mangleTemplatePrefix(TD);
- mangleTemplateArgumentList(*TemplateArgs);
+ mangleTemplateArgs(*TemplateArgs);
} else {
manglePrefix(DC->getParent());
mangleUnqualifiedName(cast<NamedDecl>(DC));
@@ -611,16 +618,24 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
case OO_Array_Delete: Out << "da"; break;
// ::= ps # + (unary)
// ::= pl # +
- case OO_Plus: Out << (Arity == 1? "ps" : "pl"); break;
+ case OO_Plus:
+ assert((Arity == 1 || Arity == 2) && "Invalid arity!");
+ Out << (Arity == 1? "ps" : "pl"); break;
// ::= ng # - (unary)
// ::= mi # -
- case OO_Minus: Out << (Arity == 1? "ng" : "mi"); break;
+ case OO_Minus:
+ assert((Arity == 1 || Arity == 2) && "Invalid arity!");
+ Out << (Arity == 1? "ng" : "mi"); break;
// ::= ad # & (unary)
// ::= an # &
- case OO_Amp: Out << (Arity == 1? "ad" : "an"); break;
+ case OO_Amp:
+ assert((Arity == 1 || Arity == 2) && "Invalid arity!");
+ Out << (Arity == 1? "ad" : "an"); break;
// ::= de # * (unary)
// ::= ml # *
- case OO_Star: Out << (Arity == 1? "de" : "ml"); break;
+ case OO_Star:
+ assert((Arity == 1 || Arity == 2) && "Invalid arity!");
+ Out << (Arity == 1? "de" : "ml"); break;
// ::= co # ~
case OO_Tilde: Out << "co"; break;
// ::= dv # /
@@ -975,11 +990,8 @@ void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
}
void CXXNameMangler::mangleType(const BlockPointerType *T) {
- assert(false && "can't mangle block pointer types yet");
-}
-
-void CXXNameMangler::mangleType(const FixedWidthIntType *T) {
- assert(false && "can't mangle arbitary-precision integer type yet");
+ Out << "U13block_pointer";
+ mangleType(T->getPointeeType());
}
void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
@@ -1078,6 +1090,16 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
break;
}
+ case Expr::CXXOperatorCallExprClass: {
+ const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E);
+ unsigned NumArgs = CE->getNumArgs();
+ mangleOperatorName(CE->getOperator(), /*Arity=*/NumArgs);
+ // Mangle the arguments.
+ for (unsigned i = 0; i != NumArgs; ++i)
+ mangleExpression(CE->getArg(i));
+ break;
+ }
+
case Expr::ParenExprClass:
mangleExpression(cast<ParenExpr>(E)->getSubExpr());
break;
@@ -1161,11 +1183,11 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
}
}
-void CXXNameMangler::mangleTemplateArgumentList(const TemplateArgumentList &L) {
+void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentList &L) {
// <template-args> ::= I <template-arg>+ E
Out << "I";
for (unsigned i = 0, e = L.size(); i != e; ++i)
- mangleTemplateArgument(L[i]);
+ mangleTemplateArg(L[i]);
Out << "E";
}
@@ -1174,11 +1196,11 @@ void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs,
// <template-args> ::= I <template-arg>+ E
Out << "I";
for (unsigned i = 0; i != NumTemplateArgs; ++i)
- mangleTemplateArgument(TemplateArgs[i]);
+ mangleTemplateArg(TemplateArgs[i]);
Out << "E";
}
-void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) {
+void CXXNameMangler::mangleTemplateArg(const TemplateArgument &A) {
// <template-arg> ::= <type> # type or template
// ::= X <expression> E # expression
// ::= <expr-primary> # simple expressions
@@ -1190,6 +1212,9 @@ void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) {
case TemplateArgument::Type:
mangleType(A.getAsType());
break;
+ case TemplateArgument::Template:
+ mangleName(A.getAsTemplate().getAsTemplateDecl());
+ break;
case TemplateArgument::Expression:
Out << 'X';
mangleExpression(A.getAsExpr());
@@ -1558,6 +1583,7 @@ void MangleContext::mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
void MangleContext::mangleCXXRTTI(QualType Ty,
llvm::SmallVectorImpl<char> &Res) {
// <special-name> ::= TI <type> # typeinfo structure
+ assert(!Ty.hasQualifiers() && "RTTI info cannot have top-level qualifiers");
CXXNameMangler Mangler(*this, Res);
Mangler.getStream() << "_ZTI";
Mangler.mangleType(Ty);
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 017059d..1e1edc1 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -81,7 +81,7 @@ namespace {
if (Builder)
Builder->Release();
- };
+ }
virtual void CompleteTentativeDefinition(VarDecl *D) {
if (Diags.hasErrorOccurred())
diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp
index 7be1ead..863a297 100644
--- a/lib/CodeGen/TargetABIInfo.cpp
+++ b/lib/CodeGen/TargetABIInfo.cpp
@@ -805,6 +805,10 @@ void X86_64ABIInfo::classify(QualType Ty,
if (Lo == Memory || Hi == Memory)
break;
}
+
+ // If this record has no fields but isn't empty, classify as INTEGER.
+ if (RD->field_empty() && Size)
+ Current = Integer;
}
// Classify the fields one at a time, merging the results.
diff --git a/lib/Driver/CC1Options.cpp b/lib/Driver/CC1Options.cpp
index 13f84c0..0e98bb9 100644
--- a/lib/Driver/CC1Options.cpp
+++ b/lib/Driver/CC1Options.cpp
@@ -15,7 +15,7 @@ using namespace clang::driver;
using namespace clang::driver::options;
using namespace clang::driver::cc1options;
-static OptTable::Info CC1InfoTable[] = {
+static const OptTable::Info CC1InfoTable[] = {
#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
{ NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index dbe7bd9..ab4bd49 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -711,6 +711,11 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
// Add a link action if necessary.
if (!LinkerInputs.empty())
Actions.push_back(new LinkJobAction(LinkerInputs, types::TY_Image));
+
+ // If we are linking, claim any options which are obviously only used for
+ // compilation.
+ if (FinalPhase == phases::Link)
+ Args.ClaimAllArgs(options::OPT_CompileOnly_Group);
}
Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
@@ -734,6 +739,10 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
case phases::Precompile:
return new PrecompileJobAction(Input, types::TY_PCH);
case phases::Compile: {
+ bool HasO4 = false;
+ if (const Arg *A = Args.getLastArg(options::OPT_O_Group))
+ HasO4 = A->getOption().matches(options::OPT_O4);
+
if (Args.hasArg(options::OPT_fsyntax_only)) {
return new CompileJobAction(Input, types::TY_Nothing);
} else if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto)) {
@@ -741,8 +750,7 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
} else if (Args.hasArg(options::OPT_emit_ast)) {
return new CompileJobAction(Input, types::TY_AST);
} else if (Args.hasArg(options::OPT_emit_llvm) ||
- Args.hasArg(options::OPT_flto) ||
- Args.hasArg(options::OPT_O4)) {
+ Args.hasArg(options::OPT_flto) || HasO4) {
types::ID Output =
Args.hasArg(options::OPT_S) ? types::TY_LLVMAsm : types::TY_LLVMBC;
return new CompileJobAction(Input, Output);
@@ -768,10 +776,8 @@ void Driver::BuildJobs(Compilation &C) const {
UsePipes = false;
// -save-temps inhibits pipes.
- if (SaveTemps && UsePipes) {
+ if (SaveTemps && UsePipes)
Diag(clang::diag::warn_drv_pipe_ignored_with_save_temps);
- UsePipes = true;
- }
Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o);
@@ -906,14 +912,12 @@ void Driver::BuildJobsForAction(Compilation &C,
// See if we should use an integrated preprocessor. We do so when we have
// exactly one input, since this is the only use case we care about
// (irrelevant since we don't support combine yet).
- bool UseIntegratedCPP = false;
const ActionList *Inputs = &A->getInputs();
if (Inputs->size() == 1 && isa<PreprocessJobAction>(*Inputs->begin())) {
if (!C.getArgs().hasArg(options::OPT_no_integrated_cpp) &&
!C.getArgs().hasArg(options::OPT_traditional_cpp) &&
!C.getArgs().hasArg(options::OPT_save_temps) &&
T.hasIntegratedCPP()) {
- UseIntegratedCPP = true;
Inputs = &(*Inputs)[0]->getInputs();
}
}
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index abe9c81..9b6264a 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -22,6 +22,10 @@ ToolChain::ToolChain(const HostInfo &_Host, const llvm::Triple &_Triple)
ToolChain::~ToolChain() {
}
+const Driver &ToolChain::getDriver() const {
+ return Host.getDriver();
+}
+
std::string ToolChain::GetFilePath(const Compilation &C,
const char *Name) const {
return Host.getDriver().GetFilePath(Name, *this);
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 420573d..cc3febf 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -88,7 +88,7 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple,
std::string Path;
if (getArchName() == "x86_64") {
- Path = getHost().getDriver().Dir;
+ Path = getDriver().Dir;
Path += "/../lib/gcc/";
Path += ToolChainDir;
Path += "/x86_64";
@@ -100,7 +100,7 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple,
getFilePaths().push_back(Path);
}
- Path = getHost().getDriver().Dir;
+ Path = getDriver().Dir;
Path += "/../lib/gcc/";
Path += ToolChainDir;
getFilePaths().push_back(Path);
@@ -109,7 +109,7 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple,
Path += ToolChainDir;
getFilePaths().push_back(Path);
- Path = getHost().getDriver().Dir;
+ Path = getDriver().Dir;
Path += "/../libexec/gcc/";
Path += ToolChainDir;
getProgramPaths().push_back(Path);
@@ -118,11 +118,11 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple,
Path += ToolChainDir;
getProgramPaths().push_back(Path);
- Path = getHost().getDriver().Dir;
+ Path = getDriver().Dir;
Path += "/../libexec";
getProgramPaths().push_back(Path);
- getProgramPaths().push_back(getHost().getDriver().Dir);
+ getProgramPaths().push_back(getDriver().Dir);
}
Darwin::~Darwin() {
@@ -134,7 +134,7 @@ Darwin::~Darwin() {
Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const {
Action::ActionClass Key;
- if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
+ if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
else
Key = JA.getKind();
@@ -238,12 +238,12 @@ DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple,
// Add the relative libexec dir (for clang-cc).
//
// FIXME: We should sink clang-cc into libexec/clang/<version>/.
- std::string Path = getHost().getDriver().Dir;
+ std::string Path = getDriver().Dir;
Path += "/../libexec";
getProgramPaths().push_back(Path);
// We expect 'as', 'ld', etc. to be adjacent to our install dir.
- getProgramPaths().push_back(getHost().getDriver().Dir);
+ getProgramPaths().push_back(getDriver().Dir);
}
void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args,
@@ -264,7 +264,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
// cares. This is useful in situations where someone wants to statically link
// something like libstdc++, and needs its runtime support routines.
if (const Arg *A = Args.getLastArg(options::OPT_static_libgcc)) {
- getHost().getDriver().Diag(clang::diag::err_drv_unsupported_opt)
+ getDriver().Diag(clang::diag::err_drv_unsupported_opt)
<< A->getAsString(Args);
return;
}
@@ -284,7 +284,7 @@ void Darwin::getMacosxVersionMin(const ArgList &Args,
if (!Driver::GetReleaseVersion(A->getValue(Args), Res[0], Res[1], Res[2],
HadExtra) ||
HadExtra) {
- const Driver &D = getHost().getDriver();
+ const Driver &D = getDriver();
D.Diag(clang::diag::err_drv_invalid_version_number)
<< A->getAsString(Args);
}
@@ -295,7 +295,7 @@ void Darwin::getMacosxVersionMin(const ArgList &Args,
DerivedArgList *Darwin::TranslateArgs(InputArgList &Args,
const char *BoundArch) const {
DerivedArgList *DAL = new DerivedArgList(Args, false);
- const OptTable &Opts = getHost().getDriver().getOpts();
+ const OptTable &Opts = getDriver().getOpts();
// FIXME: We really want to get out of the tool chain level argument
// translation business, as it makes the driver functionality much
@@ -309,7 +309,7 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args,
Arg *iPhoneVersion =
Args.getLastArgNoClaim(options::OPT_miphoneos_version_min_EQ);
if (OSXVersion && iPhoneVersion) {
- getHost().getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with)
+ getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with)
<< OSXVersion->getAsString(Args)
<< iPhoneVersion->getAsString(Args);
} else if (!OSXVersion && !iPhoneVersion) {
@@ -355,7 +355,7 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args,
// like -O4 are going to slip through.
if (!XarchArg || Index > Prev + 1 ||
XarchArg->getOption().isDriverOption()) {
- getHost().getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument)
+ getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument)
<< A->getAsString(Args);
continue;
}
@@ -526,6 +526,12 @@ bool Darwin::IsUnwindTablesDefault() const {
return getArchName() == "x86_64";
}
+bool Darwin::UseDwarfDebugFlags() const {
+ if (const char *S = ::getenv("RC_DEBUG_OPTIONS"))
+ return S[0] != '\0';
+ return false;
+}
+
const char *Darwin::GetDefaultRelocationModel() const {
return "pic";
}
@@ -542,11 +548,11 @@ const char *Darwin::GetForcedPicModel() const {
Generic_GCC::Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple)
: ToolChain(Host, Triple) {
- std::string Path(getHost().getDriver().Dir);
+ std::string Path(getDriver().Dir);
Path += "/../libexec";
getProgramPaths().push_back(Path);
- getProgramPaths().push_back(getHost().getDriver().Dir);
+ getProgramPaths().push_back(getDriver().Dir);
}
Generic_GCC::~Generic_GCC() {
@@ -559,7 +565,7 @@ Generic_GCC::~Generic_GCC() {
Tool &Generic_GCC::SelectTool(const Compilation &C,
const JobAction &JA) const {
Action::ActionClass Key;
- if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
+ if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
else
Key = JA.getKind();
@@ -620,13 +626,13 @@ DerivedArgList *Generic_GCC::TranslateArgs(InputArgList &Args,
OpenBSD::OpenBSD(const HostInfo &Host, const llvm::Triple& Triple)
: Generic_GCC(Host, Triple) {
- getFilePaths().push_back(getHost().getDriver().Dir + "/../lib");
+ getFilePaths().push_back(getDriver().Dir + "/../lib");
getFilePaths().push_back("/usr/lib");
}
Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA) const {
Action::ActionClass Key;
- if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
+ if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
else
Key = JA.getKind();
@@ -651,17 +657,17 @@ Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA) const {
FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple, bool Lib32)
: Generic_GCC(Host, Triple) {
if (Lib32) {
- getFilePaths().push_back(getHost().getDriver().Dir + "/../lib32");
+ getFilePaths().push_back(getDriver().Dir + "/../lib32");
getFilePaths().push_back("/usr/lib32");
} else {
- getFilePaths().push_back(getHost().getDriver().Dir + "/../lib");
+ getFilePaths().push_back(getDriver().Dir + "/../lib");
getFilePaths().push_back("/usr/lib");
}
}
Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const {
Action::ActionClass Key;
- if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
+ if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
else
Key = JA.getKind();
@@ -687,13 +693,13 @@ AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple)
: Generic_GCC(Host, Triple) {
// Path mangling to find libexec
- std::string Path(getHost().getDriver().Dir);
+ std::string Path(getDriver().Dir);
Path += "/../libexec";
getProgramPaths().push_back(Path);
- getProgramPaths().push_back(getHost().getDriver().Dir);
+ getProgramPaths().push_back(getDriver().Dir);
- getFilePaths().push_back(getHost().getDriver().Dir + "/../lib");
+ getFilePaths().push_back(getDriver().Dir + "/../lib");
getFilePaths().push_back("/usr/lib");
getFilePaths().push_back("/usr/sfw/lib");
getFilePaths().push_back("/opt/gcc4/lib");
@@ -703,7 +709,7 @@ AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple)
Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA) const {
Action::ActionClass Key;
- if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
+ if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
else
Key = JA.getKind();
@@ -728,7 +734,7 @@ Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA) const {
Linux::Linux(const HostInfo &Host, const llvm::Triple& Triple)
: Generic_GCC(Host, Triple) {
- getFilePaths().push_back(getHost().getDriver().Dir + "/../lib/clang/1.0/");
+ getFilePaths().push_back(getDriver().Dir + "/../lib/clang/1.0/");
getFilePaths().push_back("/lib/");
getFilePaths().push_back("/usr/lib/");
@@ -755,20 +761,20 @@ DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple)
: Generic_GCC(Host, Triple) {
// Path mangling to find libexec
- std::string Path(getHost().getDriver().Dir);
+ std::string Path(getDriver().Dir);
Path += "/../libexec";
getProgramPaths().push_back(Path);
- getProgramPaths().push_back(getHost().getDriver().Dir);
+ getProgramPaths().push_back(getDriver().Dir);
- getFilePaths().push_back(getHost().getDriver().Dir + "/../lib");
+ getFilePaths().push_back(getDriver().Dir + "/../lib");
getFilePaths().push_back("/usr/lib");
getFilePaths().push_back("/usr/lib/gcc41");
}
Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA) const {
Action::ActionClass Key;
- if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
+ if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
else
Key = JA.getKind();
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index fcd96f1..be36344 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -154,6 +154,8 @@ public:
virtual const char *GetDefaultRelocationModel() const;
virtual const char *GetForcedPicModel() const;
+ virtual bool UseDwarfDebugFlags() const;
+
/// }
};
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 70597ab..8f0af21 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -230,7 +230,7 @@ static const char *getARMTargetCPU(const ArgList &Args) {
if (MArch == "armv5e" || MArch == "armv5te")
return "arm1026ejs";
if (MArch == "armv5tej")
- return "arm926ejs";
+ return "arm926ej-s";
if (MArch == "armv6" || MArch == "armv6k")
return "arm1136jf-s";
if (MArch == "armv6j")
@@ -338,7 +338,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
void Clang::AddARMTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- const Driver &D = getToolChain().getHost().getDriver();
+ const Driver &D = getToolChain().getDriver();
// Select the ABI to use.
//
@@ -367,7 +367,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
CmdArgs.push_back(ABIName);
// Set the CPU based on -march= and -mcpu=.
- CmdArgs.push_back("-mcpu");
+ CmdArgs.push_back("-target-cpu");
CmdArgs.push_back(getARMTargetCPU(Args));
// Select the float ABI as determined by -msoft-float, -mhard-float, and
@@ -432,6 +432,53 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("hard");
}
+
+ // Set appropriate target features for floating point mode.
+ //
+ // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these
+ // yet (it uses the -mfloat-abi and -msoft-float options above), and it is
+ // stripped out by the ARM target.
+
+ // Use software floating point operations?
+ if (FloatABI == "soft") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+soft-float");
+ }
+
+ // Use software floating point argument passing?
+ if (FloatABI != "hard") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+soft-float-abi");
+ }
+
+ // Honor -mfpu=.
+ //
+ // FIXME: Centralize feature selection, defaulting shouldn't be also in the
+ // frontend target.
+ if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
+ llvm::StringRef FPU = A->getValue(Args);
+
+ // Set the target features based on the FPU.
+ if (FPU == "fpa" || FPU == "fpe2" || FPU == "fpe3" || FPU == "maverick") {
+ // Disable any default FPU support.
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-vfp2");
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-vfp3");
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-neon");
+ } else if (FPU == "vfp") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+vfp2");
+ } else if (FPU == "vfp3") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+vfp3");
+ } else if (FPU == "neon") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+neon");
+ } else
+ D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ }
}
void Clang::AddX86TargetArgs(const ArgList &Args,
@@ -480,7 +527,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
}
if (CPUName) {
- CmdArgs.push_back("-mcpu");
+ CmdArgs.push_back("-target-cpu");
CmdArgs.push_back(CPUName);
}
@@ -589,7 +636,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const Driver &D = getToolChain().getHost().getDriver();
+ const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
@@ -945,6 +992,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin))
CmdArgs.push_back("-fno-builtin");
+ if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
+ options::OPT_fno_assume_sane_operator_new))
+ CmdArgs.push_back("-fno-assume-sane-operator-new");
+
// -fblocks=0 is default.
if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks,
getToolChain().IsBlocksDefault())) {
@@ -1039,9 +1090,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers,
options::OPT_fno_dollars_in_identifiers)) {
if (A->getOption().matches(options::OPT_fdollars_in_identifiers))
- CmdArgs.push_back("-fdollars-in-identifiers=1");
+ CmdArgs.push_back("-fdollars-in-identifiers");
else
- CmdArgs.push_back("-fdollars-in-identifiers=0");
+ CmdArgs.push_back("-fno-dollars-in-identifiers");
}
// -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for
@@ -1105,6 +1156,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, "clang"));
+
+ // Optionally embed the -cc1 level arguments into the debug info, for build
+ // analysis.
+ if (getToolChain().UseDwarfDebugFlags()) {
+ llvm::SmallString<256> Flags;
+ Flags += Exec;
+ for (unsigned i = 0, e = CmdArgs.size(); i != e; ++i) {
+ Flags += " ";
+ Flags += CmdArgs[i];
+ }
+ CmdArgs.push_back("-dwarf-debug-flags");
+ CmdArgs.push_back(Args.MakeArgString(Flags.str()));
+ }
+
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
// Explicitly warn that these options are unsupported, even though
@@ -1135,7 +1200,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const Driver &D = getToolChain().getHost().getDriver();
+ const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
for (ArgList::const_iterator
@@ -1155,7 +1220,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
// If using a driver driver, force the arch.
const std::string &Arch = getToolChain().getArchName();
- if (getToolChain().getHost().useDriverDriver()) {
+ if (getToolChain().getTriple().getOS() == llvm::Triple::Darwin) {
CmdArgs.push_back("-arch");
// FIXME: Remove these special cases.
@@ -1223,8 +1288,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
II.getInputArg().render(Args, CmdArgs);
}
- const char *GCCName =
- getToolChain().getHost().getDriver().CCCGenericGCCName.c_str();
+ const char *GCCName = getToolChain().getDriver().CCCGenericGCCName.c_str();
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, GCCName));
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
@@ -1304,7 +1368,7 @@ darwin::CC1::getDependencyFileName(const ArgList &Args,
void darwin::CC1::AddCC1Args(const ArgList &Args,
ArgStringList &CmdArgs) const {
- const Driver &D = getToolChain().getHost().getDriver();
+ const Driver &D = getToolChain().getDriver();
CheckCodeGenerationOptions(D, Args);
@@ -1333,7 +1397,7 @@ void darwin::CC1::AddCC1Args(const ArgList &Args,
void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
const InputInfoList &Inputs,
const ArgStringList &OutputArgs) const {
- const Driver &D = getToolChain().getHost().getDriver();
+ const Driver &D = getToolChain().getDriver();
// Derived from cc1_options spec.
if (Args.hasArg(options::OPT_fast) ||
@@ -1481,7 +1545,7 @@ void darwin::CC1::AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args,
ArgStringList &CmdArgs,
const InputInfoList &Inputs) const {
- const Driver &D = getToolChain().getHost().getDriver();
+ const Driver &D = getToolChain().getDriver();
CheckPreprocessingOptions(D, Args);
@@ -1624,7 +1688,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const Driver &D = getToolChain().getHost().getDriver();
+ const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
assert(Inputs.size() == 1 && "Unexpected number of inputs!");
@@ -1873,7 +1937,7 @@ void darwin::DarwinTool::AddDarwinSubArch(const ArgList &Args,
void darwin::Link::AddLinkArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- const Driver &D = getToolChain().getHost().getDriver();
+ const Driver &D = getToolChain().getDriver();
// Derived from the "link" spec.
Args.AddAllArgs(CmdArgs, options::OPT_static);
@@ -2159,7 +2223,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
!Args.hasArg(options::OPT_nodefaultlibs)) {
// FIXME: g++ is more complicated here, it tries to put -lstdc++
// before -lm, for example.
- if (getToolChain().getHost().getDriver().CCCIsCXX)
+ if (getToolChain().getDriver().CCCIsCXX)
CmdArgs.push_back("-lstdc++");
// link_ssp spec is empty.
@@ -2273,7 +2337,7 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const Driver &D = getToolChain().getHost().getDriver();
+ const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
if ((!Args.hasArg(options::OPT_nostdlib)) &&
@@ -2404,7 +2468,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const Driver &D = getToolChain().getHost().getDriver();
+ const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
if ((!Args.hasArg(options::OPT_nostdlib)) &&
@@ -2539,7 +2603,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const Driver &D = getToolChain().getHost().getDriver();
+ const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
if (Args.hasArg(options::OPT_static)) {
@@ -2691,7 +2755,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const Driver &D = getToolChain().getHost().getDriver();
+ const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
if (Args.hasArg(options::OPT_static)) {
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 6729da8..8f7da52 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -137,7 +137,7 @@ namespace darwin {
}
public:
- DarwinTool(const char *Name, const ToolChain &TC) : Tool(Name, TC) {};
+ DarwinTool(const char *Name, const ToolChain &TC) : Tool(Name, TC) {}
};
class VISIBILITY_HIDDEN CC1 : public DarwinTool {
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index a74bbc2..6824d8f 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -14,10 +14,10 @@
#include "clang/Frontend/AnalysisConsumer.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ParentMap.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/Analysis/ManagerRegistry.h"
@@ -228,6 +228,19 @@ void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) {
break;
}
+ case Decl::CXXMethod: {
+ CXXMethodDecl *CXXMD = cast<CXXMethodDecl>(D);
+
+ if (Opts.AnalyzeSpecificFunction.size() > 0 &&
+ Opts.AnalyzeSpecificFunction != CXXMD->getName())
+ return;
+
+ Stmt *Body = CXXMD->getBody();
+ if (Body)
+ HandleCode(CXXMD, Body, FunctionActions);
+ break;
+ }
+
default:
break;
}
@@ -240,7 +253,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
if (!TranslationUnitActions.empty()) {
// Find the entry function definition (if any).
FunctionDecl *FD = 0;
-
+ // Must specify an entry function.
if (!Opts.AnalyzeSpecificFunction.empty()) {
for (DeclContext::decl_iterator I=TU->decls_begin(), E=TU->decls_end();
I != E; ++I) {
@@ -253,9 +266,11 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
}
}
- for (Actions::iterator I = TranslationUnitActions.begin(),
- E = TranslationUnitActions.end(); I != E; ++I)
- (*I)(*this, *Mgr, FD);
+ if (FD) {
+ for (Actions::iterator I = TranslationUnitActions.begin(),
+ E = TranslationUnitActions.end(); I != E; ++I)
+ (*I)(*this, *Mgr, FD);
+ }
}
if (!ObjCImplementationActions.empty()) {
@@ -358,7 +373,7 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
if (C.Opts.EnableExperimentalChecks)
RegisterExperimentalChecks(Eng);
- Eng.setTransferFunctions(tf);
+ Eng.setTransferFunctionsAndCheckers(tf);
// Set the graph auditor.
llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
@@ -475,8 +490,36 @@ static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr,
static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr,
Decl *D) {
+ // FIXME: This is largely copy of ActionGRExprEngine. Needs cleanup.
+ // Display progress.
+ C.DisplayFunction(D);
+
+ GRExprEngine Eng(mgr);
+
+ if (C.Opts.EnableExperimentalInternalChecks)
+ RegisterExperimentalInternalChecks(Eng);
- ActionGRExprEngine(C, mgr, D, CreateCallInliner(mgr.getASTContext()));
+ RegisterAppleChecks(Eng, *D);
+
+ if (C.Opts.EnableExperimentalChecks)
+ RegisterExperimentalChecks(Eng);
+
+ // Make a fake transfer function. The GRTransferFunc interface will be
+ // removed.
+ Eng.setTransferFunctionsAndCheckers(new GRTransferFuncs());
+
+ // Register call inliner as the last checker.
+ RegisterCallInliner(Eng);
+
+ // Execute the worklist algorithm.
+ Eng.ExecuteWorkList(mgr.getStackFrame(D));
+
+ // Visualize the exploded graph.
+ if (mgr.shouldVisualizeGraphviz())
+ Eng.ViewGraph(mgr.shouldTrimGraph());
+
+ // Display warnings.
+ Eng.getBugReporter().FlushReports();
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 03123d3..58aaa43 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -31,7 +31,6 @@ add_clang_library(clangFrontend
PlistDiagnostics.cpp
PrintParserCallbacks.cpp
PrintPreprocessedOutput.cpp
- RewriteBlocks.cpp
RewriteMacros.cpp
RewriteObjC.cpp
RewriteTest.cpp
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 7a3388f..63f66fa 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -122,6 +122,10 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-disable-llvm-optzns");
if (Opts.DisableRedZone)
Res.push_back("-disable-red-zone");
+ if (!Opts.DwarfDebugFlags.empty()) {
+ Res.push_back("-dwarf-debug-flags");
+ Res.push_back(Opts.DwarfDebugFlags);
+ }
if (!Opts.MergeAllConstants)
Res.push_back("-fno-merge-all-constants");
if (Opts.NoCommon)
@@ -276,7 +280,6 @@ static const char *getActionName(frontend::ActionKind Kind) {
case frontend::ParseSyntaxOnly: return "-fsyntax-only";
case frontend::PrintDeclContext: return "-print-decl-contexts";
case frontend::PrintPreprocessedInput: return "-E";
- case frontend::RewriteBlocks: return "-rewrite-blocks";
case frontend::RewriteMacros: return "-rewrite-macros";
case frontend::RewriteObjC: return "-rewrite-objc";
case frontend::RewriteTest: return "-rewrite-test";
@@ -440,7 +443,7 @@ static void LangOptsToArgs(const LangOptions &Opts,
if (Opts.DollarIdents)
Res.push_back("-fdollars-in-identifiers");
if (Opts.Microsoft)
- Res.push_back("-fms-extensions=1");
+ Res.push_back("-fms-extensions");
if (Opts.ObjCNonFragileABI)
Res.push_back("-fobjc-nonfragile-abi");
// NoInline is implicit.
@@ -466,6 +469,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-ffreestanding");
if (Opts.NoBuiltin)
Res.push_back("-fno-builtin");
+ if (!Opts.AssumeSaneOperatorNew)
+ Res.push_back("-fno-assume-sane-operator-new");
if (Opts.ThreadsafeStatics)
llvm::llvm_report_error("FIXME: Not yet implemented!");
if (Opts.POSIXThreads)
@@ -593,7 +598,7 @@ static void TargetOptsToArgs(const TargetOptions &Opts,
Res.push_back("-triple");
Res.push_back(Opts.Triple);
if (!Opts.CPU.empty()) {
- Res.push_back("-mcpu");
+ Res.push_back("-target-cpu");
Res.push_back(Opts.CPU);
}
if (!Opts.ABI.empty()) {
@@ -747,6 +752,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.DebugInfo = Args.hasArg(OPT_g);
Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
+ Opts.DwarfDebugFlags = getLastArgValue(Args, OPT_dwarf_debug_flags);
Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants);
Opts.NoCommon = Args.hasArg(OPT_fno_common);
Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float);
@@ -851,8 +857,6 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.ProgramAction = frontend::PrintDeclContext; break;
case OPT_E:
Opts.ProgramAction = frontend::PrintPreprocessedInput; break;
- case OPT_rewrite_blocks:
- Opts.ProgramAction = frontend::RewriteBlocks; break;
case OPT_rewrite_macros:
Opts.ProgramAction = frontend::RewriteMacros; break;
case OPT_rewrite_objc:
@@ -1124,10 +1128,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
if (Args.hasArg(OPT_trigraphs))
Opts.Trigraphs = 1;
- Opts.DollarIdents = !Opts.AsmPreprocessor;
- if (Args.hasArg(OPT_fdollars_in_identifiers))
- Opts.DollarIdents = 1;
-
+ Opts.DollarIdents = Args.hasFlag(OPT_fdollars_in_identifiers,
+ OPT_fno_dollars_in_identifiers,
+ !Opts.AsmPreprocessor);
Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings);
Opts.Microsoft = Args.hasArg(OPT_fms_extensions);
Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
@@ -1140,6 +1143,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
+ Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);
Opts.AccessControl = Args.hasArg(OPT_faccess_control);
Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);
@@ -1245,7 +1249,7 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
using namespace cc1options;
Opts.ABI = getLastArgValue(Args, OPT_target_abi);
- Opts.CPU = getLastArgValue(Args, OPT_mcpu);
+ Opts.CPU = getLastArgValue(Args, OPT_target_cpu);
Opts.Triple = getLastArgValue(Args, OPT_triple);
Opts.Features = getAllArgValues(Args, OPT_target_feature);
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index e3c313a..4c647fda 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -154,11 +154,6 @@ ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
return 0;
}
-ASTConsumer *RewriteBlocksAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
- return CreateBlockRewriter(InFile, CI.getDiagnostics(), CI.getLangOpts());
-}
-
ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
return new ASTConsumer();
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index b4ea257..9555125 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -478,6 +478,14 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
"i686-apple-darwin8", "", "", triple);
break;
case llvm::Triple::Linux:
+ // Exherbo (2009-10-26)
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ "x86_64-pc-linux-gnu", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ "i686-pc-linux-gnu", "", "", triple);
+ // Debian sid
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ "x86_64-linux-gnu", "32", "", triple);
// Ubuntu 7.10 - Gutsy Gibbon
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.3",
"i486-linux-gnu", "", "", triple);
@@ -543,11 +551,6 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
AddGnuCPlusPlusIncludePaths(
"/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4",
"i686-pc-linux-gnu", "", "", triple);
- // Exherbo (2009-10-26)
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
- "x86_64-pc-linux-gnu", "32", "", triple);
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
- "i686-pc-linux-gnu", "", "", triple);
break;
case llvm::Triple::FreeBSD:
// DragonFly
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 48ef2ac..d8fd791 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -1761,11 +1761,6 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
return Context->getQualifiedType(Base, Quals);
}
- case pch::TYPE_FIXED_WIDTH_INT: {
- assert(Record.size() == 2 && "Incorrect encoding of fixed-width int type");
- return Context->getFixedWidthIntType(Record[0], Record[1]);
- }
-
case pch::TYPE_COMPLEX: {
assert(Record.size() == 1 && "Incorrect encoding of complex type");
QualType ElemType = GetType(Record[0]);
@@ -1854,17 +1849,18 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
}
case pch::TYPE_FUNCTION_NO_PROTO: {
- if (Record.size() != 1) {
+ if (Record.size() != 2) {
Error("incorrect encoding of no-proto function type");
return QualType();
}
QualType ResultType = GetType(Record[0]);
- return Context->getFunctionNoProtoType(ResultType);
+ return Context->getFunctionNoProtoType(ResultType, Record[1]);
}
case pch::TYPE_FUNCTION_PROTO: {
QualType ResultType = GetType(Record[0]);
- unsigned Idx = 1;
+ bool NoReturn = Record[1];
+ unsigned Idx = 2;
unsigned NumParams = Record[Idx++];
llvm::SmallVector<QualType, 16> ParamTypes;
for (unsigned I = 0; I != NumParams; ++I)
@@ -1880,7 +1876,7 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams,
isVariadic, Quals, hasExceptionSpec,
hasAnyExceptionSpec, NumExceptions,
- Exceptions.data());
+ Exceptions.data(), NoReturn);
}
case pch::TYPE_UNRESOLVED_USING:
@@ -1986,9 +1982,6 @@ void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
-void TypeLocReader::VisitFixedWidthIntTypeLoc(FixedWidthIntTypeLoc TL) {
- TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
-}
void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) {
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index f28e61e..ba82d26 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -858,7 +858,9 @@ unsigned PCHStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
unsigned PCHStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
VisitExpr(E);
E->setConstructor(cast<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
E->setElidable(Record[Idx++]);
+ E->setRequiresZeroInitialization(Record[Idx++]);
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I]));
return E->getNumArgs();
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 681c1ff..2875f09 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -69,12 +69,6 @@ void PCHTypeWriter::VisitBuiltinType(const BuiltinType *T) {
assert(false && "Built-in types are never serialized");
}
-void PCHTypeWriter::VisitFixedWidthIntType(const FixedWidthIntType *T) {
- Record.push_back(T->getWidth());
- Record.push_back(T->isSigned());
- Code = pch::TYPE_FIXED_WIDTH_INT;
-}
-
void PCHTypeWriter::VisitComplexType(const ComplexType *T) {
Writer.AddTypeRef(T->getElementType(), Record);
Code = pch::TYPE_COMPLEX;
@@ -144,6 +138,7 @@ void PCHTypeWriter::VisitExtVectorType(const ExtVectorType *T) {
void PCHTypeWriter::VisitFunctionType(const FunctionType *T) {
Writer.AddTypeRef(T->getResultType(), Record);
+ Record.push_back(T->getNoReturnAttr());
}
void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
@@ -282,9 +277,6 @@ void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
-void TypeLocWriter::VisitFixedWidthIntTypeLoc(FixedWidthIntTypeLoc TL) {
- Writer.AddSourceLocation(TL.getNameLoc(), Record);
-}
void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
@@ -558,7 +550,6 @@ void PCHWriter::WriteBlockInfoBlock() {
// Decls and Types block.
BLOCK(DECLTYPES_BLOCK);
RECORD(TYPE_EXT_QUAL);
- RECORD(TYPE_FIXED_WIDTH_INT);
RECORD(TYPE_COMPLEX);
RECORD(TYPE_POINTER);
RECORD(TYPE_BLOCK_POINTER);
@@ -1645,10 +1636,10 @@ public:
II->hasMacroDefinition() &&
!PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro();
Bits = (uint32_t)II->getObjCOrBuiltinID();
- Bits = (Bits << 1) | hasMacroDefinition;
- Bits = (Bits << 1) | II->isExtensionToken();
- Bits = (Bits << 1) | II->isPoisoned();
- Bits = (Bits << 1) | II->isCPlusPlusOperatorKeyword();
+ Bits = (Bits << 1) | unsigned(hasMacroDefinition);
+ Bits = (Bits << 1) | unsigned(II->isExtensionToken());
+ Bits = (Bits << 1) | unsigned(II->isPoisoned());
+ Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword());
clang::io::Emit16(Out, Bits);
if (hasMacroDefinition)
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index 22f7ad6..abf4eaa 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -785,7 +785,9 @@ void PCHStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
VisitExpr(E);
Writer.AddDeclRef(E->getConstructor(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
Record.push_back(E->isElidable());
+ Record.push_back(E->requiresZeroInitialization());
Record.push_back(E->getNumArgs());
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
Writer.WriteSubStmt(E->getArg(I));
diff --git a/lib/Frontend/RewriteBlocks.cpp b/lib/Frontend/RewriteBlocks.cpp
deleted file mode 100644
index 25e7fc4..0000000
--- a/lib/Frontend/RewriteBlocks.cpp
+++ /dev/null
@@ -1,1152 +0,0 @@
-//===--- RewriteBlocks.cpp ----------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Hacks and fun related to the closure rewriter.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Frontend/ASTConsumers.h"
-#include "clang/Rewrite/Rewriter.h"
-#include "clang/AST/AST.h"
-#include "clang/AST/ASTConsumer.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/IdentifierTable.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/LangOptions.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/SmallPtrSet.h"
-
-using namespace clang;
-using llvm::utostr;
-
-namespace {
-
-class RewriteBlocks : public ASTConsumer {
- Rewriter Rewrite;
- Diagnostic &Diags;
- const LangOptions &LangOpts;
- unsigned RewriteFailedDiag;
-
- ASTContext *Context;
- SourceManager *SM;
- FileID MainFileID;
- const char *MainFileStart, *MainFileEnd;
-
- // Block expressions.
- llvm::SmallVector<BlockExpr *, 32> Blocks;
- llvm::SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs;
- llvm::DenseMap<BlockDeclRefExpr *, CallExpr *> BlockCallExprs;
-
- // Block related declarations.
- llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls;
- llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls;
- llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
-
- llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
-
- // The function/method we are rewriting.
- FunctionDecl *CurFunctionDef;
- ObjCMethodDecl *CurMethodDef;
-
- bool IsHeader;
-
- std::string Preamble;
-public:
- RewriteBlocks(std::string inFile, Diagnostic &D,
- const LangOptions &LOpts);
- ~RewriteBlocks() {
- // Get the buffer corresponding to MainFileID.
- // If we haven't changed it, then we are done.
- if (const RewriteBuffer *RewriteBuf =
- Rewrite.getRewriteBufferFor(MainFileID)) {
- std::string S(RewriteBuf->begin(), RewriteBuf->end());
- printf("%s\n", S.c_str());
- } else {
- printf("No changes\n");
- }
- }
-
- void Initialize(ASTContext &context);
-
- void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen);
- void ReplaceText(SourceLocation Start, unsigned OrigLength,
- const char *NewStr, unsigned NewLength);
-
- // Top Level Driver code.
- virtual void HandleTopLevelDecl(DeclGroupRef D) {
- for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
- HandleTopLevelSingleDecl(*I);
- }
- void HandleTopLevelSingleDecl(Decl *D);
- void HandleDeclInMainFile(Decl *D);
-
- // Top level
- Stmt *RewriteFunctionBody(Stmt *S);
- void InsertBlockLiteralsWithinFunction(FunctionDecl *FD);
- void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD);
-
- // Block specific rewrite rules.
- std::string SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD=0);
-
- void RewriteBlockCall(CallExpr *Exp);
- void RewriteBlockPointerDecl(NamedDecl *VD);
- void RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD);
- void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
-
- std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
- const char *funcName, std::string Tag);
- std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
- const char *funcName, std::string Tag);
- std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
- bool hasCopyDisposeHelpers);
- std::string SynthesizeBlockCall(CallExpr *Exp);
- void SynthesizeBlockLiterals(SourceLocation FunLocStart,
- const char *FunName);
-
- void CollectBlockDeclRefInfo(BlockExpr *Exp);
- void GetBlockCallExprs(Stmt *S);
- void GetBlockDeclRefExprs(Stmt *S);
-
- // We avoid calling Type::isBlockPointerType(), since it operates on the
- // canonical type. We only care if the top-level type is a closure pointer.
- bool isBlockPointerType(QualType T) { return isa<BlockPointerType>(T); }
-
- // FIXME: This predicate seems like it would be useful to add to ASTContext.
- bool isObjCType(QualType T) {
- if (!LangOpts.ObjC1 && !LangOpts.ObjC2)
- return false;
-
- QualType OCT = Context->getCanonicalType(T).getUnqualifiedType();
-
- if (OCT == Context->getCanonicalType(Context->getObjCIdType()) ||
- OCT == Context->getCanonicalType(Context->getObjCClassType()))
- return true;
-
- if (const PointerType *PT = OCT->getAs<PointerType>()) {
- if (isa<ObjCInterfaceType>(PT->getPointeeType()) ||
- PT->getPointeeType()->isObjCQualifiedIdType())
- return true;
- }
- return false;
- }
- // ObjC rewrite methods.
- void RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl);
- void RewriteCategoryDecl(ObjCCategoryDecl *CatDecl);
- void RewriteProtocolDecl(ObjCProtocolDecl *PDecl);
- void RewriteMethodDecl(ObjCMethodDecl *MDecl);
-
- void RewriteFunctionProtoType(QualType funcType, NamedDecl *D);
- void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND);
- void RewriteCastExpr(CastExpr *CE);
-
- bool PointerTypeTakesAnyBlockArguments(QualType QT);
- void GetExtentOfArgList(const char *Name, const char *&LParen, const char *&RParen);
-};
-
-}
-
-static bool IsHeaderFile(const std::string &Filename) {
- std::string::size_type DotPos = Filename.rfind('.');
-
- if (DotPos == std::string::npos) {
- // no file extension
- return false;
- }
-
- std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end());
- // C header: .h
- // C++ header: .hh or .H;
- return Ext == "h" || Ext == "hh" || Ext == "H";
-}
-
-RewriteBlocks::RewriteBlocks(std::string inFile,
- Diagnostic &D, const LangOptions &LOpts) :
- Diags(D), LangOpts(LOpts) {
- IsHeader = IsHeaderFile(inFile);
- CurFunctionDef = 0;
- CurMethodDef = 0;
- RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
- "rewriting failed");
-}
-
-ASTConsumer *clang::CreateBlockRewriter(const std::string& InFile,
- Diagnostic &Diags,
- const LangOptions &LangOpts) {
- return new RewriteBlocks(InFile, Diags, LangOpts);
-}
-
-void RewriteBlocks::Initialize(ASTContext &context) {
- Context = &context;
- SM = &Context->getSourceManager();
-
- // Get the ID and start/end of the main file.
- MainFileID = SM->getMainFileID();
- const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID);
- MainFileStart = MainBuf->getBufferStart();
- MainFileEnd = MainBuf->getBufferEnd();
-
- Rewrite.setSourceMgr(Context->getSourceManager(), LangOpts);
-
- if (IsHeader)
- Preamble = "#pragma once\n";
- Preamble += "#ifndef BLOCK_IMPL\n";
- Preamble += "#define BLOCK_IMPL\n";
- Preamble += "struct __block_impl {\n";
- Preamble += " void *isa;\n";
- Preamble += " int Flags;\n";
- Preamble += " int Size;\n";
- Preamble += " void *FuncPtr;\n";
- Preamble += "};\n";
- Preamble += "enum {\n";
- Preamble += " BLOCK_HAS_COPY_DISPOSE = (1<<25),\n";
- Preamble += " BLOCK_IS_GLOBAL = (1<<28)\n";
- Preamble += "};\n";
- if (LangOpts.Microsoft)
- Preamble += "#define __OBJC_RW_EXTERN extern \"C\" __declspec(dllimport)\n";
- else
- Preamble += "#define __OBJC_RW_EXTERN extern\n";
- Preamble += "// Runtime copy/destroy helper functions\n";
- Preamble += "__OBJC_RW_EXTERN void _Block_copy_assign(void *, void *);\n";
- Preamble += "__OBJC_RW_EXTERN void _Block_byref_assign_copy(void *, void *);\n";
- Preamble += "__OBJC_RW_EXTERN void _Block_destroy(void *);\n";
- Preamble += "__OBJC_RW_EXTERN void _Block_byref_release(void *);\n";
- Preamble += "__OBJC_RW_EXTERN void *_NSConcreteGlobalBlock;\n";
- Preamble += "__OBJC_RW_EXTERN void *_NSConcreteStackBlock;\n";
- Preamble += "#endif\n";
-
- InsertText(SM->getLocForStartOfFile(MainFileID),
- Preamble.c_str(), Preamble.size());
-}
-
-void RewriteBlocks::InsertText(SourceLocation Loc, const char *StrData,
- unsigned StrLen) {
- if (!Rewrite.InsertText(Loc, StrData, StrLen))
- return;
- Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);
-}
-
-void RewriteBlocks::ReplaceText(SourceLocation Start, unsigned OrigLength,
- const char *NewStr, unsigned NewLength) {
- if (!Rewrite.ReplaceText(Start, OrigLength,
- llvm::StringRef(NewStr, NewLength)))
- return;
- Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag);
-}
-
-void RewriteBlocks::RewriteMethodDecl(ObjCMethodDecl *Method) {
- bool haveBlockPtrs = false;
- for (ObjCMethodDecl::param_iterator I = Method->param_begin(),
- E = Method->param_end(); I != E; ++I)
- if (isBlockPointerType((*I)->getType()))
- haveBlockPtrs = true;
-
- if (!haveBlockPtrs)
- return;
-
- // Do a fuzzy rewrite.
- // We have 1 or more arguments that have closure pointers.
- SourceLocation Loc = Method->getLocStart();
- SourceLocation LocEnd = Method->getLocEnd();
- const char *startBuf = SM->getCharacterData(Loc);
- const char *endBuf = SM->getCharacterData(LocEnd);
-
- const char *methodPtr = startBuf;
- std::string Tag = "struct __block_impl *";
-
- while (*methodPtr++ && (methodPtr != endBuf)) {
- switch (*methodPtr) {
- case ':':
- methodPtr++;
- if (*methodPtr == '(') {
- const char *scanType = ++methodPtr;
- bool foundBlockPointer = false;
- unsigned parenCount = 1;
-
- while (parenCount) {
- switch (*scanType) {
- case '(':
- parenCount++;
- break;
- case ')':
- parenCount--;
- break;
- case '^':
- foundBlockPointer = true;
- break;
- }
- scanType++;
- }
- if (foundBlockPointer) {
- // advance the location to startArgList.
- Loc = Loc.getFileLocWithOffset(methodPtr-startBuf);
- assert((Loc.isValid()) && "Invalid Loc");
- ReplaceText(Loc, scanType-methodPtr-1, Tag.c_str(), Tag.size());
-
- // Advance startBuf. Since the underlying buffer has changed,
- // it's very important to advance startBuf (so we can correctly
- // compute a relative Loc the next time around).
- startBuf = methodPtr;
- }
- // Advance the method ptr to the end of the type.
- methodPtr = scanType;
- }
- break;
- }
- }
- return;
-}
-
-void RewriteBlocks::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
- for (ObjCInterfaceDecl::instmeth_iterator
- I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end();
- I != E; ++I)
- RewriteMethodDecl(*I);
- for (ObjCInterfaceDecl::classmeth_iterator
- I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end();
- I != E; ++I)
- RewriteMethodDecl(*I);
-}
-
-void RewriteBlocks::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
- for (ObjCCategoryDecl::instmeth_iterator
- I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end();
- I != E; ++I)
- RewriteMethodDecl(*I);
- for (ObjCCategoryDecl::classmeth_iterator
- I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end();
- I != E; ++I)
- RewriteMethodDecl(*I);
-}
-
-void RewriteBlocks::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
- for (ObjCProtocolDecl::instmeth_iterator
- I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
- I != E; ++I)
- RewriteMethodDecl(*I);
- for (ObjCProtocolDecl::classmeth_iterator
- I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
- I != E; ++I)
- RewriteMethodDecl(*I);
-}
-
-//===----------------------------------------------------------------------===//
-// Top Level Driver Code
-//===----------------------------------------------------------------------===//
-
-void RewriteBlocks::HandleTopLevelSingleDecl(Decl *D) {
- // Two cases: either the decl could be in the main file, or it could be in a
- // #included file. If the former, rewrite it now. If the later, check to see
- // if we rewrote the #include/#import.
- SourceLocation Loc = D->getLocation();
- Loc = SM->getInstantiationLoc(Loc);
-
- // If this is for a builtin, ignore it.
- if (Loc.isInvalid()) return;
-
- if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D))
- RewriteInterfaceDecl(MD);
- else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D))
- RewriteCategoryDecl(CD);
- else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
- RewriteProtocolDecl(PD);
-
- // If we have a decl in the main file, see if we should rewrite it.
- if (SM->isFromMainFile(Loc))
- HandleDeclInMainFile(D);
- return;
-}
-
-std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i,
- const char *funcName,
- std::string Tag) {
- const FunctionType *AFT = CE->getFunctionType();
- QualType RT = AFT->getResultType();
- std::string StructRef = "struct " + Tag;
- std::string S = "static " + RT.getAsString() + " __" +
- funcName + "_" + "block_func_" + utostr(i);
-
- BlockDecl *BD = CE->getBlockDecl();
-
- if (isa<FunctionNoProtoType>(AFT)) {
- S += "()";
- } else if (BD->param_empty()) {
- S += "(" + StructRef + " *__cself)";
- } else {
- const FunctionProtoType *FT = cast<FunctionProtoType>(AFT);
- assert(FT && "SynthesizeBlockFunc: No function proto");
- S += '(';
- // first add the implicit argument.
- S += StructRef + " *__cself, ";
- std::string ParamStr;
- for (BlockDecl::param_iterator AI = BD->param_begin(),
- E = BD->param_end(); AI != E; ++AI) {
- if (AI != BD->param_begin()) S += ", ";
- ParamStr = (*AI)->getNameAsString();
- (*AI)->getType().getAsStringInternal(ParamStr, Context->PrintingPolicy);
- S += ParamStr;
- }
- if (FT->isVariadic()) {
- if (!BD->param_empty()) S += ", ";
- S += "...";
- }
- S += ')';
- }
- S += " {\n";
-
- // Create local declarations to avoid rewriting all closure decl ref exprs.
- // First, emit a declaration for all "by ref" decls.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
- E = BlockByRefDecls.end(); I != E; ++I) {
- S += " ";
- std::string Name = (*I)->getNameAsString();
- Context->getPointerType((*I)->getType()).getAsStringInternal(Name,
- Context->PrintingPolicy);
- S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
- }
- // Next, emit a declaration for all "by copy" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
- E = BlockByCopyDecls.end(); I != E; ++I) {
- S += " ";
- std::string Name = (*I)->getNameAsString();
- // Handle nested closure invocation. For example:
- //
- // void (^myImportedClosure)(void);
- // myImportedClosure = ^(void) { setGlobalInt(x + y); };
- //
- // void (^anotherClosure)(void);
- // anotherClosure = ^(void) {
- // myImportedClosure(); // import and invoke the closure
- // };
- //
- if (isBlockPointerType((*I)->getType()))
- S += "struct __block_impl *";
- else
- (*I)->getType().getAsStringInternal(Name, Context->PrintingPolicy);
- S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by copy\n";
- }
- std::string RewrittenStr = RewrittenBlockExprs[CE];
- const char *cstr = RewrittenStr.c_str();
- while (*cstr++ != '{') ;
- S += cstr;
- S += "\n";
- return S;
-}
-
-std::string RewriteBlocks::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
- const char *funcName,
- std::string Tag) {
- std::string StructRef = "struct " + Tag;
- std::string S = "static void __";
-
- S += funcName;
- S += "_block_copy_" + utostr(i);
- S += "(" + StructRef;
- S += "*dst, " + StructRef;
- S += "*src) {";
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
- E = ImportedBlockDecls.end(); I != E; ++I) {
- S += "_Block_copy_assign(&dst->";
- S += (*I)->getNameAsString();
- S += ", src->";
- S += (*I)->getNameAsString();
- S += ");}";
- }
- S += "\nstatic void __";
- S += funcName;
- S += "_block_dispose_" + utostr(i);
- S += "(" + StructRef;
- S += "*src) {";
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
- E = ImportedBlockDecls.end(); I != E; ++I) {
- S += "_Block_destroy(src->";
- S += (*I)->getNameAsString();
- S += ");";
- }
- S += "}\n";
- return S;
-}
-
-std::string RewriteBlocks::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
- bool hasCopyDisposeHelpers) {
- std::string S = "struct " + Tag;
- std::string Constructor = " " + Tag;
-
- S += " {\n struct __block_impl impl;\n";
-
- if (hasCopyDisposeHelpers)
- S += " void *copy;\n void *dispose;\n";
-
- Constructor += "(void *fp";
-
- if (hasCopyDisposeHelpers)
- Constructor += ", void *copyHelp, void *disposeHelp";
-
- if (BlockDeclRefs.size()) {
- // Output all "by copy" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
- E = BlockByCopyDecls.end(); I != E; ++I) {
- S += " ";
- std::string FieldName = (*I)->getNameAsString();
- std::string ArgName = "_" + FieldName;
- // Handle nested closure invocation. For example:
- //
- // void (^myImportedBlock)(void);
- // myImportedBlock = ^(void) { setGlobalInt(x + y); };
- //
- // void (^anotherBlock)(void);
- // anotherBlock = ^(void) {
- // myImportedBlock(); // import and invoke the closure
- // };
- //
- if (isBlockPointerType((*I)->getType())) {
- S += "struct __block_impl *";
- Constructor += ", void *" + ArgName;
- } else {
- (*I)->getType().getAsStringInternal(FieldName, Context->PrintingPolicy);
- (*I)->getType().getAsStringInternal(ArgName, Context->PrintingPolicy);
- Constructor += ", " + ArgName;
- }
- S += FieldName + ";\n";
- }
- // Output all "by ref" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
- E = BlockByRefDecls.end(); I != E; ++I) {
- S += " ";
- std::string FieldName = (*I)->getNameAsString();
- std::string ArgName = "_" + FieldName;
- // Handle nested closure invocation. For example:
- //
- // void (^myImportedBlock)(void);
- // myImportedBlock = ^(void) { setGlobalInt(x + y); };
- //
- // void (^anotherBlock)(void);
- // anotherBlock = ^(void) {
- // myImportedBlock(); // import and invoke the closure
- // };
- //
- if (isBlockPointerType((*I)->getType())) {
- S += "struct __block_impl *";
- Constructor += ", void *" + ArgName;
- } else {
- Context->getPointerType((*I)->getType()).getAsStringInternal(FieldName,
- Context->PrintingPolicy);
- Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName,
- Context->PrintingPolicy);
- Constructor += ", " + ArgName;
- }
- S += FieldName + "; // by ref\n";
- }
- // Finish writing the constructor.
- // FIXME: handle NSConcreteGlobalBlock.
- Constructor += ", int flags=0) {\n";
- Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof(";
- Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
-
- if (hasCopyDisposeHelpers)
- Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
-
- // Initialize all "by copy" arguments.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
- E = BlockByCopyDecls.end(); I != E; ++I) {
- std::string Name = (*I)->getNameAsString();
- Constructor += " ";
- if (isBlockPointerType((*I)->getType()))
- Constructor += Name + " = (struct __block_impl *)_";
- else
- Constructor += Name + " = _";
- Constructor += Name + ";\n";
- }
- // Initialize all "by ref" arguments.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
- E = BlockByRefDecls.end(); I != E; ++I) {
- std::string Name = (*I)->getNameAsString();
- Constructor += " ";
- if (isBlockPointerType((*I)->getType()))
- Constructor += Name + " = (struct __block_impl *)_";
- else
- Constructor += Name + " = _";
- Constructor += Name + ";\n";
- }
- } else {
- // Finish writing the constructor.
- // FIXME: handle NSConcreteGlobalBlock.
- Constructor += ", int flags=0) {\n";
- Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof(";
- Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
- if (hasCopyDisposeHelpers)
- Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
- }
- Constructor += " ";
- Constructor += "}\n";
- S += Constructor;
- S += "};\n";
- return S;
-}
-
-void RewriteBlocks::SynthesizeBlockLiterals(SourceLocation FunLocStart,
- const char *FunName) {
- // Insert closures that were part of the function.
- for (unsigned i = 0; i < Blocks.size(); i++) {
-
- CollectBlockDeclRefInfo(Blocks[i]);
-
- std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i);
-
- std::string CI = SynthesizeBlockImpl(Blocks[i], Tag,
- ImportedBlockDecls.size() > 0);
-
- InsertText(FunLocStart, CI.c_str(), CI.size());
-
- std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag);
-
- InsertText(FunLocStart, CF.c_str(), CF.size());
-
- if (ImportedBlockDecls.size()) {
- std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, Tag);
- InsertText(FunLocStart, HF.c_str(), HF.size());
- }
-
- BlockDeclRefs.clear();
- BlockByRefDecls.clear();
- BlockByCopyDecls.clear();
- BlockCallExprs.clear();
- ImportedBlockDecls.clear();
- }
- Blocks.clear();
- RewrittenBlockExprs.clear();
-}
-
-void RewriteBlocks::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
- SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
- const char *FuncName = FD->getNameAsCString();
-
- SynthesizeBlockLiterals(FunLocStart, FuncName);
-}
-
-void RewriteBlocks::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
- SourceLocation FunLocStart = MD->getLocStart();
- std::string FuncName = MD->getSelector().getAsString();
- // Convert colons to underscores.
- std::string::size_type loc = 0;
- while ((loc = FuncName.find(":", loc)) != std::string::npos)
- FuncName.replace(loc, 1, "_");
-
- SynthesizeBlockLiterals(FunLocStart, FuncName.c_str());
-}
-
-void RewriteBlocks::GetBlockDeclRefExprs(Stmt *S) {
- for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
- CI != E; ++CI)
- if (*CI) {
- if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI))
- GetBlockDeclRefExprs(CBE->getBody());
- else
- GetBlockDeclRefExprs(*CI);
- }
- // Handle specific things.
- if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S))
- // FIXME: Handle enums.
- if (!isa<FunctionDecl>(CDRE->getDecl()))
- BlockDeclRefs.push_back(CDRE);
- return;
-}
-
-void RewriteBlocks::GetBlockCallExprs(Stmt *S) {
- for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
- CI != E; ++CI)
- if (*CI) {
- if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI))
- GetBlockCallExprs(CBE->getBody());
- else
- GetBlockCallExprs(*CI);
- }
-
- if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
- if (CE->getCallee()->getType()->isBlockPointerType()) {
- BlockCallExprs[dyn_cast<BlockDeclRefExpr>(CE->getCallee())] = CE;
- }
- }
- return;
-}
-
-std::string RewriteBlocks::SynthesizeBlockCall(CallExpr *Exp) {
- // Navigate to relevant type information.
- const char *closureName = 0;
- const BlockPointerType *CPT = 0;
-
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp->getCallee())) {
- closureName = DRE->getDecl()->getNameAsCString();
- CPT = DRE->getType()->getAs<BlockPointerType>();
- } else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) {
- closureName = CDRE->getDecl()->getNameAsCString();
- CPT = CDRE->getType()->getAs<BlockPointerType>();
- } else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) {
- closureName = MExpr->getMemberDecl()->getNameAsCString();
- CPT = MExpr->getType()->getAs<BlockPointerType>();
- } else {
- assert(1 && "RewriteBlockClass: Bad type");
- }
- assert(CPT && "RewriteBlockClass: Bad type");
- const FunctionType *FT = CPT->getPointeeType()->getAs<FunctionType>();
- assert(FT && "RewriteBlockClass: Bad type");
- const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
- // FTP will be null for closures that don't take arguments.
-
- // Build a closure call - start with a paren expr to enforce precedence.
- std::string BlockCall = "(";
-
- // Synthesize the cast.
- BlockCall += "(" + Exp->getType().getAsString() + "(*)";
- BlockCall += "(struct __block_impl *";
- if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
- E = FTP->arg_type_end(); I && (I != E); ++I)
- BlockCall += ", " + (*I).getAsString();
- }
- BlockCall += "))"; // close the argument list and paren expression.
-
- // Invoke the closure. We need to cast it since the declaration type is
- // bogus (it's a function pointer type)
- BlockCall += "((struct __block_impl *)";
- std::string closureExprBufStr;
- llvm::raw_string_ostream closureExprBuf(closureExprBufStr);
- Exp->getCallee()->printPretty(closureExprBuf, *Context, 0,
- PrintingPolicy(LangOpts));
- BlockCall += closureExprBuf.str();
- BlockCall += ")->FuncPtr)";
-
- // Add the arguments.
- BlockCall += "((struct __block_impl *)";
- BlockCall += closureExprBuf.str();
- for (CallExpr::arg_iterator I = Exp->arg_begin(),
- E = Exp->arg_end(); I != E; ++I) {
- std::string syncExprBufS;
- llvm::raw_string_ostream Buf(syncExprBufS);
- (*I)->printPretty(Buf, *Context, 0, PrintingPolicy(LangOpts));
- BlockCall += ", " + Buf.str();
- }
- return BlockCall;
-}
-
-void RewriteBlocks::RewriteBlockCall(CallExpr *Exp) {
- std::string BlockCall = SynthesizeBlockCall(Exp);
-
- const char *startBuf = SM->getCharacterData(Exp->getLocStart());
- const char *endBuf = SM->getCharacterData(Exp->getLocEnd());
-
- ReplaceText(Exp->getLocStart(), endBuf-startBuf,
- BlockCall.c_str(), BlockCall.size());
-}
-
-void RewriteBlocks::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) {
- // FIXME: Add more elaborate code generation required by the ABI.
- InsertText(BDRE->getLocStart(), "*", 1);
-}
-
-void RewriteBlocks::RewriteCastExpr(CastExpr *CE) {
- SourceLocation LocStart = CE->getLocStart();
- SourceLocation LocEnd = CE->getLocEnd();
-
- if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd))
- return;
-
- const char *startBuf = SM->getCharacterData(LocStart);
- const char *endBuf = SM->getCharacterData(LocEnd);
-
- // advance the location to startArgList.
- const char *argPtr = startBuf;
-
- while (*argPtr++ && (argPtr < endBuf)) {
- switch (*argPtr) {
- case '^':
- // Replace the '^' with '*'.
- LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf);
- ReplaceText(LocStart, 1, "*", 1);
- break;
- }
- }
- return;
-}
-
-void RewriteBlocks::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
- SourceLocation DeclLoc = FD->getLocation();
- unsigned parenCount = 0;
-
- // We have 1 or more arguments that have closure pointers.
- const char *startBuf = SM->getCharacterData(DeclLoc);
- const char *startArgList = strchr(startBuf, '(');
-
- assert((*startArgList == '(') && "Rewriter fuzzy parser confused");
-
- parenCount++;
- // advance the location to startArgList.
- DeclLoc = DeclLoc.getFileLocWithOffset(startArgList-startBuf);
- assert((DeclLoc.isValid()) && "Invalid DeclLoc");
-
- const char *argPtr = startArgList;
-
- while (*argPtr++ && parenCount) {
- switch (*argPtr) {
- case '^':
- // Replace the '^' with '*'.
- DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList);
- ReplaceText(DeclLoc, 1, "*", 1);
- break;
- case '(':
- parenCount++;
- break;
- case ')':
- parenCount--;
- break;
- }
- }
- return;
-}
-
-bool RewriteBlocks::PointerTypeTakesAnyBlockArguments(QualType QT) {
- const FunctionProtoType *FTP;
- const PointerType *PT = QT->getAs<PointerType>();
- if (PT) {
- FTP = PT->getPointeeType()->getAs<FunctionProtoType>();
- } else {
- const BlockPointerType *BPT = QT->getAs<BlockPointerType>();
- assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
- FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();
- }
- if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
- E = FTP->arg_type_end(); I != E; ++I)
- if (isBlockPointerType(*I))
- return true;
- }
- return false;
-}
-
-void RewriteBlocks::GetExtentOfArgList(const char *Name,
- const char *&LParen, const char *&RParen) {
- const char *argPtr = strchr(Name, '(');
- assert((*argPtr == '(') && "Rewriter fuzzy parser confused");
-
- LParen = argPtr; // output the start.
- argPtr++; // skip past the left paren.
- unsigned parenCount = 1;
-
- while (*argPtr && parenCount) {
- switch (*argPtr) {
- case '(': parenCount++; break;
- case ')': parenCount--; break;
- default: break;
- }
- if (parenCount) argPtr++;
- }
- assert((*argPtr == ')') && "Rewriter fuzzy parser confused");
- RParen = argPtr; // output the end
-}
-
-void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
- RewriteBlockPointerFunctionArgs(FD);
- return;
- }
- // Handle Variables and Typedefs.
- SourceLocation DeclLoc = ND->getLocation();
- QualType DeclT;
- if (VarDecl *VD = dyn_cast<VarDecl>(ND))
- DeclT = VD->getType();
- else if (TypedefDecl *TDD = dyn_cast<TypedefDecl>(ND))
- DeclT = TDD->getUnderlyingType();
- else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND))
- DeclT = FD->getType();
- else
- assert(0 && "RewriteBlockPointerDecl(): Decl type not yet handled");
-
- const char *startBuf = SM->getCharacterData(DeclLoc);
- const char *endBuf = startBuf;
- // scan backward (from the decl location) for the end of the previous decl.
- while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart)
- startBuf--;
-
- // *startBuf != '^' if we are dealing with a pointer to function that
- // may take block argument types (which will be handled below).
- if (*startBuf == '^') {
- // Replace the '^' with '*', computing a negative offset.
- DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf);
- ReplaceText(DeclLoc, 1, "*", 1);
- }
- if (PointerTypeTakesAnyBlockArguments(DeclT)) {
- // Replace the '^' with '*' for arguments.
- DeclLoc = ND->getLocation();
- startBuf = SM->getCharacterData(DeclLoc);
- const char *argListBegin, *argListEnd;
- GetExtentOfArgList(startBuf, argListBegin, argListEnd);
- while (argListBegin < argListEnd) {
- if (*argListBegin == '^') {
- SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf);
- ReplaceText(CaretLoc, 1, "*", 1);
- }
- argListBegin++;
- }
- }
- return;
-}
-
-void RewriteBlocks::CollectBlockDeclRefInfo(BlockExpr *Exp) {
- // Add initializers for any closure decl refs.
- GetBlockDeclRefExprs(Exp->getBody());
- if (BlockDeclRefs.size()) {
- // Unique all "by copy" declarations.
- for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
- if (!BlockDeclRefs[i]->isByRef())
- BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl());
- // Unique all "by ref" declarations.
- for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
- if (BlockDeclRefs[i]->isByRef()) {
- BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl());
- }
- // Find any imported blocks...they will need special attention.
- for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
- if (isBlockPointerType(BlockDeclRefs[i]->getType())) {
- GetBlockCallExprs(Blocks[i]);
- ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl());
- }
- }
-}
-
-std::string RewriteBlocks::SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD) {
- Blocks.push_back(Exp);
-
- CollectBlockDeclRefInfo(Exp);
- std::string FuncName;
-
- if (CurFunctionDef)
- FuncName = std::string(CurFunctionDef->getNameAsString());
- else if (CurMethodDef) {
- FuncName = CurMethodDef->getSelector().getAsString();
- // Convert colons to underscores.
- std::string::size_type loc = 0;
- while ((loc = FuncName.find(":", loc)) != std::string::npos)
- FuncName.replace(loc, 1, "_");
- } else if (VD)
- FuncName = std::string(VD->getNameAsString());
-
- std::string BlockNumber = utostr(Blocks.size()-1);
-
- std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber;
- std::string Func = "__" + FuncName + "_block_func_" + BlockNumber;
-
- std::string FunkTypeStr;
-
- // Get a pointer to the function type so we can cast appropriately.
- Context->getPointerType(QualType(Exp->getFunctionType(),0))
- .getAsStringInternal(FunkTypeStr, Context->PrintingPolicy);
-
- // Rewrite the closure block with a compound literal. The first cast is
- // to prevent warnings from the C compiler.
- std::string Init = "(" + FunkTypeStr;
-
- Init += ")&" + Tag;
-
- // Initialize the block function.
- Init += "((void*)" + Func;
-
- if (ImportedBlockDecls.size()) {
- std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber;
- Init += ",(void*)" + Buf;
- Buf = "__" + FuncName + "_block_dispose_" + BlockNumber;
- Init += ",(void*)" + Buf;
- }
- // Add initializers for any closure decl refs.
- if (BlockDeclRefs.size()) {
- // Output all "by copy" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
- E = BlockByCopyDecls.end(); I != E; ++I) {
- Init += ",";
- if (isObjCType((*I)->getType())) {
- Init += "[[";
- Init += (*I)->getNameAsString();
- Init += " retain] autorelease]";
- } else if (isBlockPointerType((*I)->getType())) {
- Init += "(void *)";
- Init += (*I)->getNameAsString();
- } else {
- Init += (*I)->getNameAsString();
- }
- }
- // Output all "by ref" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
- E = BlockByRefDecls.end(); I != E; ++I) {
- Init += ",&";
- Init += (*I)->getNameAsString();
- }
- }
- Init += ")";
- BlockDeclRefs.clear();
- BlockByRefDecls.clear();
- BlockByCopyDecls.clear();
- ImportedBlockDecls.clear();
-
- return Init;
-}
-
-//===----------------------------------------------------------------------===//
-// Function Body / Expression rewriting
-//===----------------------------------------------------------------------===//
-
-Stmt *RewriteBlocks::RewriteFunctionBody(Stmt *S) {
- // Start by rewriting all children.
- for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
- CI != E; ++CI)
- if (*CI) {
- if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) {
- RewriteFunctionBody(CBE->getBody());
-
- // We've just rewritten the block body in place.
- // Now we snarf the rewritten text and stash it away for later use.
- std::string S = Rewrite.getRewritenText(CBE->getSourceRange());
- RewrittenBlockExprs[CBE] = S;
- std::string Init = SynthesizeBlockInitExpr(CBE);
- // Do the rewrite, using S.size() which contains the rewritten size.
- ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size());
- } else {
- RewriteFunctionBody(*CI);
- }
- }
- // Handle specific things.
- if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
- if (CE->getCallee()->getType()->isBlockPointerType())
- RewriteBlockCall(CE);
- }
- if (CastExpr *CE = dyn_cast<CastExpr>(S)) {
- RewriteCastExpr(CE);
- }
- if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
- for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
- DI != DE; ++DI) {
-
- Decl *SD = *DI;
- if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {
- if (isBlockPointerType(ND->getType()))
- RewriteBlockPointerDecl(ND);
- else if (ND->getType()->isFunctionPointerType())
- CheckFunctionPointerDecl(ND->getType(), ND);
- }
- if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
- if (isBlockPointerType(TD->getUnderlyingType()))
- RewriteBlockPointerDecl(TD);
- else if (TD->getUnderlyingType()->isFunctionPointerType())
- CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
- }
- }
- }
- // Handle specific things.
- if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
- if (BDRE->isByRef())
- RewriteBlockDeclRefExpr(BDRE);
- }
- // Return this stmt unmodified.
- return S;
-}
-
-void RewriteBlocks::RewriteFunctionProtoType(QualType funcType, NamedDecl *D) {
- if (FunctionProtoType *fproto = dyn_cast<FunctionProtoType>(funcType)) {
- for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(),
- E = fproto->arg_type_end(); I && (I != E); ++I)
- if (isBlockPointerType(*I)) {
- // All the args are checked/rewritten. Don't call twice!
- RewriteBlockPointerDecl(D);
- break;
- }
- }
-}
-
-void RewriteBlocks::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) {
- const PointerType *PT = funcType->getAs<PointerType>();
- if (PT && PointerTypeTakesAnyBlockArguments(funcType))
- RewriteFunctionProtoType(PT->getPointeeType(), ND);
-}
-
-/// HandleDeclInMainFile - This is called for each top-level decl defined in the
-/// main file of the input.
-void RewriteBlocks::HandleDeclInMainFile(Decl *D) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- // Since function prototypes don't have ParmDecl's, we check the function
- // prototype. This enables us to rewrite function declarations and
- // definitions using the same code.
- RewriteFunctionProtoType(FD->getType(), FD);
-
- // FIXME: Handle CXXTryStmt
- if (CompoundStmt *Body = FD->getCompoundBody()) {
- CurFunctionDef = FD;
- FD->setBody(cast_or_null<CompoundStmt>(RewriteFunctionBody(Body)));
- // This synthesizes and inserts the block "impl" struct, invoke function,
- // and any copy/dispose helper functions.
- InsertBlockLiteralsWithinFunction(FD);
- CurFunctionDef = 0;
- }
- return;
- }
- if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- RewriteMethodDecl(MD);
- if (Stmt *Body = MD->getBody()) {
- CurMethodDef = MD;
- RewriteFunctionBody(Body);
- InsertBlockLiteralsWithinMethod(MD);
- CurMethodDef = 0;
- }
- }
- if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
- if (isBlockPointerType(VD->getType())) {
- RewriteBlockPointerDecl(VD);
- if (VD->getInit()) {
- if (BlockExpr *CBE = dyn_cast<BlockExpr>(VD->getInit())) {
- RewriteFunctionBody(CBE->getBody());
-
- // We've just rewritten the block body in place.
- // Now we snarf the rewritten text and stash it away for later use.
- std::string S = Rewrite.getRewritenText(CBE->getSourceRange());
- RewrittenBlockExprs[CBE] = S;
- std::string Init = SynthesizeBlockInitExpr(CBE, VD);
- // Do the rewrite, using S.size() which contains the rewritten size.
- ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size());
- SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(),
- VD->getNameAsCString());
- } else if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
- RewriteCastExpr(CE);
- }
- }
- } else if (VD->getType()->isFunctionPointerType()) {
- CheckFunctionPointerDecl(VD->getType(), VD);
- if (VD->getInit()) {
- if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
- RewriteCastExpr(CE);
- }
- }
- }
- return;
- }
- if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
- if (isBlockPointerType(TD->getUnderlyingType()))
- RewriteBlockPointerDecl(TD);
- else if (TD->getUnderlyingType()->isFunctionPointerType())
- CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
- return;
- }
- if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
- if (RD->isDefinition()) {
- for (RecordDecl::field_iterator i = RD->field_begin(),
- e = RD->field_end(); i != e; ++i) {
- FieldDecl *FD = *i;
- if (isBlockPointerType(FD->getType()))
- RewriteBlockPointerDecl(FD);
- }
- }
- return;
- }
-}
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index df85c13..c347472 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -30,6 +30,28 @@ using llvm::utostr;
namespace {
class RewriteObjC : public ASTConsumer {
+ enum {
+ BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)),
+ block, ... */
+ BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */
+ BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the
+ __block variable */
+ BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy
+ helpers */
+ BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose
+ support routines */
+ BLOCK_BYREF_CURRENT_MAX = 256
+ };
+
+ enum {
+ BLOCK_NEEDS_FREE = (1 << 24),
+ BLOCK_HAS_COPY_DISPOSE = (1 << 25),
+ BLOCK_HAS_CXX_OBJ = (1 << 26),
+ BLOCK_IS_GC = (1 << 27),
+ BLOCK_IS_GLOBAL = (1 << 28),
+ BLOCK_HAS_DESCRIPTOR = (1 << 29)
+ };
+
Rewriter Rewrite;
Diagnostic &Diags;
const LangOptions &LangOpts;
@@ -324,6 +346,7 @@ namespace {
// Block specific rewrite rules.
void RewriteBlockCall(CallExpr *Exp);
void RewriteBlockPointerDecl(NamedDecl *VD);
+ void RewriteByRefVar(VarDecl *VD);
Stmt *RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD);
void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
@@ -337,7 +360,7 @@ namespace {
std::string ImplTag,
int i, const char *funcName,
unsigned hasCopy);
- Stmt *SynthesizeBlockCall(CallExpr *Exp);
+ Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp);
void SynthesizeBlockLiterals(SourceLocation FunLocStart,
const char *FunName);
void RewriteRecordBody(RecordDecl *RD);
@@ -565,8 +588,8 @@ void RewriteObjC::Initialize(ASTContext &context) {
Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n";
Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n";
Preamble += "#else\n";
- Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT \"C\" void _Block_object_assign(void *, const void *, const int);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT \"C\" void _Block_object_dispose(const void *, const int);\n";
Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n";
Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n";
Preamble += "#endif\n";
@@ -576,6 +599,8 @@ void RewriteObjC::Initialize(ASTContext &context) {
Preamble += "#undef __OBJC_RW_STATICIMPORT\n";
Preamble += "#define __attribute__(X)\n";
}
+ else
+ Preamble += "#define __block\n";
}
@@ -3731,8 +3756,8 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
E = BlockByRefDecls.end(); I != E; ++I) {
S += " ";
std::string Name = (*I)->getNameAsString();
- Context->getPointerType((*I)->getType()).getAsStringInternal(Name,
- Context->PrintingPolicy);
+ std::string TypeString = "struct __Block_byref_" + Name + " *";
+ Name = TypeString + Name;
S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
}
// Next, emit a declaration for all "by copy" declarations.
@@ -3781,8 +3806,13 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
S += (*I)->getNameAsString();
S += ", (void*)src->";
S += (*I)->getNameAsString();
- S += ", 3/*BLOCK_FIELD_IS_OBJECT*/);}";
+ if (BlockByRefDecls.count((*I)))
+ S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
+ else
+ S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";
}
+ S += "}\n";
+
S += "\nstatic void __";
S += funcName;
S += "_block_dispose_" + utostr(i);
@@ -3792,7 +3822,10 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
E = ImportedBlockDecls.end(); I != E; ++I) {
S += "_Block_object_dispose((void*)src->";
S += (*I)->getNameAsString();
- S += ", 3/*BLOCK_FIELD_IS_OBJECT*/);";
+ if (BlockByRefDecls.count((*I)))
+ S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
+ else
+ S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";
}
S += "}\n";
return S;
@@ -3858,10 +3891,10 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
S += "struct __block_impl *";
Constructor += ", void *" + ArgName;
} else {
- Context->getPointerType((*I)->getType()).getAsStringInternal(FieldName,
- Context->PrintingPolicy);
- Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName,
- Context->PrintingPolicy);
+ std::string TypeString = "struct __Block_byref_" + FieldName;
+ TypeString += " *";
+ FieldName = TypeString + FieldName;
+ ArgName = TypeString + ArgName;
Constructor += ", " + ArgName;
}
S += FieldName + "; // by ref\n";
@@ -3896,7 +3929,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Constructor += Name + " = (struct __block_impl *)_";
else
Constructor += Name + " = _";
- Constructor += Name + ";\n";
+ Constructor += Name + "->__forwarding;\n";
}
} else {
// Finish writing the constructor.
@@ -3924,7 +3957,12 @@ std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag,
S += " {\n unsigned long reserved;\n";
S += " unsigned long Block_size;\n";
if (hasCopy) {
- S += " void *copy;\n void *dispose;\n";
+ S += " void (*copy)(struct ";
+ S += ImplTag; S += "*, struct ";
+ S += ImplTag; S += "*);\n";
+
+ S += " void (*dispose)(struct ";
+ S += ImplTag; S += "*);\n";
}
S += "} ";
@@ -4030,20 +4068,38 @@ void RewriteObjC::GetBlockCallExprs(Stmt *S) {
return;
}
-Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp) {
+Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
// Navigate to relevant type information.
- const char *closureName = 0;
const BlockPointerType *CPT = 0;
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp->getCallee())) {
- closureName = DRE->getDecl()->getNameAsCString();
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BlockExp)) {
CPT = DRE->getType()->getAs<BlockPointerType>();
- } else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) {
- closureName = CDRE->getDecl()->getNameAsCString();
+ } else if (const BlockDeclRefExpr *CDRE =
+ dyn_cast<BlockDeclRefExpr>(BlockExp)) {
CPT = CDRE->getType()->getAs<BlockPointerType>();
- } else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) {
- closureName = MExpr->getMemberDecl()->getNameAsCString();
+ } else if (const MemberExpr *MExpr = dyn_cast<MemberExpr>(BlockExp)) {
CPT = MExpr->getType()->getAs<BlockPointerType>();
+ }
+ else if (const ParenExpr *PRE = dyn_cast<ParenExpr>(BlockExp)) {
+ return SynthesizeBlockCall(Exp, PRE->getSubExpr());
+ }
+ else if (const ImplicitCastExpr *IEXPR = dyn_cast<ImplicitCastExpr>(BlockExp))
+ CPT = IEXPR->getType()->getAs<BlockPointerType>();
+ else if (const ConditionalOperator *CEXPR =
+ dyn_cast<ConditionalOperator>(BlockExp)) {
+ Expr *LHSExp = CEXPR->getLHS();
+ Stmt *LHSStmt = SynthesizeBlockCall(Exp, LHSExp);
+ Expr *RHSExp = CEXPR->getRHS();
+ Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp);
+ Expr *CONDExp = CEXPR->getCond();
+ ConditionalOperator *CondExpr =
+ new (Context) ConditionalOperator(CONDExp,
+ SourceLocation(), cast<Expr>(LHSStmt),
+ SourceLocation(), cast<Expr>(RHSStmt),
+ Exp->getType());
+ return CondExpr;
+ } else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) {
+ CPT = IRE->getType()->getAs<BlockPointerType>();
} else {
assert(1 && "RewriteBlockClass: Bad type");
}
@@ -4083,7 +4139,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp) {
CastExpr *BlkCast = new (Context) CStyleCastExpr(PtrBlock,
CastExpr::CK_Unknown,
- Exp->getCallee(),
+ const_cast<Expr*>(BlockExp),
PtrBlock, SourceLocation(),
SourceLocation());
// Don't forget the parens to enforce the proper binding.
@@ -4119,7 +4175,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp) {
}
void RewriteObjC::RewriteBlockCall(CallExpr *Exp) {
- Stmt *BlockCall = SynthesizeBlockCall(Exp);
+ Stmt *BlockCall = SynthesizeBlockCall(Exp, Exp->getCallee());
ReplaceStmt(Exp, BlockCall);
}
@@ -4137,12 +4193,27 @@ void RewriteObjC::RewriteBlockCall(CallExpr *Exp) {
// };
//}
Stmt *RewriteObjC::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) {
- // FIXME: Add more elaborate code generation required by the ABI.
- Expr *DerefExpr = new (Context) UnaryOperator(BDRE, UnaryOperator::Deref,
- Context->getPointerType(BDRE->getType()),
- SourceLocation());
+ // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR
+ // for each BDRE where BYREFVAR is name of the variable.
+ FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ &Context->Idents.get("__forwarding"),
+ Context->VoidPtrTy, 0,
+ /*BitWidth=*/0, /*Mutable=*/true);
+ MemberExpr *ME = new (Context) MemberExpr(BDRE, true, FD, SourceLocation(),
+ FD->getType());
+ const char *Name = BDRE->getDecl()->getNameAsCString();
+ FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ &Context->Idents.get(Name),
+ Context->VoidPtrTy, 0,
+ /*BitWidth=*/0, /*Mutable=*/true);
+ ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
+ BDRE->getType());
+
+
+
// Need parens to enforce precedence.
- ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), DerefExpr);
+ ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
+ ME);
ReplaceStmt(BDRE, PE);
return PE;
}
@@ -4298,6 +4369,94 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
return;
}
+/// RewriteByRefVar - For each __block typex ND variable this routine transforms
+/// the declaration into:
+/// struct __Block_byref_ND {
+/// void *__isa; // NULL for everything except __weak pointers
+/// struct __Block_byref_ND *__forwarding;
+/// int32_t __flags;
+/// int32_t __size;
+/// void *__ByrefKeepFuncPtr; // Only if variable is __block ObjC object
+/// void *__ByrefDestroyFuncPtr; // Only if variable is __block ObjC object
+/// typex ND;
+/// };
+///
+/// It then replaces declaration of ND variable with:
+/// struct __Block_byref_ND ND = {__isa=0B, __forwarding=&ND, __flags=some_flag,
+/// __size=sizeof(struct __Block_byref_ND),
+/// ND=initializer-if-any};
+///
+///
+void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
+ SourceLocation DeclLoc = ND->getTypeSpecStartLoc();
+ const char *startBuf = SM->getCharacterData(DeclLoc);
+ SourceLocation X = ND->getLocEnd();
+ X = SM->getInstantiationLoc(X);
+ const char *endBuf = SM->getCharacterData(X);
+ std::string Name(ND->getNameAsString());
+ std::string ByrefType = "struct __Block_byref_";
+ ByrefType += Name;
+ ByrefType += " {\n";
+ ByrefType += " void *__isa;\n";
+ ByrefType += " struct __Block_byref_" + Name + " *__forwarding;\n";
+ ByrefType += " int __flags;\n";
+ ByrefType += " int __size;\n";
+ // FIXME. Add void *__ByrefKeepFuncPtr; void *__ByrefDestroyFuncPtr;
+ // if needed.
+ ND->getType().getAsStringInternal(Name, Context->PrintingPolicy);
+ ByrefType += " " + Name + ";\n";
+ ByrefType += "};\n";
+ // Insert this type in global scope. It is needed by helper function.
+ assert(CurFunctionDef && "RewriteByRefVar - CurFunctionDef is null");
+ SourceLocation FunLocStart = CurFunctionDef->getTypeSpecStartLoc();
+ InsertText(FunLocStart, ByrefType.c_str(), ByrefType.size());
+
+ // struct __Block_byref_ND ND =
+ // {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND),
+ // initializer-if-any};
+ bool hasInit = (ND->getInit() != 0);
+ Name = ND->getNameAsString();
+ ByrefType = "struct __Block_byref_" + Name;
+ if (!hasInit) {
+ ByrefType += " " + Name + " = ";
+ ByrefType += "{0, &" + Name + ", ";
+ // FIXME. Compute the flag.
+ ByrefType += "0, ";
+ ByrefType += "sizeof(struct __Block_byref_" + Name + ")";
+ ByrefType += "};\n";
+ ReplaceText(DeclLoc, endBuf-startBuf+Name.size(),
+ ByrefType.c_str(), ByrefType.size());
+ }
+ else {
+ SourceLocation startLoc = ND->getInit()->getLocStart();
+ ByrefType += " " + Name;
+ ReplaceText(DeclLoc, endBuf-startBuf,
+ ByrefType.c_str(), ByrefType.size());
+ ByrefType = " = {0, &" + Name + ", ";
+ // FIXME. Compute the flag.
+ ByrefType += "0, ";
+ ByrefType += "sizeof(struct __Block_byref_" + Name + "), ";
+ InsertText(startLoc, ByrefType.c_str(), ByrefType.size());
+
+ // Complete the newly synthesized compound expression by inserting a right
+ // curly brace before the end of the declaration.
+ // FIXME: This approach avoids rewriting the initializer expression. It
+ // also assumes there is only one declarator. For example, the following
+ // isn't currently supported by this routine (in general):
+ //
+ // double __block BYREFVAR = 1.34, BYREFVAR2 = 1.37;
+ //
+ const char *startBuf = SM->getCharacterData(startLoc);
+ const char *semiBuf = strchr(startBuf, ';');
+ assert((*semiBuf == ';') && "RewriteByRefVar: can't find ';'");
+ SourceLocation semiLoc =
+ startLoc.getFileLocWithOffset(semiBuf-startBuf);
+
+ InsertText(semiLoc, "}", 1);
+ }
+ return;
+}
+
void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
// Add initializers for any closure decl refs.
GetBlockDeclRefExprs(Exp->getBody());
@@ -4313,7 +4472,9 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
}
// Find any imported blocks...they will need special attention.
for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
- if (BlockDeclRefs[i]->getType()->isBlockPointerType()) {
+ if (BlockDeclRefs[i]->isByRef() ||
+ BlockDeclRefs[i]->getType()->isObjCObjectPointerType() ||
+ BlockDeclRefs[i]->getType()->isBlockPointerType()) {
GetBlockCallExprs(BlockDeclRefs[i]);
ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl());
}
@@ -4422,16 +4583,14 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
InitExprs.push_back(Exp);
}
}
- if (ImportedBlockDecls.size()) { // generate "1<<25" to indicate we have helper functions.
+ if (ImportedBlockDecls.size()) {
+ // generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR
+ int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR);
unsigned IntSize =
static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
- BinaryOperator *Exp = new (Context) BinaryOperator(
- new (Context) IntegerLiteral(llvm::APInt(IntSize, 1),
- Context->IntTy,SourceLocation()),
- new (Context) IntegerLiteral(llvm::APInt(IntSize, 25),
- Context->IntTy, SourceLocation()),
- BinaryOperator::Shl, Context->IntTy, SourceLocation());
- InitExprs.push_back(Exp);
+ Expr *FlagExp = new (Context) IntegerLiteral(llvm::APInt(IntSize, flag),
+ Context->IntTy, SourceLocation());
+ InitExprs.push_back(FlagExp);
}
NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(),
FType, SourceLocation());
@@ -4479,7 +4638,8 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
Stmts.push_back(S);
else if (isa<ObjCForCollectionStmt>(S)) {
Stmts.push_back(S);
- ObjCBcLabelNo.push_back(++BcLabelCount);
+ ++BcLabelCount;
+ ObjCBcLabelNo.push_back(BcLabelCount);
}
SourceRange OrigStmtRange = S->getSourceRange();
@@ -4640,6 +4800,9 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
RewriteBlockPointerDecl(ND);
else if (ND->getType()->isFunctionPointerType())
CheckFunctionPointerDecl(ND->getType(), ND);
+ if (VarDecl *VD = dyn_cast<VarDecl>(SD))
+ if (VD->hasAttr<BlocksAttr>())
+ RewriteByRefVar(VD);
}
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
@@ -4668,7 +4831,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
}
if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
if (CE->getCallee()->getType()->isBlockPointerType()) {
- Stmt *BlockCall = SynthesizeBlockCall(CE);
+ Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee());
ReplaceStmt(S, BlockCall);
return BlockCall;
}
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
index ff44c90..4bf507d 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Frontend/Warnings.cpp
@@ -13,12 +13,12 @@
//
// This file is responsible for handling all warning options. This includes
// a number of -Wfoo options and their variants, which are driven by TableGen-
-// generated data, and the special cases -pedantic, -pedantic-errors, -w and
-// -Werror.
+// generated data, and the special cases -pedantic, -pedantic-errors, -w,
+// -Werror and -Wfatal-errors.
//
// Each warning option controls any number of actual warnings.
// Given a warning option 'foo', the following are valid:
-// -Wfoo, -Wno-foo, -Werror=foo
+// -Wfoo, -Wno-foo, -Werror=foo, -Wfatal-errors=foo
//
#include "clang/Frontend/Utils.h"
#include "clang/Basic/Diagnostic.h"
@@ -26,7 +26,6 @@
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
-#include <cstdio>
#include <cstring>
#include <utility>
#include <algorithm>
@@ -47,8 +46,6 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags,
else
Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore);
- // FIXME: -Wfatal-errors / -Wfatal-errors=foo
-
for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {
const std::string &Opt = Opts.Warnings[i];
const char *OptStart = &Opt[0];
@@ -81,8 +78,8 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags,
if (OptEnd-OptStart != 5) { // Specifier must be present.
if ((OptStart[5] != '=' && OptStart[5] != '-') ||
OptEnd-OptStart == 6) {
- fprintf(stderr, "warning: unknown -Werror warning specifier: -W%s\n",
- Opt.c_str());
+ Diags.Report(diag::warn_unknown_warning_specifier)
+ << "-Werror" << ("-W" + Opt);
continue;
}
Specifier = OptStart+6;
@@ -98,6 +95,30 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags,
OptStart = 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) {
+ Diags.Report(diag::warn_unknown_warning_specifier)
+ << "-Wfatal-errors" << ("-W" + Opt);
+ continue;
+ }
+ Specifier = OptStart + 13;
+ }
+
+ if (Specifier == 0) {
+ Diags.setErrorsAsFatal(isPositive);
+ continue;
+ }
+
+ // -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;
+ }
+
if (Diags.setDiagnosticGroupMapping(OptStart, Mapping))
Diags.Report(diag::warn_unknown_warning_option) << ("-W" + Opt);
}
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index a91e404..d5a4643 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -33,7 +33,7 @@
#include <cctype>
using namespace clang;
-static void InitCharacterInfo(LangOptions);
+static void InitCharacterInfo();
//===----------------------------------------------------------------------===//
// Token Class Implementation
@@ -59,7 +59,7 @@ tok::ObjCKeywordKind Token::getObjCKeywordID() const {
void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
const char *BufEnd) {
- InitCharacterInfo(Features);
+ InitCharacterInfo();
BufferStart = BufStart;
BufferPtr = BufPtr;
@@ -254,7 +254,7 @@ enum {
// Statically initialize CharInfo table based on ASCII character set
// Reference: FreeBSD 7.2 /usr/share/misc/ascii
-static unsigned char CharInfo[256] =
+static const unsigned char CharInfo[256] =
{
// 0 NUL 1 SOH 2 STX 3 ETX
// 4 EOT 5 ENQ 6 ACK 7 BEL
@@ -322,7 +322,7 @@ static unsigned char CharInfo[256] =
0 , 0 , 0 , 0
};
-static void InitCharacterInfo(LangOptions Features) {
+static void InitCharacterInfo() {
static bool isInited = false;
if (isInited) return;
// check the statically-initialized CharInfo table
@@ -341,10 +341,6 @@ static void InitCharacterInfo(LangOptions Features) {
for (unsigned i = '0'; i <= '9'; ++i)
assert(CHAR_NUMBER == CharInfo[i]);
- if (Features.Microsoft)
- // Hack to treat DOS & CP/M EOF (^Z) as horizontal whitespace.
- CharInfo[26/*sub*/] = CHAR_HORZ_WS;
-
isInited = true;
}
@@ -1549,6 +1545,22 @@ LexNextToken:
return; // KeepWhitespaceMode
goto LexNextToken; // GCC isn't tail call eliminating.
+
+ case 26: // DOS & CP/M EOF: "^Z".
+ // If we're in Microsoft extensions mode, treat this as end of file.
+ if (Features.Microsoft) {
+ // Read the PP instance variable into an automatic variable, because
+ // LexEndOfFile will often delete 'this'.
+ Preprocessor *PPCache = PP;
+ if (LexEndOfFile(Result, CurPtr-1)) // Retreat back into the file.
+ return; // Got a token to return.
+ assert(PPCache && "Raw buffer::LexEndOfFile should return a token");
+ return PPCache->Lex(Result);
+ }
+ // If Microsoft extensions are disabled, this is just random garbage.
+ Kind = tok::unknown;
+ break;
+
case '\n':
case '\r':
// If we are inside a preprocessor directive and we see the end of line,
@@ -1599,7 +1611,7 @@ LexNextToken:
goto SkipHorizontalWhitespace;
}
goto LexNextToken; // GCC isn't tail call eliminating.
-
+
// C99 6.4.4.1: Integer Constants.
// C99 6.4.4.2: Floating Constants.
case '0': case '1': case '2': case '3': case '4':
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index ab66942..9aaa82d 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -610,28 +610,14 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
return OverflowOccurred;
}
-llvm::APFloat NumericLiteralParser::
-GetFloatValue(const llvm::fltSemantics &Format, bool* isExact) {
+llvm::APFloat::opStatus
+NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) {
using llvm::APFloat;
using llvm::StringRef;
- llvm::SmallVector<char,256> floatChars;
unsigned n = std::min(SuffixBegin - ThisTokBegin, ThisTokEnd - ThisTokBegin);
- for (unsigned i = 0; i != n; ++i)
- floatChars.push_back(ThisTokBegin[i]);
-
- floatChars.push_back('\0');
-
- APFloat V (Format, APFloat::fcZero, false);
- APFloat::opStatus status;
-
- status = V.convertFromString(StringRef(&floatChars[0], n),
- APFloat::rmNearestTiesToEven);
-
- if (isExact)
- *isExact = status == APFloat::opOK;
-
- return V;
+ return Result.convertFromString(StringRef(ThisTokBegin, n),
+ APFloat::rmNearestTiesToEven);
}
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index 376cce8..2f1a34c 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -24,12 +24,37 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI,
Preprocessor &PP) {
assert(MI->isFunctionLike() &&
"Can't have args for an object-like macro!");
-
- // Allocate memory for the MacroArgs object with the lexer tokens at the end.
- MacroArgs *Result = (MacroArgs*)malloc(sizeof(MacroArgs) +
- NumToks*sizeof(Token));
- // Construct the macroargs object.
- new (Result) MacroArgs(NumToks, VarargsElided);
+ MacroArgs **ResultEnt = 0;
+ unsigned ClosestMatch = ~0U;
+
+ // See if we have an entry with a big enough argument list to reuse on the
+ // free list. If so, reuse it.
+ for (MacroArgs **Entry = &PP.MacroArgCache; *Entry;
+ Entry = &(*Entry)->ArgCache)
+ if ((*Entry)->NumUnexpArgTokens >= NumToks &&
+ (*Entry)->NumUnexpArgTokens < ClosestMatch) {
+ ResultEnt = Entry;
+
+ // If we have an exact match, use it.
+ if ((*Entry)->NumUnexpArgTokens == NumToks)
+ break;
+ // Otherwise, use the best fit.
+ ClosestMatch = (*Entry)->NumUnexpArgTokens;
+ }
+
+ MacroArgs *Result;
+ if (ResultEnt == 0) {
+ // Allocate memory for a MacroArgs object with the lexer tokens at the end.
+ Result = (MacroArgs*)malloc(sizeof(MacroArgs) + NumToks*sizeof(Token));
+ // Construct the MacroArgs object.
+ new (Result) MacroArgs(NumToks, VarargsElided);
+ } else {
+ Result = *ResultEnt;
+ // Unlink this node from the preprocessors singly linked list.
+ *ResultEnt = Result->ArgCache;
+ Result->NumUnexpArgTokens = NumToks;
+ Result->VarargsElided = VarargsElided;
+ }
// Copy the actual unexpanded tokens to immediately after the result ptr.
if (NumToks)
@@ -42,10 +67,16 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI,
/// destroy - Destroy and deallocate the memory for this object.
///
void MacroArgs::destroy(Preprocessor &PP) {
- // Run the dtor to deallocate the vectors.
- this->~MacroArgs();
- // Release the memory for the object.
- free(this);
+ StringifiedArgs.clear();
+
+ // Don't clear PreExpArgTokens, just clear the entries. Clearing the entries
+ // would deallocate the element vectors.
+ for (unsigned i = 0, e = PreExpArgTokens.size(); i != e; ++i)
+ PreExpArgTokens[i].clear();
+
+ // Add this to the preprocessor's free list.
+ ArgCache = PP.MacroArgCache;
+ PP.MacroArgCache = this;
}
/// deallocate - This should only be called by the Preprocessor when managing
@@ -110,13 +141,14 @@ bool MacroArgs::ArgNeedsPreexpansion(const Token *ArgTok,
/// getPreExpArgument - Return the pre-expanded form of the specified
/// argument.
const std::vector<Token> &
-MacroArgs::getPreExpArgument(unsigned Arg, Preprocessor &PP) {
- assert(Arg < NumUnexpArgTokens && "Invalid argument number!");
+MacroArgs::getPreExpArgument(unsigned Arg, const MacroInfo *MI,
+ Preprocessor &PP) {
+ assert(Arg < MI->getNumArgs() && "Invalid argument number!");
// If we have already computed this, return it.
- if (PreExpArgTokens.empty())
- PreExpArgTokens.resize(NumUnexpArgTokens);
-
+ if (PreExpArgTokens.size() < MI->getNumArgs())
+ PreExpArgTokens.resize(MI->getNumArgs());
+
std::vector<Token> &Result = PreExpArgTokens[Arg];
if (!Result.empty()) return Result;
@@ -156,7 +188,7 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
Preprocessor &PP, bool Charify) {
Token Tok;
Tok.startToken();
- Tok.setKind(tok::string_literal);
+ Tok.setKind(Charify ? tok::char_constant : tok::string_literal);
const Token *ArgTokStart = ArgToks;
diff --git a/lib/Lex/MacroArgs.h b/lib/Lex/MacroArgs.h
index fa040c7..6ff4856 100644
--- a/lib/Lex/MacroArgs.h
+++ b/lib/Lex/MacroArgs.h
@@ -82,7 +82,7 @@ public:
/// getPreExpArgument - Return the pre-expanded form of the specified
/// argument.
const std::vector<Token> &
- getPreExpArgument(unsigned Arg, Preprocessor &PP);
+ getPreExpArgument(unsigned Arg, const MacroInfo *MI, Preprocessor &PP);
/// getStringifiedArgument - Compute, cache, and return the specified argument
/// that has been 'stringified' as required by the # operator.
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index f5c60eb..9e3d283 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -220,32 +220,28 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// Get the identifier name without trigraphs or embedded newlines. Note
// that we can't use Tok.getIdentifierInfo() because its lookup is disabled
// when skipping.
- // TODO: could do this with zero copies in the no-clean case by using
- // strncmp below.
- char Directive[20];
- unsigned IdLen;
+ char DirectiveBuf[20];
+ llvm::StringRef Directive;
if (!Tok.needsCleaning() && Tok.getLength() < 20) {
- IdLen = Tok.getLength();
- memcpy(Directive, RawCharData, IdLen);
- Directive[IdLen] = 0;
+ Directive = llvm::StringRef(RawCharData, Tok.getLength());
} else {
std::string DirectiveStr = getSpelling(Tok);
- IdLen = DirectiveStr.size();
+ unsigned IdLen = DirectiveStr.size();
if (IdLen >= 20) {
CurPPLexer->ParsingPreprocessorDirective = false;
// Restore comment saving mode.
if (CurLexer) CurLexer->SetCommentRetentionState(KeepComments);
continue;
}
- memcpy(Directive, &DirectiveStr[0], IdLen);
- Directive[IdLen] = 0;
- FirstChar = Directive[0];
+ memcpy(DirectiveBuf, &DirectiveStr[0], IdLen);
+ Directive = llvm::StringRef(DirectiveBuf, IdLen);
}
- if (FirstChar == 'i' && Directive[1] == 'f') {
- if ((IdLen == 2) || // "if"
- (IdLen == 5 && !strcmp(Directive+2, "def")) || // "ifdef"
- (IdLen == 6 && !strcmp(Directive+2, "ndef"))) { // "ifndef"
+ if (Directive.startswith("if")) {
+ llvm::StringRef Sub = Directive.substr(2);
+ if (Sub.empty() || // "if"
+ Sub == "def" || // "ifdef"
+ Sub == "ndef") { // "ifndef"
// We know the entire #if/#ifdef/#ifndef block will be skipped, don't
// bother parsing the condition.
DiscardUntilEndOfDirective();
@@ -253,8 +249,9 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
/*foundnonskip*/false,
/*fnddelse*/false);
}
- } else if (FirstChar == 'e') {
- if (IdLen == 5 && !strcmp(Directive+1, "ndif")) { // "endif"
+ } else if (Directive[0] == 'e') {
+ llvm::StringRef Sub = Directive.substr(1);
+ if (Sub == "ndif") { // "endif"
CheckEndOfDirective("endif");
PPConditionalInfo CondInfo;
CondInfo.WasSkipping = true; // Silence bogus warning.
@@ -265,7 +262,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// If we popped the outermost skipping block, we're done skipping!
if (!CondInfo.WasSkipping)
break;
- } else if (IdLen == 4 && !strcmp(Directive+1, "lse")) { // "else".
+ } else if (Sub == "lse") { // "else".
// #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.
@@ -284,7 +281,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
CondInfo.FoundNonSkip = true;
break;
}
- } else if (IdLen == 4 && !strcmp(Directive+1, "lif")) { // "elif".
+ } else if (Sub == "lif") { // "elif".
PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel();
bool ShouldEnter;
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index d4e441b..81966cb 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -446,19 +446,10 @@ void Preprocessor::EnterMainSourceFile() {
if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID))
HeaderInfo.IncrementIncludeCount(FE);
- std::vector<char> PrologFile;
- PrologFile.reserve(4080);
-
- // FIXME: Don't make a copy.
- PrologFile.insert(PrologFile.end(), Predefines.begin(), Predefines.end());
-
- // Memory buffer must end with a null byte!
- PrologFile.push_back(0);
-
- // Now that we have emitted the predefined macros, #includes, etc into
- // PrologFile, preprocess it to populate the initial preprocessor state.
+ // Preprocess Predefines to populate the initial preprocessor state.
llvm::MemoryBuffer *SB =
- llvm::MemoryBuffer::getMemBufferCopy(&PrologFile.front(),&PrologFile.back(),
+ llvm::MemoryBuffer::getMemBufferCopy(Predefines.data(),
+ Predefines.data() + Predefines.size(),
"<built-in>");
assert(SB && "Cannot fail to create predefined source buffer");
FileID FID = SourceMgr.createFileIDForMemBuffer(SB);
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index a40bb62..5d95eb3 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -175,7 +175,7 @@ void TokenLexer::ExpandFunctionArguments() {
// avoids some work in common cases.
const Token *ArgTok = ActualArgs->getUnexpArgument(ArgNo);
if (ActualArgs->ArgNeedsPreexpansion(ArgTok, PP))
- ResultArgToks = &ActualArgs->getPreExpArgument(ArgNo, PP)[0];
+ ResultArgToks = &ActualArgs->getPreExpArgument(ArgNo, Macro, PP)[0];
else
ResultArgToks = ArgTok; // Use non-preexpanded tokens.
@@ -414,7 +414,7 @@ bool TokenLexer::PasteTokens(Token &Tok) {
ResultTokTmp.startToken();
// Claim that the tmp token is a string_literal so that we can get the
- // character pointer back from CreateString.
+ // character pointer back from CreateString in getLiteralData().
ResultTokTmp.setKind(tok::string_literal);
PP.CreateString(&Buffer[0], Buffer.size(), ResultTokTmp);
SourceLocation ResultTokLoc = ResultTokTmp.getLocation();
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index b9314d2..f1e639c 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -95,9 +95,12 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
if (HasTemplateScope)
Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate);
+ // The current scope is still active if we're the top-level class.
+ // Otherwise we'll need to push and enter a new scope.
bool HasClassScope = !Class.TopLevelClass;
- ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
- HasClassScope);
+ ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, HasClassScope);
+ if (HasClassScope)
+ Actions.ActOnStartDelayedMemberDeclarations(CurScope, Class.TagOrTemplate);
for (; !Class.MethodDecls.empty(); Class.MethodDecls.pop_front()) {
LateParsedMethodDeclaration &LM = Class.MethodDecls.front();
@@ -148,6 +151,9 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I)
ParseLexedMethodDeclarations(*Class.NestedClasses[I]);
+
+ if (HasClassScope)
+ Actions.ActOnFinishDelayedMemberDeclarations(CurScope, Class.TagOrTemplate);
}
/// ParseLexedMethodDefs - We finished parsing the member specification of a top
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 5dd78f7..f429ac9 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -550,13 +550,17 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D,
SourceLocation DelLoc = ConsumeToken();
Actions.SetDeclDeleted(ThisDecl, DelLoc);
} else {
- if (getLang().CPlusPlus)
+ if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
+ EnterScope(0);
Actions.ActOnCXXEnterDeclInitializer(CurScope, ThisDecl);
+ }
OwningExprResult Init(ParseInitializer());
- if (getLang().CPlusPlus)
+ if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
Actions.ActOnCXXExitDeclInitializer(CurScope, ThisDecl);
+ ExitScope();
+ }
if (Init.isInvalid()) {
SkipUntil(tok::semi, true, true);
@@ -570,14 +574,30 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D,
ExprVector Exprs(Actions);
CommaLocsTy CommaLocs;
+ if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
+ EnterScope(0);
+ Actions.ActOnCXXEnterDeclInitializer(CurScope, ThisDecl);
+ }
+
if (ParseExpressionList(Exprs, CommaLocs)) {
SkipUntil(tok::r_paren);
+
+ if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
+ Actions.ActOnCXXExitDeclInitializer(CurScope, ThisDecl);
+ ExitScope();
+ }
} else {
// Match the ')'.
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() &&
"Unexpected number of commas!");
+
+ if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
+ Actions.ActOnCXXExitDeclInitializer(CurScope, ThisDecl);
+ ExitScope();
+ }
+
Actions.AddCXXDirectInitializerToDecl(ThisDecl, LParenLoc,
move_arg(Exprs),
CommaLocs.data(), RParenLoc);
@@ -2349,7 +2369,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
if (ParseUnqualifiedId(D.getCXXScopeSpec(),
/*EnteringContext=*/true,
/*AllowDestructorName=*/true,
- /*AllowConstructorName=*/!D.getDeclSpec().hasTypeSpecifier(),
+ /*AllowConstructorName=*/!D.getDeclSpec().hasTypeSpecifier(),
/*ObjectType=*/0,
D.getName())) {
D.SetIdentifier(0, Tok.getLocation());
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index d4d19a0..265d0f3 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -852,20 +852,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
SS, Name, StartLoc, NameLoc);
}
- // Parse the optional base clause (C++ only).
- if (getLang().CPlusPlus && Tok.is(tok::colon))
- ParseBaseClause(TagOrTempResult.get());
-
// If there is a body, parse it and inform the actions module.
- if (Tok.is(tok::l_brace))
+ if (TUK == Action::TUK_Definition) {
+ assert(Tok.is(tok::l_brace) ||
+ (getLang().CPlusPlus && Tok.is(tok::colon)));
if (getLang().CPlusPlus)
ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get());
else
ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
- else if (TUK == Action::TUK_Definition) {
- // FIXME: Complain that we have a base-specifier list but no
- // definition.
- Diag(Tok, diag::err_expected_lbrace);
}
void *Result;
@@ -1364,8 +1358,6 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
PP.getSourceManager(),
"parsing struct/union/class body");
- SourceLocation LBraceLoc = ConsumeBrace();
-
// Determine whether this is a top-level (non-nested) class.
bool TopLevelClass = ClassStack.empty() ||
CurScope->isInCXXInlineMethodScope();
@@ -1378,11 +1370,27 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
if (TagDecl)
Actions.ActOnTagStartDefinition(CurScope, TagDecl);
- else {
+
+ if (Tok.is(tok::colon)) {
+ ParseBaseClause(TagDecl);
+
+ if (!Tok.is(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_lbrace_after_base_specifiers);
+ return;
+ }
+ }
+
+ assert(Tok.is(tok::l_brace));
+
+ SourceLocation LBraceLoc = ConsumeBrace();
+
+ if (!TagDecl) {
SkipUntil(tok::r_brace, false, false);
return;
}
+ Actions.ActOnStartCXXMemberDeclarations(CurScope, TagDecl, LBraceLoc);
+
// C++ 11p3: Members of a class defined with the keyword class are private
// by default. Members of a class defined with the keywords struct or union
// are public by default.
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 2c53847..9904a2c 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -1589,7 +1589,7 @@ Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
// Otherwise, eat the semicolon.
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
- return Actions.ActOnExprStmt(Actions.FullExpr(Res));
+ return Actions.ActOnExprStmt(Actions.MakeFullExpr(Res));
}
Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index a2ac646..9085b87 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -131,7 +131,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
}
// Otherwise, eat the semicolon.
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
- return Actions.ActOnExprStmt(Actions.FullExpr(Expr));
+ return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr));
}
case tok::kw_case: // C99 6.8.1: labeled-statement
@@ -494,7 +494,7 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
// Eat the semicolon at the end of stmt and convert the expr into a
// statement.
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
- R = Actions.ActOnExprStmt(Actions.FullExpr(Res));
+ R = Actions.ActOnExprStmt(Actions.MakeFullExpr(Res));
}
}
@@ -593,7 +593,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) {
if (ParseParenExprOrCondition(CondExp, CondVar))
return StmtError();
- FullExprArg FullCondExp(Actions.FullExpr(CondExp));
+ FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp));
// C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do this
@@ -720,7 +720,7 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) {
if (ParseParenExprOrCondition(Cond, CondVar))
return StmtError();
- FullExprArg FullCond(Actions.FullExpr(Cond));
+ FullExprArg FullCond(Actions.MakeFullExpr(Cond));
OwningStmtResult Switch = Actions.ActOnStartOfSwitchStmt(FullCond, CondVar);
@@ -801,7 +801,7 @@ Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) {
if (ParseParenExprOrCondition(Cond, CondVar))
return StmtError();
- FullExprArg FullCond(Actions.FullExpr(Cond));
+ FullExprArg FullCond(Actions.MakeFullExpr(Cond));
// C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do this
@@ -993,7 +993,7 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
// Turn the expression into a stmt.
if (!Value.isInvalid())
- FirstPart = Actions.ActOnExprStmt(Actions.FullExpr(Value));
+ FirstPart = Actions.ActOnExprStmt(Actions.MakeFullExpr(Value));
if (Tok.is(tok::semi)) {
ConsumeToken();
@@ -1060,8 +1060,8 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
if (!ForEach)
return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart),
- Actions.FullExpr(SecondPart), SecondVar,
- Actions.FullExpr(ThirdPart), RParenLoc,
+ Actions.MakeFullExpr(SecondPart), SecondVar,
+ Actions.MakeFullExpr(ThirdPart), RParenLoc,
move(Body));
return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc,
@@ -1232,7 +1232,6 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) {
// Remember if this was a volatile asm.
bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;
- bool isSimple = false;
if (Tok.isNot(tok::l_paren)) {
Diag(Tok, diag::err_expected_lparen_after) << "asm";
SkipUntil(tok::r_paren);
@@ -1249,53 +1248,73 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) {
ExprVector Exprs(Actions);
ExprVector Clobbers(Actions);
- unsigned NumInputs = 0, NumOutputs = 0;
-
- SourceLocation RParenLoc;
if (Tok.is(tok::r_paren)) {
- // We have a simple asm expression
- isSimple = true;
-
- RParenLoc = ConsumeParen();
- } else {
- // Parse Outputs, if present.
- if (ParseAsmOperandsOpt(Names, Constraints, Exprs))
- return StmtError();
-
- NumOutputs = Names.size();
+ // We have a simple asm expression like 'asm("foo")'.
+ SourceLocation RParenLoc = ConsumeParen();
+ return Actions.ActOnAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
+ /*NumOutputs*/ 0, /*NumInputs*/ 0, 0,
+ move_arg(Constraints), move_arg(Exprs),
+ move(AsmString), move_arg(Clobbers),
+ RParenLoc);
+ }
- // Parse Inputs, if present.
- if (ParseAsmOperandsOpt(Names, Constraints, Exprs))
- return StmtError();
+ // Parse Outputs, if present.
+ bool AteExtraColon = false;
+ if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
+ // In C++ mode, parse "::" like ": :".
+ AteExtraColon = Tok.is(tok::coloncolon);
+ ConsumeToken();
+
+ if (!AteExtraColon &&
+ ParseAsmOperandsOpt(Names, Constraints, Exprs))
+ return StmtError();
+ }
+
+ unsigned NumOutputs = Names.size();
+
+ // Parse Inputs, if present.
+ if (AteExtraColon ||
+ Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
+ // In C++ mode, parse "::" like ": :".
+ if (AteExtraColon)
+ AteExtraColon = false;
+ else {
+ AteExtraColon = Tok.is(tok::coloncolon);
+ ConsumeToken();
+ }
+
+ if (!AteExtraColon &&
+ ParseAsmOperandsOpt(Names, Constraints, Exprs))
+ return StmtError();
+ }
- assert(Names.size() == Constraints.size() &&
- Constraints.size() == Exprs.size()
- && "Input operand size mismatch!");
+ assert(Names.size() == Constraints.size() &&
+ Constraints.size() == Exprs.size() &&
+ "Input operand size mismatch!");
- NumInputs = Names.size() - NumOutputs;
+ unsigned NumInputs = Names.size() - NumOutputs;
- // Parse the clobbers, if present.
- if (Tok.is(tok::colon)) {
+ // Parse the clobbers, if present.
+ if (AteExtraColon || Tok.is(tok::colon)) {
+ if (!AteExtraColon)
ConsumeToken();
- // Parse the asm-string list for clobbers.
- while (1) {
- OwningExprResult Clobber(ParseAsmStringLiteral());
+ // Parse the asm-string list for clobbers.
+ while (1) {
+ OwningExprResult Clobber(ParseAsmStringLiteral());
- if (Clobber.isInvalid())
- break;
+ if (Clobber.isInvalid())
+ break;
- Clobbers.push_back(Clobber.release());
+ Clobbers.push_back(Clobber.release());
- if (Tok.isNot(tok::comma)) break;
- ConsumeToken();
- }
+ if (Tok.isNot(tok::comma)) break;
+ ConsumeToken();
}
-
- RParenLoc = MatchRHSPunctuation(tok::r_paren, Loc);
}
- return Actions.ActOnAsmStmt(AsmLoc, isSimple, isVolatile,
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, Loc);
+ return Actions.ActOnAsmStmt(AsmLoc, false, isVolatile,
NumOutputs, NumInputs, Names.data(),
move_arg(Constraints), move_arg(Exprs),
move(AsmString), move_arg(Clobbers),
@@ -1303,8 +1322,7 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) {
}
/// ParseAsmOperands - Parse the asm-operands production as used by
-/// asm-statement. We also parse a leading ':' token. If the leading colon is
-/// not present, we do not parse anything.
+/// asm-statement, assuming the leading ':' token was eaten.
///
/// [GNU] asm-operands:
/// asm-operand
@@ -1319,10 +1337,6 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) {
bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names,
llvm::SmallVectorImpl<ExprTy*> &Constraints,
llvm::SmallVectorImpl<ExprTy*> &Exprs) {
- // Only do anything if this operand is present.
- if (Tok.isNot(tok::colon)) return false;
- ConsumeToken();
-
// 'asm-operands' isn't present?
if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
return false;
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index cc28541..8b8af99 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -643,8 +643,10 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
}
}
- if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater))
+ if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater)) {
+ Diag(Tok.getLocation(), diag::err_expected_greater);
return true;
+ }
// Determine the location of the '>' or '>>'. Only consume this
// token if the caller asked us to.
@@ -989,7 +991,7 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
ConsumeToken();
}
- return Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater);
+ return false;
}
/// \brief Parse a C++ explicit template instantiation
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index dabd065..51c5670 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -680,10 +680,11 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
// Otherwise, not a typename.
return TPResult::False();
- case tok::coloncolon: // ::foo::bar
- if (NextToken().is(tok::kw_new) || // ::new
- NextToken().is(tok::kw_delete)) // ::delete
- return TPResult::False();
+ case tok::coloncolon: { // ::foo::bar
+ const Token &Next = NextToken();
+ if (Next.is(tok::kw_new) || // ::new
+ Next.is(tok::kw_delete)) // ::delete
+ return TPResult::False();
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
@@ -691,7 +692,8 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
return isCXXDeclarationSpecifier();
// Otherwise, not a typename.
return TPResult::False();
-
+ }
+
// decl-specifier:
// storage-class-specifier
// type-specifier
@@ -699,7 +701,6 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
// 'friend'
// 'typedef'
// 'constexpr'
-
case tok::kw_friend:
case tok::kw_typedef:
case tok::kw_constexpr:
@@ -750,6 +751,12 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw___forceinline:
return TPResult::True();
+ case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed
+ // We've already annotated a scope; try to annotate a type.
+ if (!(TryAnnotateTypeOrScopeToken() && Tok.is(tok::annot_typename)))
+ return TPResult::False();
+ // If that succeeded, fallthrough into the generic simple-type-id case.
+
// The ambiguity resides in a simple-type-specifier/typename-specifier
// followed by a '('. The '(' could either be the start of:
//
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index a864e7c..52c0153 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -880,7 +880,7 @@ Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
/// as the current tokens, so only call it in contexts where these are invalid.
bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon)
- || Tok.is(tok::kw_typename)) &&
+ || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) &&
"Cannot be a type or scope token!");
if (Tok.is(tok::kw_typename)) {
@@ -935,6 +935,9 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
return true;
}
+ // Remembers whether the token was originally a scope annotation.
+ bool wasScopeAnnotation = Tok.is(tok::annot_cxxscope);
+
CXXScopeSpec SS;
if (getLang().CPlusPlus)
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext);
@@ -1017,9 +1020,11 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
Tok.setAnnotationValue(SS.getScopeRep());
Tok.setAnnotationRange(SS.getRange());
- // In case the tokens were cached, have Preprocessor replace them with the
- // annotation token.
- PP.AnnotateCachedTokens(Tok);
+ // In case the tokens were cached, have Preprocessor replace them
+ // with the annotation token. We don't need to do this if we've
+ // just reverted back to the state we were in before being called.
+ if (!wasScopeAnnotation)
+ PP.AnnotateCachedTokens(Tok);
return true;
}
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index d8ed894..b9b85df 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -37,6 +37,7 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text)
case CK_Text:
case CK_Placeholder:
case CK_Informative:
+ case CK_ResultType:
case CK_CurrentParameter: {
char *New = new char [Text.size() + 1];
std::memcpy(New, Text.data(), Text.size());
@@ -112,6 +113,11 @@ CodeCompletionString::Chunk::CreateInformative(StringRef Informative) {
}
CodeCompletionString::Chunk
+CodeCompletionString::Chunk::CreateResultType(StringRef ResultType) {
+ return Chunk(CK_ResultType, ResultType);
+}
+
+CodeCompletionString::Chunk
CodeCompletionString::Chunk::CreateCurrentParameter(
StringRef CurrentParameter) {
return Chunk(CK_CurrentParameter, CurrentParameter);
@@ -123,6 +129,7 @@ CodeCompletionString::Chunk CodeCompletionString::Chunk::Clone() const {
case CK_Text:
case CK_Placeholder:
case CK_Informative:
+ case CK_ResultType:
case CK_CurrentParameter:
case CK_LeftParen:
case CK_RightParen:
@@ -156,6 +163,7 @@ CodeCompletionString::Chunk::Destroy() {
case CK_Text:
case CK_Placeholder:
case CK_Informative:
+ case CK_ResultType:
case CK_CurrentParameter:
delete [] Text;
break;
@@ -186,7 +194,12 @@ std::string CodeCompletionString::getAsString() const {
switch (C->Kind) {
case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break;
case CK_Placeholder: OS << "<#" << C->Text << "#>"; break;
- case CK_Informative: OS << "[#" << C->Text << "#]"; break;
+
+ case CK_Informative:
+ case CK_ResultType:
+ OS << "[#" << C->Text << "#]";
+ break;
+
case CK_CurrentParameter: OS << "<#" << C->Text << "#>"; break;
default: OS << C->Text; break;
}
@@ -236,6 +249,7 @@ void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const {
case CK_Text:
case CK_Placeholder:
case CK_Informative:
+ case CK_ResultType:
case CK_CurrentParameter: {
const char *Text = C->Text;
unsigned StrLen = strlen(Text);
@@ -286,6 +300,7 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str,
case CK_Text:
case CK_Placeholder:
case CK_Informative:
+ case CK_ResultType:
case CK_CurrentParameter: {
unsigned StrLen;
if (ReadUnsigned(Str, StrEnd, StrLen) || (Str + StrLen > StrEnd))
diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h
index 78f79ea..c5eecda 100644
--- a/lib/Sema/Lookup.h
+++ b/lib/Sema/Lookup.h
@@ -121,6 +121,8 @@ public:
typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy;
typedef DeclsTy::const_iterator iterator;
+ typedef bool (*ResultFilter)(NamedDecl*, unsigned IDNS);
+
LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc,
Sema::LookupNameKind LookupKind,
Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration)
@@ -130,11 +132,14 @@ public:
Name(Name),
NameLoc(NameLoc),
LookupKind(LookupKind),
+ IsAcceptableFn(0),
IDNS(0),
Redecl(Redecl != Sema::NotForRedeclaration),
HideTags(true),
Diagnose(Redecl == Sema::NotForRedeclaration)
- {}
+ {
+ configure();
+ }
/// Creates a temporary lookup result, initializing its core data
/// using the information from another result. Diagnostics are always
@@ -146,6 +151,7 @@ public:
Name(Other.Name),
NameLoc(Other.NameLoc),
LookupKind(Other.LookupKind),
+ IsAcceptableFn(Other.IsAcceptableFn),
IDNS(Other.IDNS),
Redecl(Other.Redecl),
HideTags(Other.HideTags),
@@ -162,6 +168,11 @@ public:
return Name;
}
+ /// \brief Sets the name to look up.
+ void setLookupName(DeclarationName Name) {
+ this->Name = Name;
+ }
+
/// Gets the kind of lookup to perform.
Sema::LookupNameKind getLookupKind() const {
return LookupKind;
@@ -178,17 +189,6 @@ public:
HideTags = Hide;
}
- /// The identifier namespace of this lookup. This information is
- /// private to the lookup routines.
- unsigned getIdentifierNamespace() const {
- assert(IDNS);
- return IDNS;
- }
-
- void setIdentifierNamespace(unsigned NS) {
- IDNS = NS;
- }
-
bool isAmbiguous() const {
return getResultKind() == Ambiguous;
}
@@ -231,7 +231,19 @@ public:
return Paths;
}
- /// \brief Add a declaration to these results.
+ /// \brief Tests whether the given declaration is acceptable.
+ bool isAcceptableDecl(NamedDecl *D) const {
+ assert(IsAcceptableFn);
+ return IsAcceptableFn(D, IDNS);
+ }
+
+ /// \brief Returns the identifier namespace mask for this lookup.
+ unsigned getIdentifierNamespace() const {
+ return IDNS;
+ }
+
+ /// \brief Add a declaration to these results. Does not test the
+ /// acceptance criteria.
void addDecl(NamedDecl *D) {
Decls.push_back(D);
ResultKind = Found;
@@ -334,6 +346,7 @@ public:
void clear(Sema::LookupNameKind Kind) {
clear();
LookupKind = Kind;
+ configure();
}
void print(llvm::raw_ostream &);
@@ -362,6 +375,10 @@ public:
return NameLoc;
}
+ /// \brief Get the Sema object that this lookup result is searching
+ /// with.
+ Sema &getSema() const { return SemaRef; }
+
/// A class for iterating through a result set and possibly
/// filtering out results. The results returned are possibly
/// sugared.
@@ -438,6 +455,7 @@ private:
}
void addDeclsFromBasePaths(const CXXBasePaths &P);
+ void configure();
// Sanity checks.
void sanity() const {
@@ -476,7 +494,9 @@ private:
SourceLocation NameLoc;
SourceRange NameContextRange;
Sema::LookupNameKind LookupKind;
- unsigned IDNS; // ill-defined until set by lookup
+ ResultFilter IsAcceptableFn; // set by configure()
+ unsigned IDNS; // set by configure()
+
bool Redecl;
/// \brief True if tag declarations should be hidden if non-tags
@@ -486,6 +506,26 @@ private:
bool Diagnose;
};
+ /// \brief Consumes visible declarations found when searching for
+ /// all visible names within a given scope or context.
+ ///
+ /// This abstract class is meant to be subclassed by clients of \c
+ /// Sema::LookupVisibleDecls(), each of which should override the \c
+ /// FoundDecl() function to process declarations as they are found.
+ class VisibleDeclConsumer {
+ public:
+ /// \brief Destroys the visible declaration consumer.
+ virtual ~VisibleDeclConsumer();
+
+ /// \brief Invoked each time \p Sema::LookupVisibleDecls() finds a
+ /// declaration visible from the current scope or context.
+ ///
+ /// \param ND the declaration found.
+ ///
+ /// \param Hiding a declaration that hides the declaration \p ND,
+ /// or NULL if no such declaration exists.
+ virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding) = 0;
+ };
}
#endif
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index ef61474..40ad90a 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -350,7 +350,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
: LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0),
- PreDeclaratorDC(0), CurBlock(0), PackContext(0), ParsingDeclDepth(0),
+ CurBlock(0), PackContext(0), ParsingDeclDepth(0),
IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0),
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
@@ -389,12 +389,6 @@ static bool getIntProperties(ASTContext &C, const Type *T,
return true;
}
- if (const FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) {
- BitWidth = FWIT->getWidth();
- Signed = FWIT->isSigned();
- return true;
- }
-
return false;
}
@@ -655,8 +649,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T) {
}
// If the target is integral, always warn.
- if ((TargetBT && TargetBT->isInteger()) ||
- isa<FixedWidthIntType>(Target))
+ if ((TargetBT && TargetBT->isInteger()))
// TODO: don't warn for integer values?
return DiagnoseImpCast(S, E, T, diag::warn_impcast_float_integer);
@@ -815,7 +808,7 @@ void Sema::ActOnEndOfTranslationUnit() {
//===----------------------------------------------------------------------===//
DeclContext *Sema::getFunctionLevelDeclContext() {
- DeclContext *DC = PreDeclaratorDC ? PreDeclaratorDC : CurContext;
+ DeclContext *DC = CurContext;
while (isa<BlockDecl>(DC))
DC = DC->getParent();
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index ada8aa1..4cecee4 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -24,6 +24,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/FullExpr.h"
#include "clang/Parse/Action.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallVector.h"
@@ -57,6 +58,7 @@ namespace clang {
class DesignatedInitExpr;
class CallExpr;
class DeclRefExpr;
+ class UnresolvedLookupExpr;
class VarDecl;
class ParmVarDecl;
class TypedefDecl;
@@ -98,7 +100,8 @@ namespace clang {
class InitializedEntity;
class InitializationKind;
class InitializationSequence;
-
+ class VisibleDeclConsumer;
+
/// BlockSemaInfo - When a block is being parsed, this contains information
/// about the block. It is pointed to from Sema::CurBlock.
struct BlockSemaInfo {
@@ -190,10 +193,6 @@ public:
/// CurContext - This is the current declaration context of parsing.
DeclContext *CurContext;
- /// PreDeclaratorDC - Keeps the declaration context before switching to the
- /// context of a declarator's nested-name-specifier.
- DeclContext *PreDeclaratorDC;
-
/// CurBlock - If inside of a block definition, this contains a pointer to
/// the active block object that represents it.
BlockSemaInfo *CurBlock;
@@ -611,10 +610,6 @@ public:
const LookupResult &Previous,
Scope *S);
void DiagnoseFunctionSpecifiers(Declarator& D);
- bool CheckRedeclaration(DeclContext *DC,
- DeclarationName Name,
- SourceLocation NameLoc,
- unsigned Diagnostic);
NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous, bool &Redeclaration);
@@ -763,6 +758,12 @@ public:
/// struct, or union).
virtual void ActOnTagStartDefinition(Scope *S, DeclPtrTy TagDecl);
+ /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a
+ /// C++ record definition's base-specifiers clause and are starting its
+ /// member declarations.
+ virtual void ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagDecl,
+ SourceLocation LBraceLoc);
+
/// ActOnTagFinishDefinition - Invoked once we have finished parsing
/// the definition of a tag (enumeration, class, struct, or union).
virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl,
@@ -841,6 +842,18 @@ public:
void MergeVarDecl(VarDecl *New, LookupResult &OldDecls);
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old);
+ // AssignmentAction - This is used by all the assignment diagnostic functions
+ // to represent what is actually causing the operation
+ enum AssignmentAction {
+ AA_Assigning,
+ AA_Passing,
+ AA_Returning,
+ AA_Converting,
+ AA_Initializing,
+ AA_Sending,
+ AA_Casting
+ };
+
/// C++ Overloading.
enum OverloadKind {
/// This is a legitimate overload: the existing declarations are
@@ -917,9 +930,13 @@ public:
TryCopyInitialization(Expr* From, QualType ToType,
bool SuppressUserConversions, bool ForceRValue,
bool InOverloadResolution);
+
bool PerformCopyInitialization(Expr *&From, QualType ToType,
- const char *Flavor, bool Elidable = false);
+ AssignmentAction Action, bool Elidable = false);
+ OwningExprResult PerformCopyInitialization(const InitializedEntity &Entity,
+ SourceLocation EqualLoc,
+ OwningExprResult Init);
ImplicitConversionSequence
TryObjectArgumentInitialization(QualType FromType, CXXMethodDecl *Method,
CXXRecordDecl *ActingContext);
@@ -1020,27 +1037,23 @@ public:
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
bool Complain);
+ FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From);
+
Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
OwningExprResult FixOverloadedFunctionReference(OwningExprResult,
FunctionDecl *Fn);
- void AddOverloadedCallCandidates(llvm::SmallVectorImpl<NamedDecl*>& Callees,
- DeclarationName &UnqualifiedName,
- bool ArgumentDependentLookup,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading = false);
- FunctionDecl *ResolveOverloadedCallFn(Expr *Fn,
- llvm::SmallVectorImpl<NamedDecl*> &Fns,
- DeclarationName UnqualifiedName,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
- SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
- SourceLocation *CommaLocs,
- SourceLocation RParenLoc,
- bool ArgumentDependentLookup);
+ OwningExprResult BuildOverloadedCallExpr(Expr *Fn,
+ UnresolvedLookupExpr *ULE,
+ SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc);
OwningExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc,
unsigned Opc,
@@ -1133,7 +1146,7 @@ public:
// members.
LookupOperatorName,
/// Look up of a name that precedes the '::' scope resolution
- /// operator in C++. This lookup completely ignores operator,
+ /// operator in C++. This lookup completely ignores operator, object,
/// function, and enumerator names (C++ [basic.lookup.qual]p1).
LookupNestedNameSpecifierName,
/// Look up a namespace name within a C++ using directive or
@@ -1164,36 +1177,6 @@ private:
bool CppLookupName(LookupResult &R, Scope *S);
public:
- /// Determines whether D is a suitable lookup result according to the
- /// lookup criteria.
- static bool isAcceptableLookupResult(NamedDecl *D, LookupNameKind NameKind,
- unsigned IDNS) {
- switch (NameKind) {
- case Sema::LookupOrdinaryName:
- case Sema::LookupTagName:
- case Sema::LookupMemberName:
- case Sema::LookupRedeclarationWithLinkage: // FIXME: check linkage, scoping
- case Sema::LookupUsingDeclName:
- case Sema::LookupObjCProtocolName:
- case Sema::LookupObjCImplementationName:
- return D->isInIdentifierNamespace(IDNS);
-
- case Sema::LookupOperatorName:
- return D->isInIdentifierNamespace(IDNS) &&
- !D->getDeclContext()->isRecord();
-
- case Sema::LookupNestedNameSpecifierName:
- return isa<TypedefDecl>(D) || D->isInIdentifierNamespace(Decl::IDNS_Tag);
-
- case Sema::LookupNamespaceName:
- return isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D);
- }
-
- assert(false &&
- "isAcceptableLookupResult always returns before this point");
- return false;
- }
-
/// \brief Look up a name, looking for a single declaration. Return
/// null if the results were absent, ambiguous, or overloaded.
///
@@ -1215,11 +1198,20 @@ public:
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
QualType T1, QualType T2,
FunctionSet &Functions);
-
+
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
Expr **Args, unsigned NumArgs,
FunctionSet &Functions);
+ void LookupVisibleDecls(Scope *S, LookupNameKind Kind,
+ VisibleDeclConsumer &Consumer);
+ void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
+ VisibleDeclConsumer &Consumer);
+
+ bool CorrectTypo(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
+ DeclContext *MemberContext = 0,
+ bool EnteringContext = false);
+
void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
AssociatedNamespaceSet &AssociatedNamespaces,
AssociatedClassSet &AssociatedClasses);
@@ -1455,7 +1447,8 @@ public:
virtual void PopExpressionEvaluationContext();
void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
-
+ bool DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD);
+
// Primary Expressions.
virtual SourceRange getExprRange(ExprTy *E) const;
@@ -1465,6 +1458,8 @@ public:
bool HasTrailingLParen,
bool IsAddressOfOperand);
+ bool DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, LookupResult &R);
+
OwningExprResult LookupInObjCMethod(LookupResult &R,
Scope *S,
IdentifierInfo *II);
@@ -1485,6 +1480,9 @@ public:
FieldDecl *Field,
Expr *BaseObjectExpr = 0,
SourceLocation OpLoc = SourceLocation());
+ OwningExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs);
OwningExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs,
@@ -1611,16 +1609,6 @@ public:
Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc);
- void DeconstructCallFunction(Expr *FnExpr,
- llvm::SmallVectorImpl<NamedDecl*>& Fns,
- DeclarationName &Name,
- NestedNameSpecifier *&Qualifier,
- SourceRange &QualifierRange,
- bool &ArgumentDependentLookup,
- bool &Overloaded,
- bool &HasExplicitTemplateArgs,
- TemplateArgumentListInfo &ExplicitTemplateArgs);
-
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
/// This provides the location of the left/right parens and a list of comma
/// locations.
@@ -1812,7 +1800,8 @@ public:
OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc,
QualType DeclInitType,
CXXConstructorDecl *Constructor,
- MultiExprArg Exprs);
+ MultiExprArg Exprs,
+ bool RequiresZeroInit = false);
// FIXME: Can re remove this and have the above BuildCXXConstructExpr check if
// the constructor can be elidable?
@@ -1820,7 +1809,8 @@ public:
QualType DeclInitType,
CXXConstructorDecl *Constructor,
bool Elidable,
- MultiExprArg Exprs);
+ MultiExprArg Exprs,
+ bool RequiresZeroInit = false);
OwningExprResult BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Cons,
QualType writtenTy,
@@ -1972,7 +1962,8 @@ public:
bool AllowMissing, FunctionDecl *&Operator);
void DeclareGlobalNewDelete();
void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return,
- QualType Argument);
+ QualType Argument,
+ bool addMallocAttr = false);
bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name, FunctionDecl* &Operator);
@@ -2003,9 +1994,10 @@ public:
/// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is
/// non-empty, will create a new CXXExprWithTemporaries expression.
/// Otherwise, just returs the passed in expression.
- Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr,
- bool ShouldDestroyTemporaries);
-
+ Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr);
+ OwningExprResult MaybeCreateCXXExprWithTemporaries(OwningExprResult SubExpr);
+ FullExpr CreateFullExpr(Expr *SubExpr);
+
virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr);
bool RequireCompleteDeclContext(const CXXScopeSpec &SS);
@@ -2216,11 +2208,15 @@ public:
SourceLocation RBrac);
virtual void ActOnReenterTemplateScope(Scope *S, DeclPtrTy Template);
+ virtual void ActOnStartDelayedMemberDeclarations(Scope *S,
+ DeclPtrTy Record);
virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S,
DeclPtrTy Method);
virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy Param);
virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S,
DeclPtrTy Method);
+ virtual void ActOnFinishDelayedMemberDeclarations(Scope *S,
+ DeclPtrTy Record);
virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
ExprArg AssertExpr,
@@ -2681,7 +2677,10 @@ public:
TDK_TooFewArguments,
/// \brief The explicitly-specified template arguments were not valid
/// template arguments for the given template.
- TDK_InvalidExplicitArguments
+ TDK_InvalidExplicitArguments,
+ /// \brief The arguments included an overloaded function name that could
+ /// not be resolved to a suitable function.
+ TDK_FailedOverloadResolution
};
/// \brief Provides information about an attempted template argument
@@ -2795,6 +2794,12 @@ public:
CXXConversionDecl *&Specialization,
TemplateDeductionInfo &Info);
+ TemplateDeductionResult
+ DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ FunctionDecl *&Specialization,
+ TemplateDeductionInfo &Info);
+
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
TemplatePartialOrderingContext TPOC);
@@ -3555,14 +3560,14 @@ public:
/// represent it in the AST.
Incompatible
};
-
+
/// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the
/// assignment conversion type specified by ConvTy. This returns true if the
/// conversion was invalid or false if the conversion was accepted.
bool DiagnoseAssignmentResult(AssignConvertType ConvTy,
SourceLocation Loc,
QualType DstType, QualType SrcType,
- Expr *SrcExpr, const char *Flavor);
+ Expr *SrcExpr, AssignmentAction Action);
/// CheckAssignmentConstraints - Perform type checking for assignment,
/// argument passing, variable initialization, and function return values.
@@ -3597,25 +3602,24 @@ public:
bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType);
bool PerformImplicitConversion(Expr *&From, QualType ToType,
- const char *Flavor,
+ AssignmentAction Action,
bool AllowExplicit = false,
bool Elidable = false);
bool PerformImplicitConversion(Expr *&From, QualType ToType,
- const char *Flavor,
+ AssignmentAction Action,
bool AllowExplicit,
bool Elidable,
ImplicitConversionSequence& ICS);
bool PerformImplicitConversion(Expr *&From, QualType ToType,
const ImplicitConversionSequence& ICS,
- const char *Flavor,
+ AssignmentAction Action,
bool IgnoreBaseAccess = false);
bool PerformImplicitConversion(Expr *&From, QualType ToType,
const StandardConversionSequence& SCS,
- const char *Flavor, bool IgnoreBaseAccess);
+ AssignmentAction Action, bool IgnoreBaseAccess);
bool BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind,
- const ImplicitConversionSequence& ICS,
- const char *Flavor);
+ const ImplicitConversionSequence& ICS);
/// the following "Check" methods will return a valid/converted QualType
/// or a null QualType (indicating an error diagnostic was issued).
@@ -3675,15 +3679,10 @@ public:
SourceLocation CmpLoc);
/// type checking declaration initializers (C99 6.7.8)
-
- bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType,
- SourceLocation InitLoc,DeclarationName InitEntity,
- bool DirectInit);
- bool CheckInitList(InitListExpr *&InitList, QualType &DeclType);
+ bool CheckInitList(const InitializedEntity &Entity,
+ InitListExpr *&InitList, QualType &DeclType);
bool CheckForConstantInitializer(Expr *e, QualType t);
- bool CheckValueInitialization(QualType Type, SourceLocation Loc);
-
// type checking C++ declaration initializers (C++ [dcl.init]).
/// ReferenceCompareResult - Expresses the result of comparing two
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 21f83a5..b7cc37b 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -37,6 +37,8 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
<< MemberDecl << LexicalAS;
Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
<< PrevMemberDecl << PrevMemberDecl->getAccess();
+
+ MemberDecl->setAccess(LexicalAS);
return true;
}
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 814af90..800c544 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -899,7 +899,7 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
// The conversion is possible, so commit to it.
Kind = CastExpr::CK_NoOp;
msg = 0;
- return Self.PerformImplicitConversion(SrcExpr, DestType, ICS, "casting",
+ return Self.PerformImplicitConversion(SrcExpr, DestType, ICS, Sema::AA_Casting,
/*IgnoreBaseAccess*/CStyle) ?
TC_Failed : TC_Success;
}
@@ -959,8 +959,9 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
// as must be the final pointee type.
while (SrcType != DestType &&
Self.UnwrapSimilarPointerTypes(SrcType, DestType)) {
- SrcType = SrcType.getUnqualifiedType();
- DestType = DestType.getUnqualifiedType();
+ Qualifiers Quals;
+ SrcType = Self.Context.getUnqualifiedArrayType(SrcType, Quals);
+ DestType = Self.Context.getUnqualifiedArrayType(DestType, Quals);
}
// Since we're dealing in canonical types, the remainder must be the same.
@@ -975,8 +976,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
const SourceRange &OpRange,
unsigned &msg,
CastExpr::CastKind &Kind) {
- QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType();
-
DestType = Self.Context.getCanonicalType(DestType);
QualType SrcType = SrcExpr->getType();
if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) {
@@ -1053,8 +1052,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
return TC_NotApplicable;
// If both types have the same size, we can successfully cast.
- if (Self.Context.getTypeSize(SrcType) == Self.Context.getTypeSize(DestType))
+ if (Self.Context.getTypeSize(SrcType)
+ == Self.Context.getTypeSize(DestType)) {
+ Kind = CastExpr::CK_BitCast;
return TC_Success;
+ }
if (destIsScalar)
msg = diag::err_bad_cxx_cast_vector_to_scalar_different_size;
@@ -1083,6 +1085,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
// to the same type. However, the behavior of compilers is pretty consistent
// on this point: allow same-type conversion if the involved types are
// pointers, disallow otherwise.
+ Kind = CastExpr::CK_NoOp;
return TC_Success;
}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 039691f..82d58ea 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -329,7 +329,7 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
/// that it contains an extra parameter \p ScopeLookupResult, which provides
/// the result of name lookup within the scope of the nested-name-specifier
-/// that was computed at template definitino time.
+/// that was computed at template definition time.
///
/// If ErrorRecoveryLookup is true, then this call is used to improve error
/// recovery. This means that it should not emit diagnostics, it should
@@ -428,6 +428,28 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
}
// FIXME: Deal with ambiguities cleanly.
+
+ if (Found.empty() && !ErrorRecoveryLookup) {
+ // We haven't found anything, and we're not recovering from a
+ // different kind of error, so look for typos.
+ DeclarationName Name = Found.getLookupName();
+ if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext) &&
+ Found.isSingleResult() &&
+ isAcceptableNestedNameSpecifier(Found.getAsSingle<NamedDecl>())) {
+ if (LookupCtx)
+ Diag(Found.getNameLoc(), diag::err_no_member_suggest)
+ << Name << LookupCtx << Found.getLookupName() << SS.getRange()
+ << CodeModificationHint::CreateReplacement(Found.getNameLoc(),
+ Found.getLookupName().getAsString());
+ else
+ Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest)
+ << Name << Found.getLookupName()
+ << CodeModificationHint::CreateReplacement(Found.getNameLoc(),
+ Found.getLookupName().getAsString());
+ } else
+ Found.clear();
+ }
+
NamedDecl *SD = Found.getAsSingle<NamedDecl>();
if (isAcceptableNestedNameSpecifier(SD)) {
if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) {
@@ -605,15 +627,18 @@ bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
/// The 'SS' should be a non-empty valid CXXScopeSpec.
bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
- if (DeclContext *DC = computeDeclContext(SS, true)) {
- // Before we enter a declarator's context, we need to make sure that
- // it is a complete declaration context.
- if (!DC->isDependentContext() && RequireCompleteDeclContext(SS))
- return true;
-
- EnterDeclaratorContext(S, DC);
- }
-
+
+ if (SS.isInvalid()) return true;
+
+ DeclContext *DC = computeDeclContext(SS, true);
+ if (!DC) return true;
+
+ // Before we enter a declarator's context, we need to make sure that
+ // it is a complete declaration context.
+ if (!DC->isDependentContext() && RequireCompleteDeclContext(SS))
+ return true;
+
+ EnterDeclaratorContext(S, DC);
return false;
}
@@ -626,6 +651,7 @@ void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
if (SS.isInvalid())
return;
- if (computeDeclContext(SS, true))
- ExitDeclaratorContext(S);
+ assert(!SS.isInvalid() && computeDeclContext(SS, true) &&
+ "exiting declarator scope we never really entered");
+ ExitDeclaratorContext(S);
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 28de500..f10fa07 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -747,6 +747,7 @@ bool Sema::SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall) {
/// SemaBuiltinObjectSize - Handle __builtin_object_size(void *ptr,
/// int type). This simply type checks that type is one of the defined
/// constants (0-3).
+// For compatability check 0-3, llvm only handles 0 and 2.
bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
Expr *Arg = TheCall->getArg(1);
if (Arg->isTypeDependent())
@@ -800,7 +801,7 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
switch (E->getStmtClass()) {
case Stmt::ConditionalOperatorClass: {
const ConditionalOperator *C = cast<ConditionalOperator>(E);
- return SemaCheckStringLiteral(C->getLHS(), TheCall,
+ return SemaCheckStringLiteral(C->getTrueExpr(), TheCall,
HasVAListArg, format_idx, firstDataArg)
&& SemaCheckStringLiteral(C->getRHS(), TheCall,
HasVAListArg, format_idx, firstDataArg);
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 4ce9330..ef82a94 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -829,6 +829,39 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank,
}
}
+/// \brief If the given declaration has an associated type, add it as a result
+/// type chunk.
+static void AddResultTypeChunk(ASTContext &Context,
+ NamedDecl *ND,
+ CodeCompletionString *Result) {
+ if (!ND)
+ return;
+
+ // Determine the type of the declaration (if it has a type).
+ QualType T;
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND))
+ T = Function->getResultType();
+ else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
+ T = Method->getResultType();
+ else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND))
+ T = FunTmpl->getTemplatedDecl()->getResultType();
+ else if (EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
+ T = Context.getTypeDeclType(cast<TypeDecl>(Enumerator->getDeclContext()));
+ else if (isa<UnresolvedUsingValueDecl>(ND)) {
+ /* Do nothing: ignore unresolved using declarations*/
+ } else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND))
+ T = Value->getType();
+ else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
+ T = Property->getType();
+
+ if (T.isNull() || Context.hasSameType(T, Context.DependentTy))
+ return;
+
+ std::string TypeStr;
+ T.getAsStringInternal(TypeStr, Context.PrintingPolicy);
+ Result->AddResultTypeChunk(TypeStr);
+}
+
/// \brief Add function parameter chunks to the given code completion string.
static void AddFunctionParameterChunks(ASTContext &Context,
FunctionDecl *Function,
@@ -1042,6 +1075,8 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
return Result;
}
+ AddResultTypeChunk(S.Context, ND, Result);
+
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
S.Context);
@@ -1170,6 +1205,13 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
Result->AddPlaceholderChunk(Arg);
}
+ if (Method->isVariadic()) {
+ if (AllParametersAreInformative)
+ Result->AddInformativeChunk(", ...");
+ else
+ Result->AddPlaceholderChunk(", ...");
+ }
+
return Result;
}
@@ -1189,6 +1231,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
CodeCompletionString *Result = new CodeCompletionString;
FunctionDecl *FDecl = getFunction();
+ AddResultTypeChunk(S.Context, FDecl, Result);
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(getFunctionType());
if (!FDecl && !Proto) {
@@ -1706,33 +1749,24 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
CodeCompleteOrdinaryName(S);
return;
}
-
- llvm::SmallVector<NamedDecl*,8> Fns;
- DeclarationName UnqualifiedName;
- NestedNameSpecifier *Qualifier;
- SourceRange QualifierRange;
- bool ArgumentDependentLookup;
- bool Overloaded;
- bool HasExplicitTemplateArgs;
- TemplateArgumentListInfo ExplicitTemplateArgs;
-
- DeconstructCallFunction(Fn, Fns, UnqualifiedName, Qualifier, QualifierRange,
- ArgumentDependentLookup, Overloaded,
- HasExplicitTemplateArgs, ExplicitTemplateArgs);
-
+ // Build an overload candidate set based on the functions we find.
+ OverloadCandidateSet CandidateSet;
+
// FIXME: What if we're calling something that isn't a function declaration?
// FIXME: What if we're calling a pseudo-destructor?
// FIXME: What if we're calling a member function?
- // Build an overload candidate set based on the functions we find.
- OverloadCandidateSet CandidateSet;
- AddOverloadedCallCandidates(Fns, UnqualifiedName,
- ArgumentDependentLookup,
- (HasExplicitTemplateArgs ? &ExplicitTemplateArgs : 0),
- Args, NumArgs,
- CandidateSet,
- /*PartialOverloading=*/true);
+ Expr *NakedFn = Fn->IgnoreParenCasts();
+ if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn))
+ AddOverloadedCallCandidates(ULE, Args, NumArgs, CandidateSet,
+ /*PartialOverloading=*/ true);
+ else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(NakedFn)) {
+ FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl());
+ if (FDecl)
+ AddOverloadCandidate(FDecl, Args, NumArgs, CandidateSet,
+ false, false, /*PartialOverloading*/ true);
+ }
// Sort the overload candidate set by placing the best overloads first.
std::stable_sort(CandidateSet.begin(), CandidateSet.end(),
@@ -2419,7 +2453,6 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
typedef CodeCompleteConsumer::Result Result;
Expr *RecExpr = static_cast<Expr *>(Receiver);
- QualType RecType = RecExpr->getType();
// If necessary, apply function/array conversion to the receiver.
// C99 6.7.5.3p[7,8].
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 14d2377..2253f09 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -35,6 +35,7 @@
#include "clang/Lex/HeaderSearch.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
#include <algorithm>
#include <cstring>
#include <functional>
@@ -106,8 +107,12 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS))
return 0;
}
-
- LookupResult Result(*this, &II, NameLoc, LookupOrdinaryName);
+
+ // FIXME: LookupNestedNameSpecifierName isn't the right kind of
+ // lookup for class-names.
+ LookupNameKind Kind = isClassName ? LookupNestedNameSpecifierName :
+ LookupOrdinaryName;
+ LookupResult Result(*this, &II, NameLoc, Kind);
if (LookupCtx) {
// Perform "qualified" name lookup into the declaration context we
// computed, which is either the type of the base of a member access
@@ -250,10 +255,41 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
// We don't have anything to suggest (yet).
SuggestedType = 0;
+ // There may have been a typo in the name of the type. Look up typo
+ // results, in case we have something that we can suggest.
+ LookupResult Lookup(*this, &II, IILoc, LookupOrdinaryName,
+ NotForRedeclaration);
+
+ // FIXME: It would be nice if we could correct for typos in built-in
+ // names, such as "itn" for "int".
+
+ if (CorrectTypo(Lookup, S, SS) && Lookup.isSingleResult()) {
+ NamedDecl *Result = Lookup.getAsSingle<NamedDecl>();
+ if ((isa<TypeDecl>(Result) || isa<ObjCInterfaceDecl>(Result)) &&
+ !Result->isInvalidDecl()) {
+ // We found a similarly-named type or interface; suggest that.
+ if (!SS || !SS->isSet())
+ Diag(IILoc, diag::err_unknown_typename_suggest)
+ << &II << Lookup.getLookupName()
+ << CodeModificationHint::CreateReplacement(SourceRange(IILoc),
+ Result->getNameAsString());
+ else if (DeclContext *DC = computeDeclContext(*SS, false))
+ Diag(IILoc, diag::err_unknown_nested_typename_suggest)
+ << &II << DC << Lookup.getLookupName() << SS->getRange()
+ << CodeModificationHint::CreateReplacement(SourceRange(IILoc),
+ Result->getNameAsString());
+ else
+ llvm_unreachable("could not have corrected a typo here");
+
+ SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS);
+ return true;
+ }
+ }
+
// FIXME: Should we move the logic that tries to recover from a missing tag
// (struct, union, enum) from Parser::ParseImplicitInt here, instead?
- if (!SS)
+ if (!SS || (!SS->isSet() && !SS->isInvalid()))
Diag(IILoc, diag::err_unknown_typename) << &II;
else if (DeclContext *DC = computeDeclContext(*SS, false))
Diag(IILoc, diag::err_typename_nested_not_found)
@@ -321,23 +357,47 @@ void Sema::PopDeclContext() {
/// EnterDeclaratorContext - Used when we must lookup names in the context
/// of a declarator's nested name specifier.
+///
void Sema::EnterDeclaratorContext(Scope *S, DeclContext *DC) {
- assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?");
- PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity());
+ // C++0x [basic.lookup.unqual]p13:
+ // A name used in the definition of a static data member of class
+ // X (after the qualified-id of the static member) is looked up as
+ // if the name was used in a member function of X.
+ // C++0x [basic.lookup.unqual]p14:
+ // If a variable member of a namespace is defined outside of the
+ // scope of its namespace then any name used in the definition of
+ // the variable member (after the declarator-id) is looked up as
+ // if the definition of the variable member occurred in its
+ // namespace.
+ // Both of these imply that we should push a scope whose context
+ // is the semantic context of the declaration. We can't use
+ // PushDeclContext here because that context is not necessarily
+ // lexically contained in the current context. Fortunately,
+ // the containing scope should have the appropriate information.
+
+ assert(!S->getEntity() && "scope already has entity");
+
+#ifndef NDEBUG
+ Scope *Ancestor = S->getParent();
+ while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent();
+ assert(Ancestor->getEntity() == CurContext && "ancestor context mismatch");
+#endif
+
CurContext = DC;
- assert(CurContext && "No context?");
- S->setEntity(CurContext);
+ S->setEntity(DC);
}
void Sema::ExitDeclaratorContext(Scope *S) {
- S->setEntity(PreDeclaratorDC);
- PreDeclaratorDC = 0;
+ assert(S->getEntity() == CurContext && "Context imbalance!");
- // Reset CurContext to the nearest enclosing context.
- while (!S->getEntity() && S->getParent())
- S = S->getParent();
- CurContext = static_cast<DeclContext*>(S->getEntity());
- assert(CurContext && "No context?");
+ // Switch back to the lexical context. The safety of this is
+ // enforced by an assert in EnterDeclaratorContext.
+ Scope *Ancestor = S->getParent();
+ while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent();
+ CurContext = (DeclContext*) Ancestor->getEntity();
+
+ // We don't need to do anything with the scope, which is going to
+ // disappear.
}
/// \brief Determine whether we allow overloading of the function
@@ -667,9 +727,8 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) {
}
// Verify the old decl was also a type.
- TypeDecl *Old = 0;
- if (!OldDecls.isSingleResult() ||
- !(Old = dyn_cast<TypeDecl>(OldDecls.getFoundDecl()))) {
+ TypeDecl *Old = OldDecls.getAsSingle<TypeDecl>();
+ if (!Old) {
Diag(New->getLocation(), diag::err_redefinition_different_kind)
<< New->getDeclName();
@@ -704,6 +763,13 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) {
return New->setInvalidDecl();
}
+ // The types match. Link up the redeclaration chain if the old
+ // declaration was a typedef.
+ // FIXME: this is a potential source of wierdness if the type
+ // spellings don't match exactly.
+ if (isa<TypedefDecl>(Old))
+ New->setPreviousDeclaration(cast<TypedefDecl>(Old));
+
if (getLangOptions().Microsoft)
return;
@@ -772,7 +838,7 @@ static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx,
if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
if (Ctor->isDefaultConstructor())
return Sema::CXXDefaultConstructor;
- if (Ctor->isCopyConstructor(Ctx))
+ if (Ctor->isCopyConstructor())
return Sema::CXXCopyConstructor;
}
@@ -901,7 +967,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// (C++98 8.3.5p3):
// All declarations for a function shall agree exactly in both the
// return type and the parameter-type-list.
- if (OldQType == NewQType)
+ // attributes should be ignored when comparing.
+ if (Context.getNoReturnType(OldQType, false) ==
+ Context.getNoReturnType(NewQType, false))
return MergeCompatibleFunctionDecls(New, Old);
// Fall through for conflicting redeclarations and redefinitions.
@@ -1253,11 +1321,6 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
HasFakeEdge = true;
continue;
}
- if (isa<AsmStmt>(S)) {
- HasFakeEdge = true;
- HasLiveReturn = true;
- continue;
- }
bool NoReturnEdge = false;
if (CallExpr *C = dyn_cast<CallExpr>(S)) {
Expr *CEE = C->getCallee()->IgnoreParenCasts();
@@ -1445,7 +1508,6 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
// FIXME: Error on auto/register at file scope
// FIXME: Error on inline/virtual/explicit
- // FIXME: Error on invalid restrict
// FIXME: Warn on useless __thread
// FIXME: Warn on useless const/volatile
// FIXME: Warn on useless static/extern/typedef/private_extern/mutable
@@ -1467,6 +1529,15 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
Tag = dyn_cast<TagDecl>(TagD);
}
+ if (unsigned TypeQuals = DS.getTypeQualifiers()) {
+ // Enforce C99 6.7.3p2: "Types other than pointer types derived from object
+ // or incomplete types shall not be restrict-qualified."
+ if (TypeQuals & DeclSpec::TQ_restrict)
+ Diag(DS.getRestrictSpecLoc(),
+ diag::err_typecheck_invalid_restrict_not_pointer_noarg)
+ << DS.getSourceRange();
+ }
+
if (DS.isFriendSpecified()) {
// If we're dealing with a class template decl, assume that the
// template routines are handling it.
@@ -1516,29 +1587,27 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
return DeclPtrTy::make(Tag);
}
-/// We are trying to introduce the given name into the given context;
+/// We are trying to inject an anonymous member into the given scope;
/// check if there's an existing declaration that can't be overloaded.
///
/// \return true if this is a forbidden redeclaration
-bool Sema::CheckRedeclaration(DeclContext *DC,
- DeclarationName Name,
- SourceLocation NameLoc,
- unsigned diagnostic) {
- LookupResult R(*this, Name, NameLoc, LookupOrdinaryName,
- ForRedeclaration);
- LookupQualifiedName(R, DC);
-
- if (R.empty()) return false;
-
- if (R.getResultKind() == LookupResult::Found &&
- isa<TagDecl>(R.getFoundDecl()))
+static bool CheckAnonMemberRedeclaration(Sema &SemaRef,
+ Scope *S,
+ DeclarationName Name,
+ SourceLocation NameLoc,
+ unsigned diagnostic) {
+ LookupResult R(SemaRef, Name, NameLoc, Sema::LookupMemberName,
+ Sema::ForRedeclaration);
+ if (!SemaRef.LookupName(R, S)) return false;
+
+ if (R.getAsSingle<TagDecl>())
return false;
// Pick a representative declaration.
- NamedDecl *PrevDecl = (*R.begin())->getUnderlyingDecl();
+ NamedDecl *PrevDecl = R.getRepresentativeDecl()->getUnderlyingDecl();
- Diag(NameLoc, diagnostic) << Name;
- Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
+ SemaRef.Diag(NameLoc, diagnostic) << Name;
+ SemaRef.Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
return true;
}
@@ -1570,8 +1639,8 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
FEnd = AnonRecord->field_end();
F != FEnd; ++F) {
if ((*F)->getDeclName()) {
- if (CheckRedeclaration(Owner, (*F)->getDeclName(),
- (*F)->getLocation(), diagKind)) {
+ if (CheckAnonMemberRedeclaration(*this, S, (*F)->getDeclName(),
+ (*F)->getLocation(), diagKind)) {
// C++ [class.union]p2:
// The names of the members of an anonymous union shall be
// distinct from the names of any other entity in the
@@ -1889,9 +1958,12 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
if (DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(), true)) {
// FIXME: Preserve type source info.
QualType T = GetTypeFromParser(DS.getTypeRep());
- EnterDeclaratorContext(S, DC);
+
+ DeclContext *SavedContext = CurContext;
+ CurContext = DC;
T = RebuildTypeInCurrentInstantiation(T, D.getIdentifierLoc(), Name);
- ExitDeclaratorContext(S);
+ CurContext = SavedContext;
+
if (T.isNull())
return DeclPtrTy();
DS.UpdateTypeRep(T.getAsOpaquePtr());
@@ -3364,7 +3436,16 @@ void Sema::CheckMain(FunctionDecl* FD) {
unsigned nparams = FTP->getNumArgs();
assert(FD->getNumParams() == nparams);
- if (nparams > 3) {
+ bool HasExtraParameters = (nparams > 3);
+
+ // Darwin passes an undocumented fourth argument of type char**. If
+ // other platforms start sprouting these, the logic below will start
+ // getting shifty.
+ if (nparams == 4 &&
+ Context.Target.getTriple().getOS() == llvm::Triple::Darwin)
+ HasExtraParameters = false;
+
+ if (HasExtraParameters) {
Diag(FD->getLocation(), diag::err_main_surplus_args) << nparams;
FD->setInvalidDecl(true);
nparams = 3;
@@ -3375,7 +3456,7 @@ void Sema::CheckMain(FunctionDecl* FD) {
QualType CharPP =
Context.getPointerType(Context.getPointerType(Context.CharTy));
- QualType Expected[] = { Context.IntTy, CharPP, CharPP };
+ QualType Expected[] = { Context.IntTy, CharPP, CharPP, CharPP };
for (unsigned i = 0; i < nparams; ++i) {
QualType AT = FTP->getArgType(i);
@@ -3504,6 +3585,18 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
Expr *Init = init.takeAs<Expr>();
assert(Init && "missing initializer");
+ // Capture the variable that is being initialized and the style of
+ // initialization.
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
+
+ // FIXME: Poor source location information.
+ InitializationKind Kind
+ = DirectInit? InitializationKind::CreateDirect(VDecl->getLocation(),
+ Init->getLocStart(),
+ Init->getLocEnd())
+ : InitializationKind::CreateCopy(VDecl->getLocation(),
+ Init->getLocStart());
+
// Get the decls type and save a reference for later, since
// CheckInitializerTypes may change it.
QualType DclT = VDecl->getType(), SavT = DclT;
@@ -3512,37 +3605,16 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
Diag(VDecl->getLocation(), diag::err_block_extern_cant_init);
VDecl->setInvalidDecl();
} else if (!VDecl->isInvalidDecl()) {
- if (VDecl->getType()->isReferenceType()
- || isa<InitListExpr>(Init)) {
- InitializedEntity Entity
- = InitializedEntity::InitializeVariable(VDecl);
-
- // FIXME: Poor source location information.
- InitializationKind Kind
- = DirectInit? InitializationKind::CreateDirect(VDecl->getLocation(),
- SourceLocation(),
- SourceLocation())
- : InitializationKind::CreateCopy(VDecl->getLocation(),
- SourceLocation());
- InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1);
- if (InitSeq) {
- OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, (void**)&Init, 1),
- &DclT);
- if (Result.isInvalid()) {
- VDecl->setInvalidDecl();
- return;
- }
-
- Init = Result.takeAs<Expr>();
- } else {
- InitSeq.Diagnose(*this, Entity, Kind, &Init, 1);
- VDecl->setInvalidDecl();
- return;
- }
- } else if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
- VDecl->getDeclName(), DirectInit))
+ InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1);
+ OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind,
+ MultiExprArg(*this, (void**)&Init, 1),
+ &DclT);
+ if (Result.isInvalid()) {
VDecl->setInvalidDecl();
+ return;
+ }
+
+ Init = Result.takeAs<Expr>();
// C++ 3.6.2p2, allow dynamic initialization of static initializers.
// Don't check invalid declarations to avoid emitting useless diagnostics.
@@ -3601,10 +3673,18 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
} else if (VDecl->isFileVarDecl()) {
if (VDecl->getStorageClass() == VarDecl::Extern)
Diag(VDecl->getLocation(), diag::warn_extern_init);
- if (!VDecl->isInvalidDecl())
- if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
- VDecl->getDeclName(), DirectInit))
+ if (!VDecl->isInvalidDecl()) {
+ InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1);
+ OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind,
+ MultiExprArg(*this, (void**)&Init, 1),
+ &DclT);
+ if (Result.isInvalid()) {
VDecl->setInvalidDecl();
+ return;
+ }
+
+ Init = Result.takeAs<Expr>();
+ }
// C++ 3.6.2p2, allow dynamic initialization of static initializers.
// Don't check invalid declarations to avoid emitting useless diagnostics.
@@ -3622,8 +3702,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
Init->setType(DclT);
}
- Init = MaybeCreateCXXExprWithTemporaries(Init,
- /*ShouldDestroyTemporaries=*/true);
+ Init = MaybeCreateCXXExprWithTemporaries(Init);
// Attach the initializer to the decl.
VDecl->setInit(Context, Init);
@@ -3635,6 +3714,15 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
assert(Deleted && "Unrecorded tentative definition?"); Deleted=Deleted;
}
+ if (getLangOptions().CPlusPlus) {
+ // Make sure we mark the destructor as used if necessary.
+ QualType InitType = VDecl->getType();
+ if (const ArrayType *Array = Context.getAsArrayType(InitType))
+ InitType = Context.getBaseElementType(Array);
+ if (InitType->isRecordType())
+ FinalizeVarWithDestructor(VDecl, InitType);
+ }
+
return;
}
@@ -3722,28 +3810,19 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
InitType->isRecordType() && !InitType->isDependentType()) {
if (!RequireCompleteType(Var->getLocation(), InitType,
diag::err_invalid_incomplete_type_use)) {
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
-
- CXXConstructorDecl *Constructor
- = PerformInitializationByConstructor(InitType,
- MultiExprArg(*this, 0, 0),
- Var->getLocation(),
- SourceRange(Var->getLocation(),
- Var->getLocation()),
- Var->getDeclName(),
- InitializationKind::CreateDefault(Var->getLocation()),
- ConstructorArgs);
-
- // FIXME: Location info for the variable initialization?
- if (!Constructor)
+ InitializedEntity Entity
+ = InitializedEntity::InitializeVariable(Var);
+ InitializationKind Kind
+ = InitializationKind::CreateDefault(Var->getLocation());
+
+ InitializationSequence InitSeq(*this, Entity, Kind, 0, 0);
+ OwningExprResult Init = InitSeq.Perform(*this, Entity, Kind,
+ MultiExprArg(*this, 0, 0));
+ if (Init.isInvalid())
Var->setInvalidDecl();
else {
- // FIXME: Cope with initialization of arrays
- if (!Constructor->isTrivial() &&
- InitializeVarWithConstructor(Var, Constructor,
- move_arg(ConstructorArgs)))
- Var->setInvalidDecl();
-
+ Var->setInit(Context,
+ MaybeCreateCXXExprWithTemporaries(Init.takeAs<Expr>()));
FinalizeVarWithDestructor(Var, InitType);
}
} else {
@@ -4382,6 +4461,10 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
if (Context.BuiltinInfo.isNoReturn(BuiltinID))
FD->addAttr(::new (Context) NoReturnAttr());
+ if (Context.BuiltinInfo.isNoThrow(BuiltinID))
+ FD->addAttr(::new (Context) NoThrowAttr());
+ if (Context.BuiltinInfo.isConst(BuiltinID))
+ FD->addAttr(::new (Context) ConstAttr());
}
IdentifierInfo *Name = FD->getIdentifier();
@@ -4939,31 +5022,36 @@ void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) {
// Enter the tag context.
PushDeclContext(S, Tag);
+}
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Tag)) {
- FieldCollector->StartClass();
-
- if (Record->getIdentifier()) {
- // C++ [class]p2:
- // [...] The class-name is also inserted into the scope of the
- // class itself; this is known as the injected-class-name. For
- // purposes of access checking, the injected-class-name is treated
- // as if it were a public member name.
- CXXRecordDecl *InjectedClassName
- = CXXRecordDecl::Create(Context, Record->getTagKind(),
- CurContext, Record->getLocation(),
- Record->getIdentifier(),
- Record->getTagKeywordLoc(),
- Record);
- InjectedClassName->setImplicit();
- InjectedClassName->setAccess(AS_public);
- if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate())
- InjectedClassName->setDescribedClassTemplate(Template);
- PushOnScopeChains(InjectedClassName, S);
- assert(InjectedClassName->isInjectedClassName() &&
- "Broken injected-class-name");
- }
- }
+void Sema::ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagD,
+ SourceLocation LBraceLoc) {
+ AdjustDeclIfTemplate(TagD);
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(TagD.getAs<Decl>());
+
+ FieldCollector->StartClass();
+
+ if (!Record->getIdentifier())
+ return;
+
+ // C++ [class]p2:
+ // [...] The class-name is also inserted into the scope of the
+ // class itself; this is known as the injected-class-name. For
+ // purposes of access checking, the injected-class-name is treated
+ // as if it were a public member name.
+ CXXRecordDecl *InjectedClassName
+ = CXXRecordDecl::Create(Context, Record->getTagKind(),
+ CurContext, Record->getLocation(),
+ Record->getIdentifier(),
+ Record->getTagKeywordLoc(),
+ Record);
+ InjectedClassName->setImplicit();
+ InjectedClassName->setAccess(AS_public);
+ if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate())
+ InjectedClassName->setDescribedClassTemplate(Template);
+ PushOnScopeChains(InjectedClassName, S);
+ assert(InjectedClassName->isInjectedClassName() &&
+ "Broken injected-class-name");
}
void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
@@ -5808,7 +5896,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
const llvm::APSInt &InitVal = ECD->getInitVal();
assert(InitVal.getBitWidth() >= IntWidth &&
"Should have promoted value to int");
- if (InitVal.getBitWidth() > IntWidth) {
+ if (!getLangOptions().CPlusPlus && InitVal.getBitWidth() > IntWidth) {
llvm::APSInt V(InitVal);
V.trunc(IntWidth);
V.extend(InitVal.getBitWidth());
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 84ee207..094e5b5 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -47,7 +47,7 @@ static const FunctionType *getFunctionType(const Decl *d,
// FIXME: We should provide an abstraction around a method or function
// to provide the following bits of information.
-/// isFunctionOrMethod - Return true if the given decl has function
+/// isFunction - Return true if the given decl has function
/// type (function or function-typed variable).
static bool isFunction(const Decl *d) {
return getFunctionType(d, false) != NULL;
@@ -730,15 +730,19 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S)
return;
}
- // TODO: could also be applied to methods?
- FunctionDecl *Fn = dyn_cast<FunctionDecl>(D);
- if (!Fn) {
+ if (!isFunctionOrMethod(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
return;
}
- Fn->addAttr(::new (S.Context) WarnUnusedResultAttr());
+ if (getFunctionType(D)->getResultType()->isVoidType()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_void_function)
+ << Attr.getName();
+ return;
+ }
+
+ D->addAttr(::new (S.Context) WarnUnusedResultAttr());
}
static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) {
@@ -1610,7 +1614,10 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
return;
}
- NewTy = S.Context.getFixedWidthIntType(128, OldTy->isSignedIntegerType());
+ if (OldTy->isSignedIntegerType())
+ NewTy = S.Context.Int128Ty;
+ else
+ NewTy = S.Context.UnsignedInt128Ty;
break;
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 228a716..204d776 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -109,8 +109,6 @@ namespace {
bool
Sema::SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg,
SourceLocation EqualLoc) {
- QualType ParamType = Param->getType();
-
if (RequireCompleteType(Param->getLocation(), Param->getType(),
diag::err_typecheck_decl_incomplete_type)) {
Param->setInvalidDecl();
@@ -125,11 +123,17 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg,
// the same semantic constraints as the initializer expression in
// a declaration of a variable of the parameter type, using the
// copy-initialization semantics (8.5).
- if (CheckInitializerTypes(Arg, ParamType, EqualLoc,
- Param->getDeclName(), /*DirectInit=*/false))
+ InitializedEntity Entity = InitializedEntity::InitializeParameter(Param);
+ InitializationKind Kind = InitializationKind::CreateCopy(Param->getLocation(),
+ EqualLoc);
+ InitializationSequence InitSeq(*this, Entity, Kind, &Arg, 1);
+ OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind,
+ MultiExprArg(*this, (void**)&Arg, 1));
+ if (Result.isInvalid())
return true;
+ Arg = Result.takeAs<Expr>();
- Arg = MaybeCreateCXXExprWithTemporaries(Arg, /*DestroyTemps=*/false);
+ Arg = MaybeCreateCXXExprWithTemporaries(Arg);
// Okay: add the default argument to the parameter
Param->setDefaultArg(Arg);
@@ -152,7 +156,6 @@ Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc,
UnparsedDefaultArgLocs.erase(Param);
ExprOwningPtr<Expr> DefaultArg(this, defarg.takeAs<Expr>());
- QualType ParamType = Param->getType();
// Default arguments are only permitted in C++
if (!getLangOptions().CPlusPlus) {
@@ -945,6 +948,51 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
return DeclPtrTy::make(Member);
}
+/// \brief Find the direct and/or virtual base specifiers that
+/// correspond to the given base type, for use in base initialization
+/// within a constructor.
+static bool FindBaseInitializer(Sema &SemaRef,
+ CXXRecordDecl *ClassDecl,
+ QualType BaseType,
+ const CXXBaseSpecifier *&DirectBaseSpec,
+ const CXXBaseSpecifier *&VirtualBaseSpec) {
+ // First, check for a direct base class.
+ DirectBaseSpec = 0;
+ for (CXXRecordDecl::base_class_const_iterator Base
+ = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ if (SemaRef.Context.hasSameUnqualifiedType(BaseType, Base->getType())) {
+ // We found a direct base of this type. That's what we're
+ // initializing.
+ DirectBaseSpec = &*Base;
+ break;
+ }
+ }
+
+ // Check for a virtual base class.
+ // FIXME: We might be able to short-circuit this if we know in advance that
+ // there are no virtual bases.
+ VirtualBaseSpec = 0;
+ if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) {
+ // We haven't found a base yet; search the class hierarchy for a
+ // virtual base class.
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (SemaRef.IsDerivedFrom(SemaRef.Context.getTypeDeclType(ClassDecl),
+ BaseType, Paths)) {
+ for (CXXBasePaths::paths_iterator Path = Paths.begin();
+ Path != Paths.end(); ++Path) {
+ if (Path->back().Base->isVirtual()) {
+ VirtualBaseSpec = Path->back().Base;
+ break;
+ }
+ }
+ }
+ }
+
+ return DirectBaseSpec || VirtualBaseSpec;
+}
+
/// ActOnMemInitializer - Handle a C++ member initializer.
Sema::MemInitResult
Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
@@ -1000,16 +1048,69 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
}
// It didn't name a member, so see if it names a class.
QualType BaseType;
-
TypeSourceInfo *TInfo = 0;
- if (TemplateTypeTy)
+
+ if (TemplateTypeTy) {
BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo);
- else
- BaseType = QualType::getFromOpaquePtr(getTypeName(*MemberOrBase, IdLoc,
- S, &SS));
- if (BaseType.isNull())
- return Diag(IdLoc, diag::err_mem_init_not_member_or_class)
- << MemberOrBase << SourceRange(IdLoc, RParenLoc);
+ } else {
+ LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName);
+ LookupParsedName(R, S, &SS);
+
+ TypeDecl *TyD = R.getAsSingle<TypeDecl>();
+ if (!TyD) {
+ if (R.isAmbiguous()) return true;
+
+ // If no results were found, try to correct typos.
+ if (R.empty() &&
+ CorrectTypo(R, S, &SS, ClassDecl) && R.isSingleResult()) {
+ if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) {
+ if (Member->getDeclContext()->getLookupContext()->Equals(ClassDecl)) {
+ // We have found a non-static data member with a similar
+ // name to what was typed; complain and initialize that
+ // member.
+ Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
+ << MemberOrBase << true << R.getLookupName()
+ << CodeModificationHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
+
+ return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
+ LParenLoc, RParenLoc);
+ }
+ } else if (TypeDecl *Type = R.getAsSingle<TypeDecl>()) {
+ const CXXBaseSpecifier *DirectBaseSpec;
+ const CXXBaseSpecifier *VirtualBaseSpec;
+ if (FindBaseInitializer(*this, ClassDecl,
+ Context.getTypeDeclType(Type),
+ DirectBaseSpec, VirtualBaseSpec)) {
+ // We have found a direct or virtual base class with a
+ // similar name to what was typed; complain and initialize
+ // that base class.
+ Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
+ << MemberOrBase << false << R.getLookupName()
+ << CodeModificationHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
+
+ TyD = Type;
+ }
+ }
+ }
+
+ if (!TyD) {
+ Diag(IdLoc, diag::err_mem_init_not_member_or_class)
+ << MemberOrBase << SourceRange(IdLoc, RParenLoc);
+ return true;
+ }
+ }
+
+ BaseType = Context.getTypeDeclType(TyD);
+ if (SS.isSet()) {
+ NestedNameSpecifier *Qualifier =
+ static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+
+ // FIXME: preserve source range information
+ BaseType = Context.getQualifiedNameType(Qualifier, BaseType);
+ }
+ }
if (!TInfo)
TInfo = Context.getTrivialTypeSourceInfo(BaseType, IdLoc);
@@ -1095,14 +1196,13 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
QualType FieldType = Member->getType();
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
if (FieldType->isDependentType()) {
// Can't check init for dependent type.
} else if (FieldType->isRecordType()) {
// Member is a record (struct/union/class), so pass the initializer
// arguments down to the record's constructor.
if (!HasDependentArg) {
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
-
C = PerformInitializationByConstructor(FieldType,
MultiExprArg(*this,
(void**)Args,
@@ -1137,7 +1237,8 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
}
else
NewExp = (Expr*)Args[0];
- if (PerformCopyInitialization(NewExp, FieldType, "passing"))
+ if (!Member->isInvalidDecl() &&
+ PerformCopyInitialization(NewExp, FieldType, AA_Passing))
return true;
Args[0] = NewExp;
}
@@ -1174,37 +1275,11 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// mem-initializer-list can initialize a base class using any
// name that denotes that base class type.
- // First, check for a direct base class.
+ // Check for direct and virtual base classes.
const CXXBaseSpecifier *DirectBaseSpec = 0;
- for (CXXRecordDecl::base_class_const_iterator Base =
- ClassDecl->bases_begin(); Base != ClassDecl->bases_end(); ++Base) {
- if (Context.hasSameUnqualifiedType(BaseType, Base->getType())) {
- // We found a direct base of this type. That's what we're
- // initializing.
- DirectBaseSpec = &*Base;
- break;
- }
- }
-
- // Check for a virtual base class.
- // FIXME: We might be able to short-circuit this if we know in advance that
- // there are no virtual bases.
const CXXBaseSpecifier *VirtualBaseSpec = 0;
- if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) {
- // We haven't found a base yet; search the class hierarchy for a
- // virtual base class.
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
- /*DetectVirtual=*/false);
- if (IsDerivedFrom(Context.getTypeDeclType(ClassDecl), BaseType, Paths)) {
- for (CXXBasePaths::paths_iterator Path = Paths.begin();
- Path != Paths.end(); ++Path) {
- if (Path->back().Base->isVirtual()) {
- VirtualBaseSpec = Path->back().Base;
- break;
- }
- }
- }
- }
+ FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
+ VirtualBaseSpec);
// C++ [base.class.init]p2:
// If a mem-initializer-id is ambiguous because it designates both
@@ -1224,10 +1299,10 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
}
CXXConstructorDecl *C = 0;
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
if (!BaseType->isDependentType() && !HasDependentArg) {
DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(BaseType).getUnqualifiedType());
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
C = PerformInitializationByConstructor(BaseType,
MultiExprArg(*this,
@@ -1977,6 +2052,12 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
if (!Record || Record->isInvalidDecl())
return;
+ if (!Record->isDependentType())
+ AddImplicitlyDeclaredMembersToClass(Record);
+
+ if (Record->isInvalidDecl())
+ return;
+
if (!Record->isAbstract()) {
// Collect all the pure virtual methods and see if this is an abstract
// class after all.
@@ -1987,9 +2068,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
if (Record->isAbstract())
(void)AbstractClassUsageDiagnoser(*this, Record);
-
- if (!Record->isDependentType() && !Record->isInvalidDecl())
- AddImplicitlyDeclaredMembersToClass(Record);
}
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
@@ -2261,6 +2339,18 @@ void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) {
}
}
+void Sema::ActOnStartDelayedMemberDeclarations(Scope *S, DeclPtrTy RecordD) {
+ if (!RecordD) return;
+ AdjustDeclIfTemplate(RecordD);
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordD.getAs<Decl>());
+ PushDeclContext(S, Record);
+}
+
+void Sema::ActOnFinishDelayedMemberDeclarations(Scope *S, DeclPtrTy RecordD) {
+ if (!RecordD) return;
+ PopDeclContext();
+}
+
/// ActOnStartDelayedCXXMethodDeclaration - We have completed
/// parsing a top-level (non-nested) C++ class, and we are now
/// parsing those parts of the given Method declaration that could
@@ -2270,18 +2360,6 @@ void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) {
/// name. However, it should not bring the parameters into scope;
/// that will be performed by ActOnDelayedCXXMethodParameter.
void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) {
- if (!MethodD)
- return;
-
- AdjustDeclIfTemplate(MethodD);
-
- CXXScopeSpec SS;
- FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>());
- QualType ClassTy
- = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
- SS.setScopeRep(
- NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr()));
- ActOnCXXEnterDeclaratorScope(S, SS);
}
/// ActOnDelayedCXXMethodParameter - We've already started a delayed
@@ -2318,12 +2396,6 @@ void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) {
AdjustDeclIfTemplate(MethodD);
FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>());
- CXXScopeSpec SS;
- QualType ClassTy
- = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
- SS.setScopeRep(
- NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr()));
- ActOnCXXExitDeclaratorScope(S, SS);
// Now that we have our default arguments, check the constructor
// again. It could produce additional diagnostics or affect whether
@@ -2746,6 +2818,28 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
PushOnScopeChains(Namespc, DeclRegionScope);
} else {
// Anonymous namespaces.
+ assert(Namespc->isAnonymousNamespace());
+ CurContext->addDecl(Namespc);
+
+ // Link the anonymous namespace into its parent.
+ NamespaceDecl *PrevDecl;
+ DeclContext *Parent = CurContext->getLookupContext();
+ if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(Parent)) {
+ PrevDecl = TU->getAnonymousNamespace();
+ TU->setAnonymousNamespace(Namespc);
+ } else {
+ NamespaceDecl *ND = cast<NamespaceDecl>(Parent);
+ PrevDecl = ND->getAnonymousNamespace();
+ ND->setAnonymousNamespace(Namespc);
+ }
+
+ // Link the anonymous namespace with its previous declaration.
+ if (PrevDecl) {
+ assert(PrevDecl->isAnonymousNamespace());
+ assert(!PrevDecl->getNextNamespace());
+ Namespc->setOriginalNamespace(PrevDecl->getOriginalNamespace());
+ PrevDecl->setNextNamespace(Namespc);
+ }
// C++ [namespace.unnamed]p1. An unnamed-namespace-definition
// behaves as if it were replaced by
@@ -2763,20 +2857,19 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// declarations semantically contained within an anonymous
// namespace internal linkage.
- assert(Namespc->isAnonymousNamespace());
- CurContext->addDecl(Namespc);
-
- UsingDirectiveDecl* UD
- = UsingDirectiveDecl::Create(Context, CurContext,
- /* 'using' */ LBrace,
- /* 'namespace' */ SourceLocation(),
- /* qualifier */ SourceRange(),
- /* NNS */ NULL,
- /* identifier */ SourceLocation(),
- Namespc,
- /* Ancestor */ CurContext);
- UD->setImplicit();
- CurContext->addDecl(UD);
+ if (!PrevDecl) {
+ UsingDirectiveDecl* UD
+ = UsingDirectiveDecl::Create(Context, CurContext,
+ /* 'using' */ LBrace,
+ /* 'namespace' */ SourceLocation(),
+ /* qualifier */ SourceRange(),
+ /* NNS */ NULL,
+ /* identifier */ SourceLocation(),
+ Namespc,
+ /* Ancestor */ CurContext);
+ UD->setImplicit();
+ CurContext->addDecl(UD);
+ }
}
// Although we could have an invalid decl (i.e. the namespace name is a
@@ -3696,7 +3789,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *CopyConstructor,
unsigned TypeQuals) {
assert((CopyConstructor->isImplicit() &&
- CopyConstructor->isCopyConstructor(Context, TypeQuals) &&
+ CopyConstructor->isCopyConstructor(TypeQuals) &&
!CopyConstructor->isUsed()) &&
"DefineImplicitCopyConstructor - call it for implicit copy ctor");
@@ -3736,7 +3829,8 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
Sema::OwningExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor,
- MultiExprArg ExprArgs) {
+ MultiExprArg ExprArgs,
+ bool RequiresZeroInit) {
bool Elidable = false;
// C++ [class.copy]p15:
@@ -3747,8 +3841,13 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
// all, even if the class copy constructor or destructor have side effects.
// FIXME: Is this enough?
- if (Constructor->isCopyConstructor(Context)) {
+ if (Constructor->isCopyConstructor()) {
Expr *E = ((Expr **)ExprArgs.get())[0];
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+ if (ICE->getCastKind() == CastExpr::CK_NoOp)
+ E = ICE->getSubExpr();
+ if (CXXFunctionalCastExpr *FCE = dyn_cast<CXXFunctionalCastExpr>(E))
+ E = FCE->getSubExpr();
while (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(E))
E = BE->getSubExpr();
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
@@ -3759,10 +3858,12 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
Elidable = !CE->getCallReturnType()->isReferenceType();
else if (isa<CXXTemporaryObjectExpr>(E))
Elidable = true;
+ else if (isa<CXXConstructExpr>(E))
+ Elidable = true;
}
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
- Elidable, move(ExprArgs));
+ Elidable, move(ExprArgs), RequiresZeroInit);
}
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
@@ -3770,13 +3871,15 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
Sema::OwningExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, bool Elidable,
- MultiExprArg ExprArgs) {
+ MultiExprArg ExprArgs,
+ bool RequiresZeroInit) {
unsigned NumExprs = ExprArgs.size();
Expr **Exprs = (Expr **)ExprArgs.release();
MarkDeclarationReferenced(ConstructLoc, Constructor);
- return Owned(CXXConstructExpr::Create(Context, DeclInitType, Constructor,
- Elidable, Exprs, NumExprs));
+ return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
+ Constructor, Elidable, Exprs, NumExprs,
+ RequiresZeroInit));
}
Sema::OwningExprResult
@@ -3806,7 +3909,7 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD,
Expr *Temp = TempResult.takeAs<Expr>();
MarkDeclarationReferenced(VD->getLocation(), Constructor);
- Temp = MaybeCreateCXXExprWithTemporaries(Temp, /*DestroyTemps=*/true);
+ Temp = MaybeCreateCXXExprWithTemporaries(Temp);
VD->setInit(Context, Temp);
return false;
@@ -3829,8 +3932,7 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
MultiExprArg Exprs,
SourceLocation *CommaLocs,
SourceLocation RParenLoc) {
- unsigned NumExprs = Exprs.size();
- assert(NumExprs != 0 && Exprs.get() && "missing expressions");
+ assert(Exprs.size() != 0 && Exprs.get() && "missing expressions");
Decl *RealDecl = Dcl.getAs<Decl>();
// If there is no declaration, there was an error parsing it. Just ignore
@@ -3881,53 +3983,50 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
if (const ArrayType *Array = Context.getAsArrayType(DeclInitType))
DeclInitType = Context.getBaseElementType(Array);
- // FIXME: This isn't the right place to complete the type.
if (RequireCompleteType(VDecl->getLocation(), VDecl->getType(),
diag::err_typecheck_decl_incomplete_type)) {
VDecl->setInvalidDecl();
return;
}
- if (VDecl->getType()->isRecordType()) {
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
-
- CXXConstructorDecl *Constructor
- = PerformInitializationByConstructor(DeclInitType,
- move(Exprs),
- VDecl->getLocation(),
- SourceRange(VDecl->getLocation(),
- RParenLoc),
- VDecl->getDeclName(),
- InitializationKind::CreateDirect(VDecl->getLocation(),
- LParenLoc,
- RParenLoc),
- ConstructorArgs);
- if (!Constructor)
- RealDecl->setInvalidDecl();
- else {
- VDecl->setCXXDirectInitializer(true);
- if (InitializeVarWithConstructor(VDecl, Constructor,
- move_arg(ConstructorArgs)))
- RealDecl->setInvalidDecl();
- FinalizeVarWithDestructor(VDecl, DeclInitType);
- }
+ // The variable can not have an abstract class type.
+ if (RequireNonAbstractType(VDecl->getLocation(), VDecl->getType(),
+ diag::err_abstract_type_in_decl,
+ AbstractVariableType))
+ VDecl->setInvalidDecl();
+
+ const VarDecl *Def = 0;
+ if (VDecl->getDefinition(Def)) {
+ Diag(VDecl->getLocation(), diag::err_redefinition)
+ << VDecl->getDeclName();
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ VDecl->setInvalidDecl();
return;
}
-
- if (NumExprs > 1) {
- Diag(CommaLocs[0], diag::err_builtin_direct_init_more_than_one_arg)
- << SourceRange(VDecl->getLocation(), RParenLoc);
- RealDecl->setInvalidDecl();
+
+ // Capture the variable that is being initialized and the style of
+ // initialization.
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
+
+ // FIXME: Poor source location information.
+ InitializationKind Kind
+ = InitializationKind::CreateDirect(VDecl->getLocation(),
+ LParenLoc, RParenLoc);
+
+ InitializationSequence InitSeq(*this, Entity, Kind,
+ (Expr**)Exprs.get(), Exprs.size());
+ OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(Exprs));
+ if (Result.isInvalid()) {
+ VDecl->setInvalidDecl();
return;
}
-
- // Let clients know that initialization was done with a direct initializer.
+
+ Result = MaybeCreateCXXExprWithTemporaries(move(Result));
+ VDecl->setInit(Context, Result.takeAs<Expr>());
VDecl->setCXXDirectInitializer(true);
- assert(NumExprs == 1 && "Expected 1 expression");
- // Set the init expression, handles conversions.
- AddInitializerToDecl(Dcl, ExprArg(*this, Exprs.release()[0]),
- /*DirectInit=*/true);
+ if (VDecl->getType()->getAs<RecordType>())
+ FinalizeVarWithDestructor(VDecl, DeclInitType);
}
/// \brief Add the applicable constructor candidates for an initialization
@@ -4164,7 +4263,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
/// type, and the first type (T1) is the pointee type of the reference
/// type being initialized.
Sema::ReferenceCompareResult
-Sema::CompareReferenceRelationship(SourceLocation Loc,
+Sema::CompareReferenceRelationship(SourceLocation Loc,
QualType OrigT1, QualType OrigT2,
bool& DerivedToBase) {
assert(!OrigT1->isReferenceType() &&
@@ -4173,8 +4272,9 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
QualType T1 = Context.getCanonicalType(OrigT1);
QualType T2 = Context.getCanonicalType(OrigT2);
- QualType UnqualT1 = T1.getLocalUnqualifiedType();
- QualType UnqualT2 = T2.getLocalUnqualifiedType();
+ Qualifiers T1Quals, T2Quals;
+ QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
+ QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
// C++ [dcl.init.ref]p4:
// Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
@@ -4192,6 +4292,13 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
// At this point, we know that T1 and T2 are reference-related (at
// least).
+ // If the type is an array type, promote the element qualifiers to the type
+ // for comparison.
+ if (isa<ArrayType>(T1) && T1Quals)
+ T1 = Context.getQualifiedType(UnqualT1, T1Quals);
+ if (isa<ArrayType>(T2) && T2Quals)
+ T2 = Context.getQualifiedType(UnqualT2, T2Quals);
+
// C++ [dcl.init.ref]p4:
// "cv1 T1" is reference-compatible with "cv2 T2" if T1 is
// reference-related to T2 and cv1 is the same cv-qualification
@@ -4199,7 +4306,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
// overload resolution, cases for which cv1 is greater
// cv-qualification than cv2 are identified as
// reference-compatible with added qualification (see 13.3.3.2).
- if (T1.getCVRQualifiers() == T2.getCVRQualifiers())
+ if (T1Quals.getCVRQualifiers() == T2Quals.getCVRQualifiers())
return Ref_Compatible;
else if (T1.isMoreQualifiedThan(T2))
return Ref_Compatible_With_Added_Qualification;
@@ -4462,7 +4569,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
if (!isRValRef && T1.getCVRQualifiers() != Qualifiers::Const) {
if (!ICS)
Diag(DeclLoc, diag::err_not_reference_to_const_init)
- << T1 << (InitLvalue != Expr::LV_Valid? "temporary" : "value")
+ << T1 << int(InitLvalue != Expr::LV_Valid)
<< T2 << Init->getSourceRange();
return true;
}
@@ -4528,7 +4635,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// initialization fails.
if (!ICS)
Diag(DeclLoc, diag::err_reference_init_drops_quals)
- << T1 << (InitLvalue != Expr::LV_Valid? "temporary" : "value")
+ << T1 << int(InitLvalue != Expr::LV_Valid)
<< T2 << Init->getSourceRange();
return true;
}
@@ -4542,7 +4649,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
(T1->isRecordType() || T2->isRecordType())) {
if (!ICS)
Diag(DeclLoc, diag::err_typecheck_convert_incompatible)
- << DeclType << Init->getType() << "initializing" << Init->getSourceRange();
+ << DeclType << Init->getType() << AA_Initializing << Init->getSourceRange();
return true;
}
@@ -4576,7 +4683,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
return ICS->ConversionKind == ImplicitConversionSequence::BadConversion;
} else {
ImplicitConversionSequence Conversions;
- bool badConversion = PerformImplicitConversion(Init, T1, "initializing",
+ bool badConversion = PerformImplicitConversion(Init, T1, AA_Initializing,
false, false,
Conversions);
if (badConversion) {
@@ -4664,7 +4771,7 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
<< FnDecl->getDeclName() << ExpectedFirstParamType;
// Check that the first parameter type is what we expect.
- if (SemaRef.Context.getCanonicalType(FirstParamType) !=
+ if (SemaRef.Context.getCanonicalType(FirstParamType).getUnqualifiedType() !=
ExpectedFirstParamType)
return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag)
<< FnDecl->getDeclName() << ExpectedFirstParamType;
@@ -5154,13 +5261,10 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// C++98 [class.friend]p1: A friend of a class is a function
// or class that is not a member of the class . . .
- // But that's a silly restriction which nobody implements for
- // inner classes, and C++0x removes it anyway, so we only report
- // this (as a warning) if we're being pedantic.
- if (!getLangOptions().CPlusPlus0x)
- if (const RecordType *RT = T->getAs<RecordType>())
- if (RT->getDecl()->getDeclContext() == CurContext)
- Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class);
+ // This is fixed in DR77, which just barely didn't make the C++03
+ // deadline. It's also a very silly restriction that seriously
+ // affects inner classes and which nobody else seems to implement;
+ // thus we never diagnose it, not even in -pedantic.
Decl *D;
if (TempParams.size())
@@ -5341,6 +5445,9 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
FrD->setAccess(AS_public);
CurContext->addDecl(FrD);
+ if (D.getName().getKind() == UnqualifiedId::IK_TemplateId)
+ FrD->setSpecialization(true);
+
return DeclPtrTy::make(ND);
}
@@ -5421,6 +5528,18 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
return true;
}
+ // C++ [class.virtual]p6:
+ // If the return type of D::f differs from the return type of B::f, the
+ // class type in the return type of D::f shall be complete at the point of
+ // declaration of D::f or shall be the class type D.
+ if (const RecordType *RT = NewClassTy->getAs<RecordType>()) {
+ if (!RT->isBeingDefined() &&
+ RequireCompleteType(New->getLocation(), NewClassTy,
+ PDiag(diag::err_covariant_return_incomplete)
+ << New->getDeclName()))
+ return true;
+ }
+
if (!Context.hasSameUnqualifiedType(NewClassTy, OldClassTy)) {
// Check if the new class derives from the old class.
if (!IsDerivedFrom(NewClassTy, OldClassTy)) {
@@ -5497,50 +5616,32 @@ bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) {
return true;
}
-/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an
-/// initializer for the declaration 'Dcl'.
+/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse
+/// an initializer for the out-of-line declaration 'Dcl'. The scope
+/// is a fresh scope pushed for just this purpose.
+///
/// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a
/// static data member of class X, names should be looked up in the scope of
/// class X.
void Sema::ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) {
- AdjustDeclIfTemplate(Dcl);
-
- Decl *D = Dcl.getAs<Decl>();
// If there is no declaration, there was an error parsing it.
- if (D == 0)
- return;
-
- // Check whether it is a declaration with a nested name specifier like
- // int foo::bar;
- if (!D->isOutOfLine())
- return;
-
- // C++ [basic.lookup.unqual]p13
- //
- // A name used in the definition of a static data member of class X
- // (after the qualified-id of the static member) is looked up as if the name
- // was used in a member function of X.
+ Decl *D = Dcl.getAs<Decl>();
+ if (D == 0) return;
- // Change current context into the context of the initializing declaration.
+ // We should only get called for declarations with scope specifiers, like:
+ // int foo::bar;
+ assert(D->isOutOfLine());
EnterDeclaratorContext(S, D->getDeclContext());
}
/// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an
-/// initializer for the declaration 'Dcl'.
+/// initializer for the out-of-line declaration 'Dcl'.
void Sema::ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl) {
- AdjustDeclIfTemplate(Dcl);
-
- Decl *D = Dcl.getAs<Decl>();
// If there is no declaration, there was an error parsing it.
- if (D == 0)
- return;
-
- // Check whether it is a declaration with a nested name specifier like
- // int foo::bar;
- if (!D->isOutOfLine())
- return;
+ Decl *D = Dcl.getAs<Decl>();
+ if (D == 0) return;
- assert(S->getEntity() == D->getDeclContext() && "Context imbalance!");
+ assert(D->isOutOfLine());
ExitDeclaratorContext(S);
}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index a768e1b..beadb58 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -1950,6 +1950,10 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
!(Attributes & ObjCDeclSpec::DQ_PR_retain) &&
!(Attributes & ObjCDeclSpec::DQ_PR_copy)));
QualType T = GetTypeForDeclarator(FD.D, S);
+ if (T->isReferenceType()) {
+ Diag(AtLoc, diag::error_reference_property);
+ return DeclPtrTy();
+ }
Decl *ClassDecl = ClassCategory.getAs<Decl>();
ObjCInterfaceDecl *CCPrimary = 0; // continuation class's primary class
// May modify Attributes.
@@ -2028,7 +2032,14 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
FD.D.getIdentifierLoc(),
FD.D.getIdentifier(), T);
- DC->addDecl(PDecl);
+ DeclContext::lookup_result Found = DC->lookup(PDecl->getDeclName());
+ if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) {
+ Diag(PDecl->getLocation(), diag::err_duplicate_property);
+ Diag((*Found.first)->getLocation(), diag::note_property_declare);
+ PDecl->setInvalidDecl();
+ }
+ else
+ DC->addDecl(PDecl);
if (T->isArrayType() || T->isFunctionType()) {
Diag(AtLoc, diag::err_property_type) << T;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 358f445..7bf04d8 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "SemaInit.h"
#include "Lookup.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -258,44 +259,17 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) {
bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) {
DefaultArgumentPromotion(Expr);
- if (Expr->getType()->isObjCInterfaceType()) {
- switch (ExprEvalContexts.back().Context ) {
- case Unevaluated:
- // The argument will never be evaluated, so don't complain.
- break;
-
- case PotentiallyEvaluated:
- Diag(Expr->getLocStart(),
- diag::err_cannot_pass_objc_interface_to_vararg)
- << Expr->getType() << CT;
- return true;
-
- case PotentiallyPotentiallyEvaluated:
- ExprEvalContexts.back().addDiagnostic(Expr->getLocStart(),
- PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
- << Expr->getType() << CT);
- break;
- }
- }
-
- if (!Expr->getType()->isPODType()) {
- switch (ExprEvalContexts.back().Context ) {
- case Unevaluated:
- // The argument will never be evaluated, so don't complain.
- break;
-
- case PotentiallyEvaluated:
- Diag(Expr->getLocStart(), diag::warn_cannot_pass_non_pod_arg_to_vararg)
- << Expr->getType() << CT;
- break;
+ if (Expr->getType()->isObjCInterfaceType() &&
+ DiagRuntimeBehavior(Expr->getLocStart(),
+ PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
+ << Expr->getType() << CT))
+ return true;
- case PotentiallyPotentiallyEvaluated:
- ExprEvalContexts.back().addDiagnostic(Expr->getLocStart(),
- PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
- << Expr->getType() << CT);
- break;
- }
- }
+ if (!Expr->getType()->isPODType() &&
+ DiagRuntimeBehavior(Expr->getLocStart(),
+ PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
+ << Expr->getType() << CT))
+ return true;
return false;
}
@@ -590,7 +564,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
== Context.getCanonicalType(ThisType)) ||
IsDerivedFrom(ThisType, AnonFieldType)) {
// Our base object expression is "this".
- BaseObjectExpr = new (Context) CXXThisExpr(SourceLocation(),
+ BaseObjectExpr = new (Context) CXXThisExpr(Loc,
MD->getThisType(Context));
BaseObjectIsPointer = true;
}
@@ -761,23 +735,9 @@ static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
return true;
}
-/// Determines if this a C++ class member.
-static bool IsClassMember(NamedDecl *D) {
- DeclContext *DC = D->getDeclContext();
-
- // C++0x [class.mem]p1:
- // The enumerators of an unscoped enumeration defined in
- // the class are members of the class.
- // FIXME: support C++0x scoped enumerations.
- if (isa<EnumDecl>(DC))
- DC = DC->getParent();
-
- return DC->isRecord();
-}
-
/// Determines if this is an instance member of a class.
static bool IsInstanceMember(NamedDecl *D) {
- assert(IsClassMember(D) &&
+ assert(D->isCXXClassMember() &&
"checking whether non-member is instance member");
if (isa<FieldDecl>(D)) return true;
@@ -839,7 +799,7 @@ enum IMAKind {
/// not be caught until template-instantiation.
static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
const LookupResult &R) {
- assert(!R.empty() && IsClassMember(*R.begin()));
+ assert(!R.empty() && (*R.begin())->isCXXClassMember());
bool isStaticContext =
(!isa<CXXMethodDecl>(SemaRef.CurContext) ||
@@ -916,6 +876,112 @@ static void DiagnoseInstanceReference(Sema &SemaRef,
SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range;
}
+/// Diagnose an empty lookup.
+///
+/// \return false if new lookup candidates were found
+bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
+ LookupResult &R) {
+ DeclarationName Name = R.getLookupName();
+
+ unsigned diagnostic = diag::err_undeclared_var_use;
+ unsigned diagnostic_suggest = diag::err_undeclared_var_use_suggest;
+ if (Name.getNameKind() == DeclarationName::CXXOperatorName ||
+ Name.getNameKind() == DeclarationName::CXXLiteralOperatorName ||
+ Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
+ diagnostic = diag::err_undeclared_use;
+ diagnostic_suggest = diag::err_undeclared_use_suggest;
+ }
+
+ // If the original lookup was an unqualified lookup, fake an
+ // unqualified lookup. This is useful when (for example) the
+ // original lookup would not have found something because it was a
+ // dependent name.
+ for (DeclContext *DC = SS.isEmpty()? CurContext : 0;
+ DC; DC = DC->getParent()) {
+ if (isa<CXXRecordDecl>(DC)) {
+ LookupQualifiedName(R, DC);
+
+ if (!R.empty()) {
+ // Don't give errors about ambiguities in this lookup.
+ R.suppressDiagnostics();
+
+ CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(CurContext);
+ bool isInstance = CurMethod &&
+ CurMethod->isInstance() &&
+ DC == CurMethod->getParent();
+
+ // Give a code modification hint to insert 'this->'.
+ // TODO: fixit for inserting 'Base<T>::' in the other cases.
+ // Actually quite difficult!
+ if (isInstance)
+ Diag(R.getNameLoc(), diagnostic) << Name
+ << CodeModificationHint::CreateInsertion(R.getNameLoc(),
+ "this->");
+ else
+ Diag(R.getNameLoc(), diagnostic) << Name;
+
+ // Do we really want to note all of these?
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
+ Diag((*I)->getLocation(), diag::note_dependent_var_use);
+
+ // Tell the callee to try to recover.
+ return false;
+ }
+ }
+ }
+
+ // We didn't find anything, so try to correct for a typo.
+ if (S && CorrectTypo(R, S, &SS)) {
+ if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) {
+ if (SS.isEmpty())
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName()
+ << CodeModificationHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
+ else
+ Diag(R.getNameLoc(), diag::err_no_member_suggest)
+ << Name << computeDeclContext(SS, false) << R.getLookupName()
+ << SS.getRange()
+ << CodeModificationHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
+
+ // Tell the callee to try to recover.
+ return false;
+ }
+
+ if (isa<TypeDecl>(*R.begin()) || isa<ObjCInterfaceDecl>(*R.begin())) {
+ // FIXME: If we ended up with a typo for a type name or
+ // Objective-C class name, we're in trouble because the parser
+ // is in the wrong place to recover. Suggest the typo
+ // correction, but don't make it a fix-it since we're not going
+ // to recover well anyway.
+ if (SS.isEmpty())
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName();
+ else
+ Diag(R.getNameLoc(), diag::err_no_member_suggest)
+ << Name << computeDeclContext(SS, false) << R.getLookupName()
+ << SS.getRange();
+
+ // Don't try to recover; it won't work.
+ return true;
+ }
+
+ R.clear();
+ }
+
+ // Emit a special diagnostic for failed member lookups.
+ // FIXME: computing the declaration context might fail here (?)
+ if (!SS.isEmpty()) {
+ Diag(R.getNameLoc(), diag::err_no_member)
+ << Name << computeDeclContext(SS, false)
+ << SS.getRange();
+ return true;
+ }
+
+ // Give up, we can't recover.
+ Diag(R.getNameLoc(), diagnostic) << Name;
+ return true;
+}
+
Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
const CXXScopeSpec &SS,
UnqualifiedId &Id,
@@ -988,17 +1054,11 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
// If this name wasn't predeclared and if this is not a function
// call, diagnose the problem.
if (R.empty()) {
- if (!SS.isEmpty())
- return ExprError(Diag(NameLoc, diag::err_no_member)
- << Name << computeDeclContext(SS, false)
- << SS.getRange());
- else if (Name.getNameKind() == DeclarationName::CXXOperatorName ||
- Name.getNameKind() == DeclarationName::CXXLiteralOperatorName ||
- Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
- return ExprError(Diag(NameLoc, diag::err_undeclared_use)
- << Name);
- else
- return ExprError(Diag(NameLoc, diag::err_undeclared_var_use) << Name);
+ if (DiagnoseEmptyLookup(S, SS, R))
+ return ExprError();
+
+ assert(!R.empty() &&
+ "DiagnoseEmptyLookup returned false but added no results");
}
}
@@ -1051,35 +1111,10 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
// class member access expression.
// But note that &SomeClass::foo is grammatically distinct, even
// though we don't parse it that way.
- if (!R.empty() && IsClassMember(*R.begin())) {
+ if (!R.empty() && (*R.begin())->isCXXClassMember()) {
bool isAbstractMemberPointer = (isAddressOfOperand && !SS.isEmpty());
-
- if (!isAbstractMemberPointer) {
- switch (ClassifyImplicitMemberAccess(*this, R)) {
- case IMA_Instance:
- return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
-
- case IMA_AnonymousMember:
- assert(R.isSingleResult());
- return BuildAnonymousStructUnionMemberReference(R.getNameLoc(),
- R.getAsSingle<FieldDecl>());
-
- case IMA_Mixed:
- case IMA_Mixed_Unrelated:
- case IMA_Unresolved:
- return BuildImplicitMemberExpr(SS, R, TemplateArgs, false);
-
- case IMA_Static:
- case IMA_Mixed_StaticContext:
- case IMA_Unresolved_StaticContext:
- break;
-
- case IMA_Error_StaticContext:
- case IMA_Error_Unrelated:
- DiagnoseInstanceReference(*this, SS, R);
- return ExprError();
- }
- }
+ if (!isAbstractMemberPointer)
+ return BuildPossibleImplicitMemberExpr(SS, R, TemplateArgs);
}
if (TemplateArgs)
@@ -1088,6 +1123,42 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
return BuildDeclarationNameExpr(SS, R, ADL);
}
+/// Builds an expression which might be an implicit member expression.
+Sema::OwningExprResult
+Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ switch (ClassifyImplicitMemberAccess(*this, R)) {
+ case IMA_Instance:
+ return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
+
+ case IMA_AnonymousMember:
+ assert(R.isSingleResult());
+ return BuildAnonymousStructUnionMemberReference(R.getNameLoc(),
+ R.getAsSingle<FieldDecl>());
+
+ case IMA_Mixed:
+ case IMA_Mixed_Unrelated:
+ case IMA_Unresolved:
+ return BuildImplicitMemberExpr(SS, R, TemplateArgs, false);
+
+ case IMA_Static:
+ case IMA_Mixed_StaticContext:
+ case IMA_Unresolved_StaticContext:
+ if (TemplateArgs)
+ return BuildTemplateIdExpr(SS, R, false, *TemplateArgs);
+ return BuildDeclarationNameExpr(SS, R, false);
+
+ case IMA_Error_StaticContext:
+ case IMA_Error_Unrelated:
+ DiagnoseInstanceReference(*this, SS, R);
+ return ExprError();
+ }
+
+ llvm_unreachable("unexpected instance member access kind");
+ return ExprError();
+}
+
/// BuildQualifiedDeclarationNameExpr - Build a C++ qualified
/// declaration name, generally during template instantiation.
/// There's a large number of things which don't need to be done along
@@ -1315,7 +1386,7 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
// -- a declaration of a class member
// Since using decls preserve this property, we check this on the
// original decl.
- if (IsClassMember(D))
+ if (D->isCXXClassMember())
return false;
// C++0x [basic.lookup.argdep]p3:
@@ -1408,7 +1479,6 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
assert(D && "Cannot refer to a NULL declaration");
assert(!isa<FunctionTemplateDecl>(D) &&
"Cannot refer unambiguously to a function template");
- DeclarationName Name = D->getDeclName();
if (CheckDeclInExpr(*this, Loc, D))
return ExprError();
@@ -1427,7 +1497,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
if (!VD) {
Diag(Loc, diag::err_ref_non_value)
<< D << SS.getRange();
- Diag(D->getLocation(), diag::note_previous_declaration);
+ Diag(D->getLocation(), diag::note_declared_at);
return ExprError();
}
@@ -1515,11 +1585,17 @@ Sema::OwningExprResult Sema::ActOnCharacterConstant(const Token &Tok) {
if (Literal.hadError())
return ExprError();
- QualType type = getLangOptions().CPlusPlus ? Context.CharTy : Context.IntTy;
+ QualType Ty;
+ if (!getLangOptions().CPlusPlus)
+ Ty = Context.IntTy; // 'x' and L'x' -> int in C.
+ else if (Literal.isWide())
+ Ty = Context.WCharTy; // L'x' -> wchar_t in C++.
+ else
+ Ty = Context.CharTy; // 'x' -> char in C++
return Owned(new (Context) CharacterLiteral(Literal.getValue(),
Literal.isWide(),
- type, Tok.getLocation()));
+ Ty, Tok.getLocation()));
}
Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) {
@@ -1558,9 +1634,31 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) {
const llvm::fltSemantics &Format = Context.getFloatTypeSemantics(Ty);
- // isExact will be set by GetFloatValue().
- bool isExact = false;
- llvm::APFloat Val = Literal.GetFloatValue(Format, &isExact);
+ using llvm::APFloat;
+ APFloat Val(Format);
+
+ APFloat::opStatus result = Literal.GetFloatValue(Val);
+
+ // Overflow is always an error, but underflow is only an error if
+ // we underflowed to zero (APFloat reports denormals as underflow).
+ if ((result & APFloat::opOverflow) ||
+ ((result & APFloat::opUnderflow) && Val.isZero())) {
+ unsigned diagnostic;
+ llvm::SmallVector<char, 20> buffer;
+ if (result & APFloat::opOverflow) {
+ diagnostic = diag::err_float_overflow;
+ APFloat::getLargest(Format).toString(buffer);
+ } else {
+ diagnostic = diag::err_float_underflow;
+ APFloat::getSmallest(Format).toString(buffer);
+ }
+
+ Diag(Tok.getLocation(), diagnostic)
+ << Ty
+ << llvm::StringRef(buffer.data(), buffer.size());
+ }
+
+ bool isExact = (result == APFloat::opOK);
Res = new (Context) FloatingLiteral(Val, isExact, Ty, Tok.getLocation());
} else if (!Literal.isIntegerLiteral()) {
@@ -1698,9 +1796,8 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType,
}
if (RequireCompleteType(OpLoc, exprType,
- isSizeof ? diag::err_sizeof_incomplete_type :
- PDiag(diag::err_alignof_incomplete_type)
- << ExprRange))
+ PDiag(diag::err_sizeof_alignof_incomplete_type)
+ << int(!isSizeof) << ExprRange))
return true;
// Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
@@ -2054,20 +2151,12 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
}
}
- // If this is a halving swizzle, verify that the base type has an even
- // number of elements.
- if (HalvingSwizzle && (vecType->getNumElements() & 1U)) {
- Diag(OpLoc, diag::err_ext_vector_component_requires_even)
- << baseType << SourceRange(CompLoc);
- return QualType();
- }
-
// The component accessor looks fine - now we need to compute the actual type.
// The vector type is implied by the component accessor. For example,
// vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc.
// vec4.s0 is a float, vec4.s23 is a vec3, etc.
// vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2.
- unsigned CompSize = HalvingSwizzle ? vecType->getNumElements() / 2
+ unsigned CompSize = HalvingSwizzle ? (vecType->getNumElements() + 1) / 2
: CompName->getLength();
if (HexSwizzle)
CompSize--;
@@ -2277,6 +2366,23 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
// The record definition is complete, now look up the member.
SemaRef.LookupQualifiedName(R, DC);
+ if (!R.empty())
+ return false;
+
+ // We didn't find anything with the given name, so try to correct
+ // for typos.
+ DeclarationName Name = R.getLookupName();
+ if (SemaRef.CorrectTypo(R, 0, &SS, DC) &&
+ (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) {
+ SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
+ << Name << DC << R.getLookupName() << SS.getRange()
+ << CodeModificationHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
+ return false;
+ } else {
+ R.clear();
+ }
+
return false;
}
@@ -2372,6 +2478,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
// result.
if (R.isOverloadedResult() || R.isUnresolvableResult()) {
bool Dependent =
+ BaseExprType->isDependentType() ||
R.isUnresolvableResult() ||
UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs);
@@ -3059,28 +3166,36 @@ Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
if (Result.isInvalid())
return ExprError();
- if (SetParamDefaultArgument(Param, move(Result),
- /*FIXME:EqualLoc*/
- UninstExpr->getSourceRange().getBegin()))
+ // Check the expression as an initializer for the parameter.
+ InitializedEntity Entity
+ = InitializedEntity::InitializeParameter(Param);
+ InitializationKind Kind
+ = InitializationKind::CreateCopy(Param->getLocation(),
+ /*FIXME:EqualLoc*/UninstExpr->getSourceRange().getBegin());
+ Expr *ResultE = Result.takeAs<Expr>();
+
+ InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1);
+ Result = InitSeq.Perform(*this, Entity, Kind,
+ MultiExprArg(*this, (void**)&ResultE, 1));
+ if (Result.isInvalid())
return ExprError();
+
+ // Build the default argument expression.
+ return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param,
+ Result.takeAs<Expr>()));
}
- Expr *DefaultExpr = Param->getDefaultArg();
-
// If the default expression creates temporaries, we need to
// push them to the current stack of expression temporaries so they'll
// be properly destroyed.
- if (CXXExprWithTemporaries *E
- = dyn_cast_or_null<CXXExprWithTemporaries>(DefaultExpr)) {
- assert(!E->shouldDestroyTemporaries() &&
- "Can't destroy temporaries in a default argument expr!");
- for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I)
- ExprTemporaries.push_back(E->getTemporary(I));
- }
+ // FIXME: We should really be rebuilding the default argument with new
+ // bound temporaries; see the comment in PR5810.
+ for (unsigned i = 0, e = Param->getNumDefaultArgTemporaries(); i != e; ++i)
+ ExprTemporaries.push_back(Param->getDefaultArgTemporary(i));
}
// We already type-checked the argument, so we know it works.
- return Owned(CXXDefaultArgExpr::Create(Context, Param));
+ return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param));
}
/// ConvertArgumentsForCall - Converts the arguments specified in
@@ -3169,12 +3284,22 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
<< Arg->getSourceRange()))
return true;
- // Pass the argument.
- if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
- return true;
+ // Pass the argument
+ ParmVarDecl *Param = 0;
+ if (FDecl && i < FDecl->getNumParams())
+ Param = FDecl->getParamDecl(i);
+
- if (!ProtoArgType->isReferenceType())
- Arg = MaybeBindToTemporary(Arg).takeAs<Expr>();
+ InitializedEntity Entity =
+ Param? InitializedEntity::InitializeParameter(Param)
+ : InitializedEntity::InitializeParameter(ProtoArgType);
+ OwningExprResult ArgE = PerformCopyInitialization(Entity,
+ SourceLocation(),
+ Owned(Arg));
+ if (ArgE.isInvalid())
+ return true;
+
+ Arg = ArgE.takeAs<Expr>();
} else {
ParmVarDecl *Param = FDecl->getParamDecl(i);
@@ -3200,64 +3325,6 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
return Invalid;
}
-/// \brief "Deconstruct" the function argument of a call expression to find
-/// the underlying declaration (if any), the name of the called function,
-/// whether argument-dependent lookup is available, whether it has explicit
-/// template arguments, etc.
-void Sema::DeconstructCallFunction(Expr *FnExpr,
- llvm::SmallVectorImpl<NamedDecl*> &Fns,
- DeclarationName &Name,
- NestedNameSpecifier *&Qualifier,
- SourceRange &QualifierRange,
- bool &ArgumentDependentLookup,
- bool &Overloaded,
- bool &HasExplicitTemplateArguments,
- TemplateArgumentListInfo &ExplicitTemplateArgs) {
- // Set defaults for all of the output parameters.
- Name = DeclarationName();
- Qualifier = 0;
- QualifierRange = SourceRange();
- ArgumentDependentLookup = false;
- Overloaded = false;
- HasExplicitTemplateArguments = false;
-
- // If we're directly calling a function, get the appropriate declaration.
- // Also, in C++, keep track of whether we should perform argument-dependent
- // lookup and whether there were any explicitly-specified template arguments.
- while (true) {
- if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(FnExpr))
- FnExpr = IcExpr->getSubExpr();
- else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) {
- FnExpr = PExpr->getSubExpr();
- } else if (isa<UnaryOperator>(FnExpr) &&
- cast<UnaryOperator>(FnExpr)->getOpcode()
- == UnaryOperator::AddrOf) {
- FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr();
- } else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) {
- Fns.push_back(cast<NamedDecl>(DRExpr->getDecl()));
- ArgumentDependentLookup = false;
- if ((Qualifier = DRExpr->getQualifier()))
- QualifierRange = DRExpr->getQualifierRange();
- break;
- } else if (UnresolvedLookupExpr *UnresLookup
- = dyn_cast<UnresolvedLookupExpr>(FnExpr)) {
- Name = UnresLookup->getName();
- Fns.append(UnresLookup->decls_begin(), UnresLookup->decls_end());
- ArgumentDependentLookup = UnresLookup->requiresADL();
- Overloaded = UnresLookup->isOverloaded();
- if ((Qualifier = UnresLookup->getQualifier()))
- QualifierRange = UnresLookup->getQualifierRange();
- if (UnresLookup->hasExplicitTemplateArgs()) {
- HasExplicitTemplateArguments = true;
- UnresLookup->copyTemplateArgumentsInto(ExplicitTemplateArgs);
- }
- break;
- } else {
- break;
- }
- }
-}
-
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
/// This provides the location of the left/right parens and a list of comma
/// locations.
@@ -3372,72 +3439,23 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
// If we're directly calling a function, get the appropriate declaration.
// Also, in C++, keep track of whether we should perform argument-dependent
// lookup and whether there were any explicitly-specified template arguments.
- llvm::SmallVector<NamedDecl*,8> Fns;
- DeclarationName UnqualifiedName;
- bool Overloaded;
- bool ADL;
- bool HasExplicitTemplateArgs = 0;
- TemplateArgumentListInfo ExplicitTemplateArgs;
- NestedNameSpecifier *Qualifier = 0;
- SourceRange QualifierRange;
- DeconstructCallFunction(Fn, Fns, UnqualifiedName, Qualifier, QualifierRange,
- ADL, Overloaded, HasExplicitTemplateArgs,
- ExplicitTemplateArgs);
-
- NamedDecl *NDecl; // the specific declaration we're calling, if applicable
- FunctionDecl *FDecl; // same, if it's known to be a function
-
- if (Overloaded || ADL) {
-#ifndef NDEBUG
- if (ADL) {
- // To do ADL, we must have found an unqualified name.
- assert(UnqualifiedName && "found no unqualified name for ADL");
-
- // We don't perform ADL for implicit declarations of builtins.
- // Verify that this was correctly set up.
- if (Fns.size() == 1 && (FDecl = dyn_cast<FunctionDecl>(Fns[0])) &&
- FDecl->getBuiltinID() && FDecl->isImplicit())
- assert(0 && "performing ADL for builtin");
-
- // We don't perform ADL in C.
- assert(getLangOptions().CPlusPlus && "ADL enabled in C");
- }
-
- if (Overloaded) {
- // To be overloaded, we must either have multiple functions or
- // at least one function template (which is effectively an
- // infinite set of functions).
- assert((Fns.size() > 1 ||
- (Fns.size() == 1 &&
- isa<FunctionTemplateDecl>(Fns[0]->getUnderlyingDecl())))
- && "unrecognized overload situation");
- }
-#endif
-
- FDecl = ResolveOverloadedCallFn(Fn, Fns, UnqualifiedName,
- (HasExplicitTemplateArgs ? &ExplicitTemplateArgs : 0),
- LParenLoc, Args, NumArgs, CommaLocs,
- RParenLoc, ADL);
- if (!FDecl)
- return ExprError();
-
- Fn = FixOverloadedFunctionReference(Fn, FDecl);
- NDecl = FDecl;
- } else {
- assert(Fns.size() <= 1 && "overloaded without Overloaded flag");
- if (Fns.empty())
- NDecl = 0;
- else {
- NDecl = Fns[0];
- }
+ Expr *NakedFn = Fn->IgnoreParens();
+ if (isa<UnresolvedLookupExpr>(NakedFn)) {
+ UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(NakedFn);
+ return BuildOverloadedCallExpr(Fn, ULE, LParenLoc, Args, NumArgs,
+ CommaLocs, RParenLoc);
}
+ NamedDecl *NDecl = 0;
+ if (isa<DeclRefExpr>(NakedFn))
+ NDecl = cast<DeclRefExpr>(NakedFn)->getDecl();
+
return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc);
}
-/// BuildCallExpr - Build a call to a resolved expression, i.e. an
-/// expression not of \p OverloadTy. The expression should
+/// 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
/// block-pointer type.
///
@@ -3547,8 +3565,9 @@ Action::OwningExprResult
Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
SourceLocation RParenLoc, ExprArg InitExpr) {
assert((Ty != 0) && "ActOnCompoundLiteral(): missing type");
- //FIXME: Preserve type source info.
- QualType literalType = GetTypeFromParser(Ty);
+
+ QualType literalType = GetTypeFromParser(Ty);
+
// FIXME: put back this assert when initializers are worked out.
//assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression");
Expr *literalExpr = static_cast<Expr*>(InitExpr.get());
@@ -3564,16 +3583,29 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
literalExpr->getSourceRange().getEnd())))
return ExprError();
- if (CheckInitializerTypes(literalExpr, literalType, LParenLoc,
- DeclarationName(), /*FIXME:DirectInit=*/false))
+ InitializedEntity Entity
+ = InitializedEntity::InitializeTemporary(literalType);
+ InitializationKind Kind
+ = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc),
+ /*IsCStyleCast=*/true);
+ InitializationSequence InitSeq(*this, Entity, Kind, &literalExpr, 1);
+ OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind,
+ MultiExprArg(*this, (void**)&literalExpr, 1),
+ &literalType);
+ if (Result.isInvalid())
return ExprError();
+ InitExpr.release();
+ literalExpr = static_cast<Expr*>(Result.get());
bool isFileScope = getCurFunctionOrMethodDecl() == 0;
if (isFileScope) { // 6.5.2.5p3
if (CheckForConstantInitializer(literalExpr, literalType))
return ExprError();
}
- InitExpr.release();
+
+ Result.release();
+
+ // FIXME: Store the TInfo to preserve type information better.
return Owned(new (Context) CompoundLiteralExpr(LParenLoc, literalType,
literalExpr, isFileScope));
}
@@ -3600,7 +3632,9 @@ static CastExpr::CastKind getScalarCastKind(ASTContext &Context,
if (SrcTy->hasPointerRepresentation()) {
if (DestTy->hasPointerRepresentation())
- return CastExpr::CK_BitCast;
+ return DestTy->isObjCObjectPointerType() ?
+ CastExpr::CK_AnyPointerToObjCPointerCast :
+ CastExpr::CK_BitCast;
if (DestTy->isIntegerType())
return CastExpr::CK_PointerToIntegral;
}
@@ -4632,7 +4666,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
// expression is implicitly converted (C++ 4) to the
// cv-unqualified type of the left operand.
if (PerformImplicitConversion(rExpr, lhsType.getUnqualifiedType(),
- "assigning"))
+ AA_Assigning))
return Incompatible;
return Compatible;
}
@@ -5226,7 +5260,18 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if (getLangOptions().CPlusPlus) {
if (LCanPointeeTy == RCanPointeeTy)
return ResultTy;
-
+ if (!isRelational &&
+ (LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) {
+ // Valid unless comparison between non-null pointer and function pointer
+ // This is a gcc extension compatibility comparison.
+ if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType())
+ && !LHSIsNull && !RHSIsNull) {
+ Diag(Loc, diag::ext_typecheck_comparison_of_fptr_to_void)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ ImpCastExprToType(rex, lType, CastExpr::CK_BitCast);
+ return ResultTy;
+ }
+ }
// C++ [expr.rel]p2:
// [...] Pointer conversions (4.10) and qualification
// conversions (4.4) are performed on pointer operands (or on
@@ -5503,7 +5548,7 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
return InvalidOperands(Loc, lex, rex);
if (PerformImplicitConversion(lex, Context.BoolTy, LHS,
- "passing", /*IgnoreBaseAccess=*/false))
+ AA_Passing, /*IgnoreBaseAccess=*/false))
return InvalidOperands(Loc, lex, rex);
StandardConversionSequence RHS;
@@ -5512,7 +5557,7 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
return InvalidOperands(Loc, lex, rex);
if (PerformImplicitConversion(rex, Context.BoolTy, RHS,
- "passing", /*IgnoreBaseAccess=*/false))
+ AA_Passing, /*IgnoreBaseAccess=*/false))
return InvalidOperands(Loc, lex, rex);
// C++ [expr.log.and]p2
@@ -5587,6 +5632,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_NoSetterProperty:
Diag = diag::error_nosetter_property_assignment;
break;
+ case Expr::MLV_SubObjCPropertySetting:
+ Diag = diag::error_no_subobject_property_setting;
+ break;
}
SourceRange Assign;
@@ -5651,7 +5699,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
}
if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType,
- RHS, "assigning"))
+ RHS, AA_Assigning))
return QualType();
// C99 6.5.16p3: The type of an assignment expression is the type of the
@@ -5734,7 +5782,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
<< ResType << Op->getSourceRange();
} else {
Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement)
- << ResType << Op->getSourceRange();
+ << ResType << int(isInc) << Op->getSourceRange();
return QualType();
}
// At this point, we know we have a real, complex or pointer type.
@@ -6478,28 +6526,12 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
// Get the decl corresponding to this.
RecordDecl *RD = RC->getDecl();
if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
- if (!CRD->isPOD() && !DidWarnAboutNonPOD) {
- switch (ExprEvalContexts.back().Context ) {
- case Unevaluated:
- // The argument will never be evaluated, so don't complain.
- break;
-
- case PotentiallyEvaluated:
- ExprError(Diag(BuiltinLoc, diag::warn_offsetof_non_pod_type)
- << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
- << Res->getType());
- DidWarnAboutNonPOD = true;
- break;
-
- case PotentiallyPotentiallyEvaluated:
- ExprEvalContexts.back().addDiagnostic(BuiltinLoc,
- PDiag(diag::warn_offsetof_non_pod_type)
- << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
- << Res->getType());
- DidWarnAboutNonPOD = true;
- break;
- }
- }
+ if (!CRD->isPOD() && !DidWarnAboutNonPOD &&
+ DiagRuntimeBehavior(BuiltinLoc,
+ PDiag(diag::warn_offsetof_non_pod_type)
+ << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
+ << Res->getType()))
+ DidWarnAboutNonPOD = true;
}
LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName);
@@ -6847,7 +6879,7 @@ MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef,
bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
SourceLocation Loc,
QualType DstType, QualType SrcType,
- Expr *SrcExpr, const char *Flavor) {
+ Expr *SrcExpr, AssignmentAction Action) {
// Decode the result (notice that AST's are still created for extensions).
bool isInvalid = false;
unsigned DiagKind;
@@ -6910,7 +6942,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
break;
}
- Diag(Loc, DiagKind) << DstType << SrcType << Flavor
+ Diag(Loc, DiagKind) << DstType << SrcType << Action
<< SrcExpr->getSourceRange() << Hint;
return isInvalid;
}
@@ -7053,7 +7085,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
if (!Constructor->isUsed())
DefineImplicitDefaultConstructor(Loc, Constructor);
} else if (Constructor->isImplicit() &&
- Constructor->isCopyConstructor(Context, TypeQuals)) {
+ Constructor->isCopyConstructor(TypeQuals)) {
if (!Constructor->isUsed())
DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals);
}
@@ -7120,6 +7152,41 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
}
}
+/// \brief Emit a diagnostic that describes an effect on the run-time behavior
+/// of the program being compiled.
+///
+/// This routine emits the given diagnostic when the code currently being
+/// type-checked is "potentially evaluated", meaning that there is a
+/// possibility that the code will actually be executable. Code in sizeof()
+/// expressions, code used only during overload resolution, etc., are not
+/// potentially evaluated. This routine will suppress such diagnostics or,
+/// in the absolutely nutty case of potentially potentially evaluated
+/// expressions (C++ typeid), queue the diagnostic to potentially emit it
+/// later.
+///
+/// This routine should be used for all diagnostics that describe the run-time
+/// behavior of a program, such as passing a non-POD value through an ellipsis.
+/// Failure to do so will likely result in spurious diagnostics or failures
+/// during overload resolution or within sizeof/alignof/typeof/typeid.
+bool Sema::DiagRuntimeBehavior(SourceLocation Loc,
+ const PartialDiagnostic &PD) {
+ switch (ExprEvalContexts.back().Context ) {
+ case Unevaluated:
+ // The argument will never be evaluated, so don't complain.
+ break;
+
+ case PotentiallyEvaluated:
+ Diag(Loc, PD);
+ return true;
+
+ case PotentiallyPotentiallyEvaluated:
+ ExprEvalContexts.back().addDiagnostic(Loc, PD);
+ break;
+ }
+
+ return false;
+}
+
bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
CallExpr *CE, FunctionDecl *FD) {
if (ReturnType->isVoidType() || !ReturnType->isIncompleteType())
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 6d991b6..5f723f9 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -31,9 +31,29 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
if (!StdNamespace)
return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
- if (isType)
+ if (isType) {
+ // C++ [expr.typeid]p4:
+ // The top-level cv-qualifiers of the lvalue expression or the type-id
+ // that is the operand of typeid are always ignored.
// FIXME: Preserve type source info.
- TyOrExpr = GetTypeFromParser(TyOrExpr).getAsOpaquePtr();
+ // FIXME: Preserve the type before we stripped the cv-qualifiers?
+ QualType T = GetTypeFromParser(TyOrExpr);
+ if (T.isNull())
+ return ExprError();
+
+ // C++ [expr.typeid]p4:
+ // If the type of the type-id is a class type or a reference to a class
+ // type, the class shall be completely-defined.
+ QualType CheckT = T;
+ if (const ReferenceType *RefType = CheckT->getAs<ReferenceType>())
+ CheckT = RefType->getPointeeType();
+
+ if (CheckT->getAs<RecordType>() &&
+ RequireCompleteType(OpLoc, CheckT, diag::err_incomplete_typeid))
+ return ExprError();
+
+ TyOrExpr = T.getUnqualifiedType().getAsOpaquePtr();
+ }
IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info");
LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName);
@@ -45,21 +65,36 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
QualType TypeInfoType = Context.getTypeDeclType(TypeInfoRecordDecl);
if (!isType) {
- // C++0x [expr.typeid]p3:
- // When typeid is applied to an expression other than an lvalue of a
- // polymorphic class type [...] [the] expression is an unevaluated
- // operand.
-
- // FIXME: if the type of the expression is a class type, the class
- // shall be completely defined.
bool isUnevaluatedOperand = true;
Expr *E = static_cast<Expr *>(TyOrExpr);
- if (E && !E->isTypeDependent() && E->isLvalue(Context) == Expr::LV_Valid) {
+ if (E && !E->isTypeDependent()) {
QualType T = E->getType();
if (const RecordType *RecordT = T->getAs<RecordType>()) {
CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl());
- if (RecordD->isPolymorphic())
+ // C++ [expr.typeid]p3:
+ // When typeid is applied to an expression other than an lvalue of a
+ // polymorphic class type [...] [the] expression is an unevaluated
+ // operand. [...]
+ if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid)
isUnevaluatedOperand = false;
+ else {
+ // C++ [expr.typeid]p3:
+ // [...] If the type of the expression is a class type, the class
+ // shall be completely-defined.
+ if (RequireCompleteType(OpLoc, T, diag::err_incomplete_typeid))
+ return ExprError();
+ }
+ }
+
+ // C++ [expr.typeid]p4:
+ // [...] If the type of the type-id is a reference to a possibly
+ // cv-qualified type, the result of the typeid expression refers to a
+ // std::type_info object representing the cv-unqualified referenced
+ // type.
+ if (T.hasQualifiers()) {
+ ImpCastExprToType(E, T.getUnqualifiedType(), CastExpr::CK_NoOp,
+ E->isLvalue(Context));
+ TyOrExpr = E;
}
}
@@ -102,8 +137,15 @@ Sema::ActOnCXXThrow(SourceLocation OpLoc, ExprArg E) {
/// CheckCXXThrowOperand - Validate the operand of a throw.
bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
// C++ [except.throw]p3:
- // [...] adjusting the type from "array of T" or "function returning T"
- // to "pointer to T" or "pointer to function returning T", [...]
+ // A throw-expression initializes a temporary object, called the exception
+ // object, the type of which is determined by removing any top-level
+ // cv-qualifiers from the static type of the operand of throw and adjusting
+ // the type from "array of T" or "function returning T" to "pointer to T"
+ // or "pointer to function returning T", [...]
+ if (E->getType().hasQualifiers())
+ ImpCastExprToType(E, E->getType().getUnqualifiedType(), CastExpr::CK_NoOp,
+ E->isLvalue(Context) == Expr::LV_Valid);
+
DefaultFunctionArrayConversion(E);
// If the type of the exception would be an incomplete type or a pointer
@@ -425,74 +467,61 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
bool Init = ConstructorLParen.isValid();
// --- Choosing a constructor ---
- // C++ 5.3.4p15
- // 1) If T is a POD and there's no initializer (ConstructorLParen is invalid)
- // the object is not initialized. If the object, or any part of it, is
- // const-qualified, it's an error.
- // 2) If T is a POD and there's an empty initializer, the object is value-
- // initialized.
- // 3) If T is a POD and there's one initializer argument, the object is copy-
- // constructed.
- // 4) If T is a POD and there's more initializer arguments, it's an error.
- // 5) If T is not a POD, the initializer arguments are used as constructor
- // arguments.
- //
- // Or by the C++0x formulation:
- // 1) If there's no initializer, the object is default-initialized according
- // to C++0x rules.
- // 2) Otherwise, the object is direct-initialized.
CXXConstructorDecl *Constructor = 0;
Expr **ConsArgs = (Expr**)ConstructorArgs.get();
- const RecordType *RT;
unsigned NumConsArgs = ConstructorArgs.size();
ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this);
- if (AllocType->isDependentType() ||
- Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) {
- // Skip all the checks.
- } else if ((RT = AllocType->getAs<RecordType>()) &&
- !AllocType->isAggregateType()) {
- InitializationKind InitKind = InitializationKind::CreateDefault(TypeLoc);
- if (NumConsArgs > 0)
- InitKind = InitializationKind::CreateDirect(TypeLoc,
- PlacementLParen,
- PlacementRParen);
- Constructor = PerformInitializationByConstructor(
- AllocType, move(ConstructorArgs),
- TypeLoc,
- SourceRange(TypeLoc, ConstructorRParen),
- RT->getDecl()->getDeclName(),
- InitKind,
- ConvertedConstructorArgs);
- if (!Constructor)
+ if (!AllocType->isDependentType() &&
+ !Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) {
+ // C++0x [expr.new]p15:
+ // A new-expression that creates an object of type T initializes that
+ // object as follows:
+ InitializationKind Kind
+ // - If the new-initializer is omitted, the object is default-
+ // initialized (8.5); if no initialization is performed,
+ // the object has indeterminate value
+ = !Init? InitializationKind::CreateDefault(TypeLoc)
+ // - Otherwise, the new-initializer is interpreted according to the
+ // initialization rules of 8.5 for direct-initialization.
+ : InitializationKind::CreateDirect(TypeLoc,
+ ConstructorLParen,
+ ConstructorRParen);
+
+ InitializedEntity Entity
+ = InitializedEntity::InitializeNew(StartLoc, AllocType);
+ InitializationSequence InitSeq(*this, Entity, Kind, ConsArgs, NumConsArgs);
+ OwningExprResult FullInit = InitSeq.Perform(*this, Entity, Kind,
+ move(ConstructorArgs));
+ if (FullInit.isInvalid())
return ExprError();
-
- // Take the converted constructor arguments and use them for the new
- // expression.
- NumConsArgs = ConvertedConstructorArgs.size();
- ConsArgs = (Expr **)ConvertedConstructorArgs.take();
- } else {
- if (!Init) {
- // FIXME: Check that no subpart is const.
- if (AllocType.isConstQualified())
- return ExprError(Diag(StartLoc, diag::err_new_uninitialized_const)
- << TypeRange);
- } else if (NumConsArgs == 0) {
- // Object is value-initialized. Do nothing.
- } else if (NumConsArgs == 1) {
- // Object is direct-initialized.
- // FIXME: What DeclarationName do we pass in here?
- if (CheckInitializerTypes(ConsArgs[0], AllocType, StartLoc,
- DeclarationName() /*AllocType.getAsString()*/,
- /*DirectInit=*/true))
- return ExprError();
+
+ // FullInit is our initializer; walk through it to determine if it's a
+ // constructor call, which CXXNewExpr handles directly.
+ if (Expr *FullInitExpr = (Expr *)FullInit.get()) {
+ if (CXXBindTemporaryExpr *Binder
+ = dyn_cast<CXXBindTemporaryExpr>(FullInitExpr))
+ FullInitExpr = Binder->getSubExpr();
+ if (CXXConstructExpr *Construct
+ = dyn_cast<CXXConstructExpr>(FullInitExpr)) {
+ Constructor = Construct->getConstructor();
+ for (CXXConstructExpr::arg_iterator A = Construct->arg_begin(),
+ AEnd = Construct->arg_end();
+ A != AEnd; ++A)
+ ConvertedConstructorArgs.push_back(A->Retain());
+ } else {
+ // Take the converted initializer.
+ ConvertedConstructorArgs.push_back(FullInit.release());
+ }
} else {
- return ExprError(Diag(StartLoc,
- diag::err_builtin_direct_init_more_than_one_arg)
- << SourceRange(ConstructorLParen, ConstructorRParen));
+ // No initialization required.
}
+
+ // Take the converted arguments and use them for the new expression.
+ NumConsArgs = ConvertedConstructorArgs.size();
+ ConsArgs = (Expr **)ConvertedConstructorArgs.take();
}
-
+
// FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16)
PlacementArgs.release();
@@ -631,10 +660,9 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
// Whatch out for variadic allocator function.
unsigned NumArgsInFnDecl = FnDecl->getNumParams();
for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) {
- // FIXME: Passing word to diagnostic.
if (PerformCopyInitialization(Args[i],
FnDecl->getParamDecl(i)->getType(),
- "passing"))
+ AA_Passing))
return true;
}
Operator = FnDecl;
@@ -720,13 +748,14 @@ void Sema::DeclareGlobalNewDelete() {
QualType VoidPtr = Context.getPointerType(Context.VoidTy);
QualType SizeT = Context.getSizeType();
+ bool AssumeSaneOperatorNew = getLangOptions().AssumeSaneOperatorNew;
DeclareGlobalAllocationFunction(
Context.DeclarationNames.getCXXOperatorName(OO_New),
- VoidPtr, SizeT);
+ VoidPtr, SizeT, AssumeSaneOperatorNew);
DeclareGlobalAllocationFunction(
Context.DeclarationNames.getCXXOperatorName(OO_Array_New),
- VoidPtr, SizeT);
+ VoidPtr, SizeT, AssumeSaneOperatorNew);
DeclareGlobalAllocationFunction(
Context.DeclarationNames.getCXXOperatorName(OO_Delete),
Context.VoidTy, VoidPtr);
@@ -738,7 +767,8 @@ void Sema::DeclareGlobalNewDelete() {
/// DeclareGlobalAllocationFunction - Declares a single implicit global
/// allocation function if it doesn't already exist.
void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
- QualType Return, QualType Argument) {
+ QualType Return, QualType Argument,
+ bool AddMallocAttr) {
DeclContext *GlobalCtx = Context.getTranslationUnitDecl();
// Check if this function is already declared.
@@ -749,7 +779,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
// FIXME: Do we need to check for default arguments here?
FunctionDecl *Func = cast<FunctionDecl>(*Alloc);
if (Func->getNumParams() == 1 &&
- Context.getCanonicalType(Func->getParamDecl(0)->getType())==Argument)
+ Context.getCanonicalType(
+ Func->getParamDecl(0)->getType().getUnqualifiedType()) == Argument)
return;
}
}
@@ -771,6 +802,10 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
FnType, /*TInfo=*/0, FunctionDecl::None, false, true);
Alloc->setImplicit();
+
+ if (AddMallocAttr)
+ Alloc->addAttr(::new (Context) MallocAttr());
+
ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
0, Argument, /*TInfo=*/0,
VarDecl::None, 0);
@@ -876,7 +911,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
Operand.release();
if (!PerformImplicitConversion(Ex,
ObjectPtrConversions.front()->getConversionType(),
- "converting")) {
+ AA_Converting)) {
Operand = Owned(Ex);
Type = Ex->getType();
}
@@ -1027,16 +1062,16 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
/// resolution works differently in that case.
bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
- const char *Flavor, bool AllowExplicit,
+ AssignmentAction Action, bool AllowExplicit,
bool Elidable) {
ImplicitConversionSequence ICS;
- return PerformImplicitConversion(From, ToType, Flavor, AllowExplicit,
+ return PerformImplicitConversion(From, ToType, Action, AllowExplicit,
Elidable, ICS);
}
bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
- const char *Flavor, bool AllowExplicit,
+ AssignmentAction Action, bool AllowExplicit,
bool Elidable,
ImplicitConversionSequence& ICS) {
ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
@@ -1054,7 +1089,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
/*ForceRValue=*/false,
/*InOverloadResolution=*/false);
}
- return PerformImplicitConversion(From, ToType, ICS, Flavor);
+ return PerformImplicitConversion(From, ToType, ICS, Action);
}
/// BuildCXXDerivedToBaseExpr - This routine generates the suitable AST
@@ -1062,8 +1097,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
/// necessary information is passed in ICS.
bool
Sema::BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind,
- const ImplicitConversionSequence& ICS,
- const char *Flavor) {
+ const ImplicitConversionSequence& ICS) {
QualType BaseType =
QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr);
// Must do additional defined to base conversion.
@@ -1095,15 +1129,15 @@ Sema::BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind,
/// expression From to the type ToType using the pre-computed implicit
/// conversion sequence ICS. Returns true if there was an error, false
/// otherwise. The expression From is replaced with the converted
-/// expression. Flavor is the kind of conversion we're performing,
+/// expression. Action is the kind of conversion we're performing,
/// used in the error message.
bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
const ImplicitConversionSequence &ICS,
- const char* Flavor, bool IgnoreBaseAccess) {
+ AssignmentAction Action, bool IgnoreBaseAccess) {
switch (ICS.ConversionKind) {
case ImplicitConversionSequence::StandardConversion:
- if (PerformImplicitConversion(From, ToType, ICS.Standard, Flavor,
+ if (PerformImplicitConversion(From, ToType, ICS.Standard, Action,
IgnoreBaseAccess))
return true;
break;
@@ -1136,7 +1170,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
// Whatch out for elipsis conversion.
if (!ICS.UserDefined.EllipsisConversion) {
if (PerformImplicitConversion(From, BeforeToType,
- ICS.UserDefined.Before, "converting",
+ ICS.UserDefined.Before, AA_Converting,
IgnoreBaseAccess))
return true;
}
@@ -1156,7 +1190,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
// there's some nasty stuff involving MaybeBindToTemporary going on here.
if (ICS.UserDefined.After.Second == ICK_Derived_To_Base &&
ICS.UserDefined.After.CopyConstructor) {
- return BuildCXXDerivedToBaseExpr(From, CastKind, ICS, Flavor);
+ return BuildCXXDerivedToBaseExpr(From, CastKind, ICS);
}
if (ICS.UserDefined.After.CopyConstructor) {
@@ -1167,7 +1201,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
}
return PerformImplicitConversion(From, ToType, ICS.UserDefined.After,
- "converting", IgnoreBaseAccess);
+ AA_Converting, IgnoreBaseAccess);
}
case ImplicitConversionSequence::EllipsisConversion:
@@ -1191,7 +1225,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
const StandardConversionSequence& SCS,
- const char *Flavor, bool IgnoreBaseAccess) {
+ AssignmentAction Action, bool IgnoreBaseAccess) {
// Overall FIXME: we are recomputing too many types here and doing far too
// much extra work. What this means is that we need to keep track of more
// information that is computed when we try the implicit conversion initially,
@@ -1323,7 +1357,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
// Diagnose incompatible Objective-C conversions
Diag(From->getSourceRange().getBegin(),
diag::ext_typecheck_convert_incompatible_pointer)
- << From->getType() << ToType << Flavor
+ << From->getType() << ToType << Action
<< From->getSourceRange();
}
@@ -1595,9 +1629,9 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
case OR_Success:
// We found a match. Perform the conversions on the arguments and move on.
if (Self.PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], "converting") ||
+ Best->Conversions[0], Sema::AA_Converting) ||
Self.PerformImplicitConversion(RHS, Best->BuiltinTypes.ParamTypes[1],
- Best->Conversions[1], "converting"))
+ Best->Conversions[1], Sema::AA_Converting))
break;
return false;
@@ -1655,7 +1689,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E,
/*AllowExplicit=*/false,
/*ForceRValue=*/false);
}
- if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, "converting"))
+ if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, Sema::AA_Converting))
return true;
return false;
}
@@ -1879,9 +1913,9 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
LPointee = Context.getQualifiedType(LPointee, MergedQuals);
QualType Common
= Context.getMemberPointerType(LPointee, MoreDerived.getTypePtr());
- if (PerformImplicitConversion(LHS, Common, "converting"))
+ if (PerformImplicitConversion(LHS, Common, Sema::AA_Converting))
return QualType();
- if (PerformImplicitConversion(RHS, Common, "converting"))
+ if (PerformImplicitConversion(RHS, Common, Sema::AA_Converting))
return QualType();
return Common;
}
@@ -2046,13 +2080,13 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
&& E2ToC2.ConversionKind !=
ImplicitConversionSequence::BadConversion;
if (ToC1Viable && !ToC2Viable) {
- if (!PerformImplicitConversion(E1, Composite1, E1ToC1, "converting") &&
- !PerformImplicitConversion(E2, Composite1, E2ToC1, "converting"))
+ if (!PerformImplicitConversion(E1, Composite1, E1ToC1, Sema::AA_Converting) &&
+ !PerformImplicitConversion(E2, Composite1, E2ToC1, Sema::AA_Converting))
return Composite1;
}
if (ToC2Viable && !ToC1Viable) {
- if (!PerformImplicitConversion(E1, Composite2, E1ToC2, "converting") &&
- !PerformImplicitConversion(E2, Composite2, E2ToC2, "converting"))
+ if (!PerformImplicitConversion(E1, Composite2, E1ToC2, Sema::AA_Converting) &&
+ !PerformImplicitConversion(E2, Composite2, E2ToC2, Sema::AA_Converting))
return Composite2;
}
return QualType();
@@ -2062,6 +2096,8 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
if (!Context.getLangOptions().CPlusPlus)
return Owned(E);
+ assert(!isa<CXXBindTemporaryExpr>(E) && "Double-bound temporary?");
+
const RecordType *RT = E->getType()->getAs<RecordType>();
if (!RT)
return Owned(E);
@@ -2089,8 +2125,7 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E));
}
-Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr,
- bool ShouldDestroyTemps) {
+Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr) {
assert(SubExpr && "sub expression can't be null!");
unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
@@ -2100,8 +2135,31 @@ Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr,
Expr *E = CXXExprWithTemporaries::Create(Context, SubExpr,
&ExprTemporaries[FirstTemporary],
- ExprTemporaries.size() - FirstTemporary,
- ShouldDestroyTemps);
+ ExprTemporaries.size() - FirstTemporary);
+ ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary,
+ ExprTemporaries.end());
+
+ return E;
+}
+
+Sema::OwningExprResult
+Sema::MaybeCreateCXXExprWithTemporaries(OwningExprResult SubExpr) {
+ if (SubExpr.isInvalid())
+ return ExprError();
+
+ return Owned(MaybeCreateCXXExprWithTemporaries(SubExpr.takeAs<Expr>()));
+}
+
+FullExpr Sema::CreateFullExpr(Expr *SubExpr) {
+ unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
+ assert(ExprTemporaries.size() >= FirstTemporary);
+
+ unsigned NumTemporaries = ExprTemporaries.size() - FirstTemporary;
+ CXXTemporary **Temporaries =
+ NumTemporaries == 0 ? 0 : &ExprTemporaries[FirstTemporary];
+
+ FullExpr E = FullExpr::Create(Context, SubExpr, Temporaries, NumTemporaries);
+
ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary,
ExprTemporaries.end());
@@ -2243,9 +2301,7 @@ Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc,
Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
Expr *FullExpr = Arg.takeAs<Expr>();
if (FullExpr)
- FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr,
- /*ShouldDestroyTemps=*/true);
-
+ FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr);
return Owned(FullExpr);
}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index b78c10b..2e31e47 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -205,7 +205,7 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
IsError |=
DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType,
- argExpr, "sending");
+ argExpr, AA_Sending);
}
// Promote additional arguments to variadic methods.
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 4518465..3ef5156 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -16,11 +16,13 @@
//===----------------------------------------------------------------------===//
#include "SemaInit.h"
+#include "Lookup.h"
#include "Sema.h"
#include "clang/Parse/Designator.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/TypeLoc.h"
#include "llvm/Support/ErrorHandling.h"
#include <map>
using namespace clang;
@@ -73,7 +75,7 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType,
if (S.getLangOptions().CPlusPlus) {
// FIXME: I dislike this error message. A lot.
if (S.PerformImplicitConversion(Init, DeclType,
- "initializing", DirectInit)) {
+ Sema::AA_Initializing, DirectInit)) {
ImplicitConversionSequence ICS;
OverloadCandidateSet CandidateSet;
if (S.IsUserDefinedConversion(Init, DeclType, ICS.UserDefined,
@@ -81,7 +83,7 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType,
true, false, false) != OR_Ambiguous)
return S.Diag(Init->getSourceRange().getBegin(),
diag::err_typecheck_convert_incompatible)
- << DeclType << Init->getType() << "initializing"
+ << DeclType << Init->getType() << Sema::AA_Initializing
<< Init->getSourceRange();
S.Diag(Init->getSourceRange().getBegin(),
diag::err_typecheck_convert_ambiguous)
@@ -95,7 +97,7 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType,
Sema::AssignConvertType ConvTy =
S.CheckSingleAssignmentConstraints(DeclType, Init);
return S.DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType,
- InitType, Init, "initializing");
+ InitType, Init, Sema::AA_Initializing);
}
static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) {
@@ -134,172 +136,6 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) {
Str->setType(DeclT);
}
-bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
- SourceLocation InitLoc,
- DeclarationName InitEntity, bool DirectInit) {
- if (DeclType->isDependentType() ||
- Init->isTypeDependent() || Init->isValueDependent()) {
- // We have either a dependent type or a type- or value-dependent
- // initializer, so we don't perform any additional checking at
- // this point.
-
- // 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.
- if (!DeclType->isDependentType()) {
- if (const IncompleteArrayType *ArrayT
- = Context.getAsIncompleteArrayType(DeclType)) {
- if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
- if (!ILE->isTypeDependent()) {
- // Compute the constant array type from the length of the
- // initializer list.
- // FIXME: This will be wrong if there are designated
- // initializations. Good thing they don't exist in C++!
- llvm::APInt NumElements(Context.getTypeSize(Context.getSizeType()),
- ILE->getNumInits());
- llvm::APInt Zero(Context.getTypeSize(Context.getSizeType()), 0);
- if (NumElements == Zero) {
- // Sizing an array implicitly to zero is not allowed by ISO C,
- // but is supported by GNU.
- Diag(ILE->getLocStart(), diag::ext_typecheck_zero_array_size);
- }
-
- DeclType = Context.getConstantArrayType(ArrayT->getElementType(),
- NumElements,
- ArrayT->getSizeModifier(),
- ArrayT->getIndexTypeCVRQualifiers());
- return false;
- }
- }
-
- // Make the array type-dependent by making it dependently-sized.
- DeclType = Context.getDependentSizedArrayType(ArrayT->getElementType(),
- /*NumElts=*/0,
- ArrayT->getSizeModifier(),
- ArrayT->getIndexTypeCVRQualifiers(),
- SourceRange());
- }
- }
-
- return false;
- }
-
- // C++ [dcl.init.ref]p1:
- // A variable declared to be a T& or T&&, that is "reference to type T"
- // (8.3.2), shall be initialized by an object, or function, of
- // type T or by an object that can be converted into a T.
- if (DeclType->isReferenceType())
- return CheckReferenceInit(Init, DeclType, InitLoc,
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/DirectInit,
- /*ForceRValue=*/false);
-
- // C99 6.7.8p3: The type of the entity to be initialized shall be an array
- // of unknown size ("[]") or an object type that is not a variable array type.
- if (const VariableArrayType *VAT = Context.getAsVariableArrayType(DeclType))
- return Diag(InitLoc, diag::err_variable_object_no_init)
- << VAT->getSizeExpr()->getSourceRange();
-
- InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
- if (!InitList) {
- // FIXME: Handle wide strings
- if (Expr *Str = IsStringInit(Init, DeclType, Context)) {
- CheckStringInit(Str, DeclType, *this);
- return false;
- }
-
- // C++ [dcl.init]p14:
- // -- If the destination type is a (possibly cv-qualified) class
- // type:
- if (getLangOptions().CPlusPlus && DeclType->isRecordType()) {
- QualType DeclTypeC = Context.getCanonicalType(DeclType);
- QualType InitTypeC = Context.getCanonicalType(Init->getType());
-
- // -- If the initialization is direct-initialization, or if it is
- // copy-initialization where the cv-unqualified version of the
- // source type is the same class as, or a derived class of, the
- // class of the destination, constructors are considered.
- if ((DeclTypeC.getLocalUnqualifiedType()
- == InitTypeC.getLocalUnqualifiedType()) ||
- IsDerivedFrom(InitTypeC, DeclTypeC)) {
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(DeclType->getAs<RecordType>()->getDecl());
-
- // No need to make a CXXConstructExpr if both the ctor and dtor are
- // trivial.
- if (RD->hasTrivialConstructor() && RD->hasTrivialDestructor())
- return false;
-
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
-
- // FIXME: Poor location information
- InitializationKind InitKind
- = InitializationKind::CreateCopy(Init->getLocStart(),
- SourceLocation());
- if (DirectInit)
- InitKind = InitializationKind::CreateDirect(Init->getLocStart(),
- SourceLocation(),
- SourceLocation());
- CXXConstructorDecl *Constructor
- = PerformInitializationByConstructor(DeclType,
- MultiExprArg(*this,
- (void **)&Init, 1),
- InitLoc, Init->getSourceRange(),
- InitEntity, InitKind,
- ConstructorArgs);
- if (!Constructor)
- return true;
-
- OwningExprResult InitResult =
- BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
- DeclType, Constructor,
- move_arg(ConstructorArgs));
- if (InitResult.isInvalid())
- return true;
-
- Init = InitResult.takeAs<Expr>();
- return false;
- }
-
- // -- Otherwise (i.e., for the remaining copy-initialization
- // cases), user-defined conversion sequences that can
- // convert from the source type to the destination type or
- // (when a conversion function is used) to a derived class
- // thereof are enumerated as described in 13.3.1.4, and the
- // best one is chosen through overload resolution
- // (13.3). If the conversion cannot be done or is
- // ambiguous, the initialization is ill-formed. The
- // function selected is called with the initializer
- // expression as its argument; if the function is a
- // constructor, the call initializes a temporary of the
- // destination type.
- // FIXME: We're pretending to do copy elision here; return to this when we
- // have ASTs for such things.
- if (!PerformImplicitConversion(Init, DeclType, "initializing"))
- return false;
-
- if (InitEntity)
- return Diag(InitLoc, diag::err_cannot_initialize_decl)
- << InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
- << Init->getType() << Init->getSourceRange();
- return Diag(InitLoc, diag::err_cannot_initialize_decl_noname)
- << DeclType << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
- << Init->getType() << Init->getSourceRange();
- }
-
- // C99 6.7.8p16.
- if (DeclType->isArrayType())
- return Diag(Init->getLocStart(), diag::err_array_init_list_required)
- << Init->getSourceRange();
-
- return CheckSingleInitializer(Init, DeclType, DirectInit, *this);
- }
-
- bool hadError = CheckInitList(InitList, DeclType);
- Init = InitList;
- return hadError;
-}
-
//===----------------------------------------------------------------------===//
// Semantic checking for initializer lists.
//===----------------------------------------------------------------------===//
@@ -399,9 +235,14 @@ class InitListChecker {
int numArrayElements(QualType DeclType);
int numStructUnionElements(QualType DeclType);
- void FillInValueInitializations(InitListExpr *ILE);
+ void FillInValueInitForField(unsigned Init, FieldDecl *Field,
+ const InitializedEntity &ParentEntity,
+ InitListExpr *ILE, bool &RequiresSecondPass);
+ void FillInValueInitializations(const InitializedEntity &Entity,
+ InitListExpr *ILE, bool &RequiresSecondPass);
public:
- InitListChecker(Sema &S, InitListExpr *IL, QualType &T);
+ InitListChecker(Sema &S, const InitializedEntity &Entity,
+ InitListExpr *IL, QualType &T);
bool HadError() { return hadError; }
// @brief Retrieves the fully-structured initializer list used for
@@ -410,10 +251,75 @@ public:
};
} // end anonymous namespace
+void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
+ const InitializedEntity &ParentEntity,
+ InitListExpr *ILE,
+ bool &RequiresSecondPass) {
+ SourceLocation Loc = ILE->getSourceRange().getBegin();
+ unsigned NumInits = ILE->getNumInits();
+ InitializedEntity MemberEntity
+ = InitializedEntity::InitializeMember(Field, &ParentEntity);
+ if (Init >= NumInits || !ILE->getInit(Init)) {
+ // FIXME: We probably don't need to handle references
+ // specially here, since value-initialization of references is
+ // handled in InitializationSequence.
+ if (Field->getType()->isReferenceType()) {
+ // C++ [dcl.init.aggr]p9:
+ // If an incomplete or empty initializer-list leaves a
+ // member of reference type uninitialized, the program is
+ // ill-formed.
+ SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized)
+ << Field->getType()
+ << ILE->getSyntacticForm()->getSourceRange();
+ SemaRef.Diag(Field->getLocation(),
+ diag::note_uninit_reference_member);
+ hadError = true;
+ return;
+ }
+
+ InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
+ true);
+ InitializationSequence InitSeq(SemaRef, MemberEntity, Kind, 0, 0);
+ if (!InitSeq) {
+ InitSeq.Diagnose(SemaRef, MemberEntity, Kind, 0, 0);
+ hadError = true;
+ return;
+ }
+
+ Sema::OwningExprResult MemberInit
+ = InitSeq.Perform(SemaRef, MemberEntity, Kind,
+ Sema::MultiExprArg(SemaRef, 0, 0));
+ if (MemberInit.isInvalid()) {
+ hadError = true;
+ return;
+ }
+
+ if (hadError) {
+ // Do nothing
+ } else if (Init < NumInits) {
+ ILE->setInit(Init, MemberInit.takeAs<Expr>());
+ } else if (InitSeq.getKind()
+ == InitializationSequence::ConstructorInitialization) {
+ // 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
+ // through the initializer list.
+ ILE->updateInit(Init, MemberInit.takeAs<Expr>());
+ RequiresSecondPass = true;
+ }
+ } else if (InitListExpr *InnerILE
+ = dyn_cast<InitListExpr>(ILE->getInit(Init)))
+ FillInValueInitializations(MemberEntity, InnerILE,
+ RequiresSecondPass);
+}
+
/// Recursively replaces NULL values within the given initializer list
/// with expressions that perform value-initialization of the
/// appropriate type.
-void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
+void
+InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
+ InitListExpr *ILE,
+ bool &RequiresSecondPass) {
assert((ILE->getType() != SemaRef.Context.VoidTy) &&
"Should not have void type");
SourceLocation Loc = ILE->getSourceRange().getBegin();
@@ -421,46 +327,32 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
Loc = ILE->getSyntacticForm()->getSourceRange().getBegin();
if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
- unsigned Init = 0, NumInits = ILE->getNumInits();
- for (RecordDecl::field_iterator
- Field = RType->getDecl()->field_begin(),
- FieldEnd = RType->getDecl()->field_end();
- Field != FieldEnd; ++Field) {
- if (Field->isUnnamedBitfield())
- continue;
-
- if (Init >= NumInits || !ILE->getInit(Init)) {
- if (Field->getType()->isReferenceType()) {
- // C++ [dcl.init.aggr]p9:
- // If an incomplete or empty initializer-list leaves a
- // member of reference type uninitialized, the program is
- // ill-formed.
- SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized)
- << Field->getType()
- << ILE->getSyntacticForm()->getSourceRange();
- SemaRef.Diag(Field->getLocation(),
- diag::note_uninit_reference_member);
- hadError = true;
+ if (RType->getDecl()->isUnion() &&
+ ILE->getInitializedFieldInUnion())
+ FillInValueInitForField(0, ILE->getInitializedFieldInUnion(),
+ Entity, ILE, RequiresSecondPass);
+ else {
+ unsigned Init = 0;
+ for (RecordDecl::field_iterator
+ Field = RType->getDecl()->field_begin(),
+ FieldEnd = RType->getDecl()->field_end();
+ Field != FieldEnd; ++Field) {
+ if (Field->isUnnamedBitfield())
+ continue;
+
+ if (hadError)
return;
- } else if (SemaRef.CheckValueInitialization(Field->getType(), Loc)) {
- hadError = true;
+
+ FillInValueInitForField(Init, *Field, Entity, ILE, RequiresSecondPass);
+ if (hadError)
return;
- }
- // FIXME: If value-initialization involves calling a constructor, should
- // we make that call explicit in the representation (even when it means
- // extending the initializer list)?
- if (Init < NumInits && !hadError)
- ILE->setInit(Init,
- new (SemaRef.Context) ImplicitValueInitExpr(Field->getType()));
- } else if (InitListExpr *InnerILE
- = dyn_cast<InitListExpr>(ILE->getInit(Init)))
- FillInValueInitializations(InnerILE);
- ++Init;
+ ++Init;
- // Only look at the first initialization of a union.
- if (RType->getDecl()->isUnion())
- break;
+ // Only look at the first initialization of a union.
+ if (RType->getDecl()->isUnion())
+ break;
+ }
}
return;
@@ -468,39 +360,71 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
QualType ElementType;
+ InitializedEntity ElementEntity = Entity;
unsigned NumInits = ILE->getNumInits();
unsigned NumElements = NumInits;
if (const ArrayType *AType = SemaRef.Context.getAsArrayType(ILE->getType())) {
ElementType = AType->getElementType();
if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType))
NumElements = CAType->getSize().getZExtValue();
+ ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context,
+ 0, Entity);
} else if (const VectorType *VType = ILE->getType()->getAs<VectorType>()) {
ElementType = VType->getElementType();
NumElements = VType->getNumElements();
+ ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context,
+ 0, Entity);
} else
ElementType = ILE->getType();
+
for (unsigned Init = 0; Init != NumElements; ++Init) {
+ if (hadError)
+ return;
+
+ if (ElementEntity.getKind() == InitializedEntity::EK_ArrayOrVectorElement)
+ ElementEntity.setElementIndex(Init);
+
if (Init >= NumInits || !ILE->getInit(Init)) {
- if (SemaRef.CheckValueInitialization(ElementType, Loc)) {
+ InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
+ true);
+ InitializationSequence InitSeq(SemaRef, ElementEntity, Kind, 0, 0);
+ if (!InitSeq) {
+ InitSeq.Diagnose(SemaRef, ElementEntity, Kind, 0, 0);
hadError = true;
return;
}
- // FIXME: If value-initialization involves calling a constructor, should
- // we make that call explicit in the representation (even when it means
- // extending the initializer list)?
- if (Init < NumInits && !hadError)
- ILE->setInit(Init,
- new (SemaRef.Context) ImplicitValueInitExpr(ElementType));
+ Sema::OwningExprResult ElementInit
+ = InitSeq.Perform(SemaRef, ElementEntity, Kind,
+ Sema::MultiExprArg(SemaRef, 0, 0));
+ if (ElementInit.isInvalid()) {
+ hadError = true;
+ return;
+ }
+
+ if (hadError) {
+ // Do nothing
+ } else if (Init < NumInits) {
+ ILE->setInit(Init, ElementInit.takeAs<Expr>());
+ } else if (InitSeq.getKind()
+ == InitializationSequence::ConstructorInitialization) {
+ // 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
+ // through the initializer list.
+ ILE->updateInit(Init, ElementInit.takeAs<Expr>());
+ RequiresSecondPass = true;
+ }
} else if (InitListExpr *InnerILE
- = dyn_cast<InitListExpr>(ILE->getInit(Init)))
- FillInValueInitializations(InnerILE);
+ = dyn_cast<InitListExpr>(ILE->getInit(Init)))
+ FillInValueInitializations(ElementEntity, InnerILE, RequiresSecondPass);
}
}
-InitListChecker::InitListChecker(Sema &S, InitListExpr *IL, QualType &T)
+InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
+ InitListExpr *IL, QualType &T)
: SemaRef(S) {
hadError = false;
@@ -511,8 +435,13 @@ InitListChecker::InitListChecker(Sema &S, InitListExpr *IL, QualType &T)
CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex,
/*TopLevelObject=*/true);
- if (!hadError)
- FillInValueInitializations(FullyStructuredList);
+ if (!hadError) {
+ bool RequiresSecondPass = false;
+ FillInValueInitializations(Entity, FullyStructuredList, RequiresSecondPass);
+ if (RequiresSecondPass && !hadError)
+ FillInValueInitializations(Entity, FullyStructuredList,
+ RequiresSecondPass);
+ }
}
int InitListChecker::numArrayElements(QualType DeclType) {
@@ -743,7 +672,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion) {
if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS,
- "initializing"))
+ Sema::AA_Initializing))
hadError = true;
UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
++Index;
@@ -783,7 +712,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
} else {
// We cannot initialize this element, so let
// PerformCopyInitialization produce the appropriate diagnostic.
- SemaRef.PerformCopyInitialization(expr, ElemType, "initializing");
+ SemaRef.PerformCopyInitialization(expr, ElemType, Sema::AA_Initializing);
hadError = true;
++Index;
++StructuredIndex;
@@ -1358,22 +1287,33 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// may find nothing, or may find a member of an anonymous
// struct/union.
DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
+ FieldDecl *ReplacementField = 0;
if (Lookup.first == Lookup.second) {
- // Name lookup didn't find anything.
- SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
- << FieldName << CurrentObjectType;
- ++Index;
- return true;
- } else if (!KnownField && isa<FieldDecl>(*Lookup.first) &&
- cast<RecordDecl>((*Lookup.first)->getDeclContext())
- ->isAnonymousStructOrUnion()) {
- // Handle an field designator that refers to a member of an
- // anonymous struct or union.
- ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx,
- cast<FieldDecl>(*Lookup.first),
- Field, FieldIndex);
- D = DIE->getDesignator(DesigIdx);
- } else {
+ // Name lookup didn't find anything. Determine whether this
+ // was a typo for another field name.
+ LookupResult R(SemaRef, FieldName, D->getFieldLoc(),
+ Sema::LookupMemberName);
+ if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl()) &&
+ (ReplacementField = R.getAsSingle<FieldDecl>()) &&
+ ReplacementField->getDeclContext()->getLookupContext()
+ ->Equals(RT->getDecl())) {
+ SemaRef.Diag(D->getFieldLoc(),
+ diag::err_field_designator_unknown_suggest)
+ << FieldName << CurrentObjectType << R.getLookupName()
+ << CodeModificationHint::CreateReplacement(D->getFieldLoc(),
+ R.getLookupName().getAsString());
+ } else {
+ SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
+ << FieldName << CurrentObjectType;
+ ++Index;
+ return true;
+ }
+ } else if (!KnownField) {
+ // Determine whether we found a field at all.
+ ReplacementField = dyn_cast<FieldDecl>(*Lookup.first);
+ }
+
+ if (!ReplacementField) {
// Name lookup found something, but it wasn't a field.
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
<< FieldName;
@@ -1382,6 +1322,32 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
++Index;
return true;
}
+
+ if (!KnownField &&
+ cast<RecordDecl>((ReplacementField)->getDeclContext())
+ ->isAnonymousStructOrUnion()) {
+ // Handle an field designator that refers to a member of an
+ // anonymous struct or union.
+ ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx,
+ ReplacementField,
+ Field, FieldIndex);
+ D = DIE->getDesignator(DesigIdx);
+ } else if (!KnownField) {
+ // The replacement field comes from typo correction; find it
+ // in the list of fields.
+ FieldIndex = 0;
+ Field = RT->getDecl()->field_begin();
+ for (; Field != FieldEnd; ++Field) {
+ if (Field->isUnnamedBitfield())
+ continue;
+
+ if (ReplacementField == *Field ||
+ Field->getIdentifier() == ReplacementField->getIdentifier())
+ break;
+
+ ++FieldIndex;
+ }
+ }
} else if (!KnownField &&
cast<RecordDecl>((*Field)->getDeclContext())
->isAnonymousStructOrUnion()) {
@@ -1844,101 +1810,27 @@ Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
return Owned(DIE);
}
-bool Sema::CheckInitList(InitListExpr *&InitList, QualType &DeclType) {
- InitListChecker CheckInitList(*this, InitList, DeclType);
+bool Sema::CheckInitList(const InitializedEntity &Entity,
+ InitListExpr *&InitList, QualType &DeclType) {
+ InitListChecker CheckInitList(*this, Entity, InitList, DeclType);
if (!CheckInitList.HadError())
InitList = CheckInitList.getFullyStructuredList();
return CheckInitList.HadError();
}
-/// \brief Diagnose any semantic errors with value-initialization of
-/// the given type.
-///
-/// Value-initialization effectively zero-initializes any types
-/// without user-declared constructors, and calls the default
-/// constructor for a for any type that has a user-declared
-/// constructor (C++ [dcl.init]p5). Value-initialization can fail when
-/// a type with a user-declared constructor does not have an
-/// accessible, non-deleted default constructor. In C, everything can
-/// be value-initialized, which corresponds to C's notion of
-/// initializing objects with static storage duration when no
-/// initializer is provided for that object.
-///
-/// \returns true if there was an error, false otherwise.
-bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) {
- // C++ [dcl.init]p5:
- //
- // To value-initialize an object of type T means:
-
- // -- if T is an array type, then each element is value-initialized;
- if (const ArrayType *AT = Context.getAsArrayType(Type))
- return CheckValueInitialization(AT->getElementType(), Loc);
-
- if (const RecordType *RT = Type->getAs<RecordType>()) {
- if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- // -- if T is a class type (clause 9) with a user-declared
- // constructor (12.1), then the default constructor for T is
- // called (and the initialization is ill-formed if T has no
- // accessible default constructor);
- if (ClassDecl->hasUserDeclaredConstructor()) {
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
-
- // FIXME: Poor location information
- CXXConstructorDecl *Constructor
- = PerformInitializationByConstructor(Type,
- MultiExprArg(*this, 0, 0),
- Loc, SourceRange(Loc),
- DeclarationName(),
- InitializationKind::CreateValue(Loc, Loc, Loc),
- ConstructorArgs);
- if (!Constructor)
- return true;
-
- OwningExprResult Init
- = BuildCXXConstructExpr(Loc, Type, Constructor,
- move_arg(ConstructorArgs));
- if (Init.isInvalid())
- return true;
-
- // FIXME: Actually perform the value-initialization!
- return false;
- }
- }
- }
-
- if (Type->isReferenceType()) {
- // C++ [dcl.init]p5:
- // [...] A program that calls for default-initialization or
- // value-initialization of an entity of reference type is
- // ill-formed. [...]
- // FIXME: Once we have code that goes through this path, add an actual
- // diagnostic :)
- }
-
- return false;
-}
-
//===----------------------------------------------------------------------===//
// Initialization entity
//===----------------------------------------------------------------------===//
-void InitializedEntity::InitDeclLoc() {
- assert((Kind == EK_Variable || Kind == EK_Parameter || Kind == EK_Member) &&
- "InitDeclLoc cannot be used with non-declaration entities.");
-
- if (TypeSourceInfo *DI = VariableOrMember->getTypeSourceInfo()) {
- TL = DI->getTypeLoc();
- return;
- }
-
- // FIXME: Once we've gone through the effort to create the fake
- // TypeSourceInfo, should we cache it in the declaration?
- // (If not, we "leak" it).
- TypeSourceInfo *DI = VariableOrMember->getASTContext()
- .CreateTypeSourceInfo(VariableOrMember->getType());
- DI->getTypeLoc().initialize(VariableOrMember->getLocation());
- TL = DI->getTypeLoc();
+InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index,
+ const InitializedEntity &Parent)
+ : Kind(EK_ArrayOrVectorElement), Parent(&Parent), Index(Index)
+{
+ if (const ArrayType *AT = Context.getAsArrayType(Parent.getType()))
+ Type = AT->getElementType();
+ else
+ Type = Parent.getType()->getAs<VectorType>()->getElementType();
}
InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context,
@@ -1947,13 +1839,54 @@ InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context,
InitializedEntity Result;
Result.Kind = EK_Base;
Result.Base = Base;
- // FIXME: CXXBaseSpecifier should store a TypeLoc.
- TypeSourceInfo *DI = Context.CreateTypeSourceInfo(Base->getType());
- DI->getTypeLoc().initialize(Base->getSourceRange().getBegin());
- Result.TL = DI->getTypeLoc();
+ Result.Type = Base->getType();
return Result;
}
+DeclarationName InitializedEntity::getName() const {
+ switch (getKind()) {
+ case EK_Parameter:
+ if (!VariableOrMember)
+ return DeclarationName();
+ // Fall through
+
+ case EK_Variable:
+ case EK_Member:
+ return VariableOrMember->getDeclName();
+
+ case EK_Result:
+ case EK_Exception:
+ case EK_New:
+ case EK_Temporary:
+ case EK_Base:
+ case EK_ArrayOrVectorElement:
+ return DeclarationName();
+ }
+
+ // Silence GCC warning
+ return DeclarationName();
+}
+
+DeclaratorDecl *InitializedEntity::getDecl() const {
+ switch (getKind()) {
+ case EK_Variable:
+ case EK_Parameter:
+ case EK_Member:
+ return VariableOrMember;
+
+ case EK_Result:
+ case EK_Exception:
+ case EK_New:
+ case EK_Temporary:
+ case EK_Base:
+ case EK_ArrayOrVectorElement:
+ return 0;
+ }
+
+ // Silence GCC warning
+ return 0;
+}
+
//===----------------------------------------------------------------------===//
// Initialization sequence
//===----------------------------------------------------------------------===//
@@ -1971,6 +1904,8 @@ void InitializationSequence::Step::Destroy() {
case SK_ListInitialization:
case SK_ConstructorInitialization:
case SK_ZeroInitialization:
+ case SK_CAssignment:
+ case SK_StringInit:
break;
case SK_ConversionSequence:
@@ -2056,6 +1991,20 @@ void InitializationSequence::AddZeroInitializationStep(QualType T) {
Steps.push_back(S);
}
+void InitializationSequence::AddCAssignmentStep(QualType T) {
+ Step S;
+ S.Kind = SK_CAssignment;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
+void InitializationSequence::AddStringInitStep(QualType T) {
+ Step S;
+ S.Kind = SK_StringInit;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
void InitializationSequence::SetOverloadFailure(FailureKind Failure,
OverloadingResult Result) {
SequenceKind = FailedSequence;
@@ -2081,7 +2030,7 @@ static void TryListInitialization(Sema &S,
// force us to perform more checking here.
Sequence.setSequenceKind(InitializationSequence::ListInitialization);
- QualType DestType = Entity.getType().getType();
+ QualType DestType = Entity.getType();
// C++ [dcl.init]p13:
// If T is a scalar type, then a declaration of the form
@@ -2125,7 +2074,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
Expr *Initializer,
bool AllowRValues,
InitializationSequence &Sequence) {
- QualType DestType = Entity.getType().getType();
+ QualType DestType = Entity.getType();
QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
QualType T1 = cv1T1.getUnqualifiedType();
QualType cv2T2 = Initializer->getType();
@@ -2273,7 +2222,7 @@ static void TryReferenceInitialization(Sema &S,
InitializationSequence &Sequence) {
Sequence.setSequenceKind(InitializationSequence::ReferenceBinding);
- QualType DestType = Entity.getType().getType();
+ QualType DestType = Entity.getType();
QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
QualType T1 = cv1T1.getUnqualifiedType();
QualType cv2T2 = Initializer->getType();
@@ -2437,7 +2386,12 @@ static void TryReferenceInitialization(Sema &S,
// this into an overloading ambiguity diagnostic. However, we need
// to keep that set as an OverloadCandidateSet rather than as some
// other kind of set.
- Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed);
+ if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty())
+ Sequence.SetOverloadFailure(
+ InitializationSequence::FK_ReferenceInitOverloadFailed,
+ ConvOvlResult);
+ else
+ Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed);
return;
}
@@ -2463,7 +2417,8 @@ static void TryStringLiteralInitialization(Sema &S,
const InitializationKind &Kind,
Expr *Initializer,
InitializationSequence &Sequence) {
- // FIXME: Implement!
+ Sequence.setSequenceKind(InitializationSequence::StringInit);
+ Sequence.AddStringInitStep(Entity.getType());
}
/// \brief Attempt initialization by constructor (C++ [dcl.init]), which
@@ -2475,7 +2430,10 @@ static void TryConstructorInitialization(Sema &S,
Expr **Args, unsigned NumArgs,
QualType DestType,
InitializationSequence &Sequence) {
- Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization);
+ if (Kind.getKind() == InitializationKind::IK_Copy)
+ Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion);
+ else
+ Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization);
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
@@ -2512,7 +2470,7 @@ static void TryConstructorInitialization(Sema &S,
Constructor = cast<CXXConstructorDecl>(*Con);
if (!Constructor->isInvalidDecl() &&
- Constructor->isConvertingConstructor(AllowExplicit)) {
+ (AllowExplicit || !Constructor->isExplicit())) {
if (ConstructorTmpl)
S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0,
Args, NumArgs, CandidateSet);
@@ -2535,9 +2493,13 @@ static void TryConstructorInitialization(Sema &S,
// Add the constructor initialization step. Any cv-qualification conversion is
// subsumed by the initialization.
- Sequence.AddConstructorInitializationStep(
+ if (Kind.getKind() == InitializationKind::IK_Copy) {
+ Sequence.AddUserConversionStep(Best->Function, DestType);
+ } else {
+ Sequence.AddConstructorInitializationStep(
cast<CXXConstructorDecl>(Best->Function),
- DestType);
+ DestType);
+ }
}
/// \brief Attempt value initialization (C++ [dcl.init]p7).
@@ -2548,7 +2510,7 @@ static void TryValueInitialization(Sema &S,
// C++ [dcl.init]p5:
//
// To value-initialize an object of type T means:
- QualType T = Entity.getType().getType();
+ QualType T = Entity.getType();
// -- if T is an array type, then each element is value-initialized;
while (const ArrayType *AT = S.Context.getAsArrayType(T))
@@ -2566,15 +2528,58 @@ static void TryValueInitialization(Sema &S,
if (ClassDecl->hasUserDeclaredConstructor())
return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence);
- // FIXME: non-union class type w/ non-trivial default constructor gets
- // zero-initialized, then constructor gets called.
+ // -- if T is a (possibly cv-qualified) non-union class type
+ // without a user-provided constructor, then the object is
+ // zero-initialized and, if T’s implicitly-declared default
+ // constructor is non-trivial, that constructor is called.
+ if ((ClassDecl->getTagKind() == TagDecl::TK_class ||
+ ClassDecl->getTagKind() == TagDecl::TK_struct) &&
+ !ClassDecl->hasTrivialConstructor()) {
+ Sequence.AddZeroInitializationStep(Entity.getType());
+ return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence);
+ }
}
}
- Sequence.AddZeroInitializationStep(Entity.getType().getType());
+ Sequence.AddZeroInitializationStep(Entity.getType());
Sequence.setSequenceKind(InitializationSequence::ZeroInitialization);
}
+/// \brief Attempt default initialization (C++ [dcl.init]p6).
+static void TryDefaultInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ InitializationSequence &Sequence) {
+ assert(Kind.getKind() == InitializationKind::IK_Default);
+
+ // C++ [dcl.init]p6:
+ // To default-initialize an object of type T means:
+ // - if T is an array type, each element is default-initialized;
+ QualType DestType = Entity.getType();
+ while (const ArrayType *Array = S.Context.getAsArrayType(DestType))
+ DestType = Array->getElementType();
+
+ // - if T is a (possibly cv-qualified) class type (Clause 9), the default
+ // constructor for T is called (and the initialization is ill-formed if
+ // T has no accessible default constructor);
+ if (DestType->isRecordType()) {
+ // FIXME: 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
+ // default constructor.
+ return TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType,
+ Sequence);
+ }
+
+ // - 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
+ // default constructor.
+ if (DestType.isConstQualified())
+ Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
+}
+
/// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]),
/// which enumerates all conversion functions and performs overload resolution
/// to select the best.
@@ -2585,7 +2590,7 @@ static void TryUserDefinedConversion(Sema &S,
InitializationSequence &Sequence) {
Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion);
- QualType DestType = Entity.getType().getType();
+ QualType DestType = Entity.getType();
assert(!DestType->isReferenceType() && "References are handled elsewhere");
QualType SourceType = Initializer->getType();
assert((DestType->isRecordType() || SourceType->isRecordType()) &&
@@ -2632,43 +2637,49 @@ static void TryUserDefinedConversion(Sema &S,
}
}
}
-
+
+ SourceLocation DeclLoc = Initializer->getLocStart();
+
if (const RecordType *SourceRecordType = SourceType->getAs<RecordType>()) {
// The type we're converting from is a class type, enumerate its conversion
// functions.
- CXXRecordDecl *SourceRecordDecl
- = cast<CXXRecordDecl>(SourceRecordType->getDecl());
-
- const UnresolvedSet *Conversions
- = SourceRecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
- E = Conversions->end();
- I != E; ++I) {
- NamedDecl *D = *I;
- CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
- if (isa<UsingShadowDecl>(D))
- D = cast<UsingShadowDecl>(D)->getTargetDecl();
-
- FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
- CXXConversionDecl *Conv;
- if (ConvTemplate)
- Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
- else
- Conv = cast<CXXConversionDecl>(*I);
+
+ // We can only enumerate the conversion functions for a complete type; if
+ // the type isn't complete, simply skip this step.
+ if (!S.RequireCompleteType(DeclLoc, SourceType, 0)) {
+ CXXRecordDecl *SourceRecordDecl
+ = cast<CXXRecordDecl>(SourceRecordType->getDecl());
- if (AllowExplicit || !Conv->isExplicit()) {
+ const UnresolvedSet *Conversions
+ = SourceRecordDecl->getVisibleConversionFunctions();
+ for (UnresolvedSet::iterator I = Conversions->begin(),
+ E = Conversions->end();
+ I != E; ++I) {
+ NamedDecl *D = *I;
+ CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+ FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
+ CXXConversionDecl *Conv;
if (ConvTemplate)
- S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, Initializer,
- DestType, CandidateSet);
+ Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
- S.AddConversionCandidate(Conv, ActingDC, Initializer, DestType,
- CandidateSet);
+ Conv = cast<CXXConversionDecl>(*I);
+
+ if (AllowExplicit || !Conv->isExplicit()) {
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(ConvTemplate, ActingDC,
+ Initializer, DestType,
+ CandidateSet);
+ else
+ S.AddConversionCandidate(Conv, ActingDC, Initializer, DestType,
+ CandidateSet);
+ }
}
}
}
- SourceLocation DeclLoc = Initializer->getLocStart();
-
// Perform overload resolution. If it fails, return the failed result.
OverloadCandidateSet::iterator Best;
if (OverloadingResult Result
@@ -2711,7 +2722,7 @@ static void TryImplicitConversion(Sema &S,
Expr *Initializer,
InitializationSequence &Sequence) {
ImplicitConversionSequence ICS
- = S.TryImplicitConversion(Initializer, Entity.getType().getType(),
+ = S.TryImplicitConversion(Initializer, Entity.getType(),
/*SuppressUserConversions=*/true,
/*AllowExplicit=*/false,
/*ForceRValue=*/false,
@@ -2723,7 +2734,7 @@ static void TryImplicitConversion(Sema &S,
return;
}
- Sequence.AddConversionSequenceStep(ICS, Entity.getType().getType());
+ Sequence.AddConversionSequenceStep(ICS, Entity.getType());
}
InitializationSequence::InitializationSequence(Sema &S,
@@ -2739,7 +2750,7 @@ InitializationSequence::InitializationSequence(Sema &S,
// type is the type of the initializer expression. The source type is not
// defined when the initializer is a braced-init-list or when it is a
// parenthesized list of expressions.
- QualType DestType = Entity.getType().getType();
+ QualType DestType = Entity.getType();
if (DestType->isDependentType() ||
Expr::hasAnyTypeDependentArguments(Args, NumArgs)) {
@@ -2749,7 +2760,7 @@ InitializationSequence::InitializationSequence(Sema &S,
QualType SourceType;
Expr *Initializer = 0;
- if (Kind.getKind() == InitializationKind::IK_Copy) {
+ if (NumArgs == 1) {
Initializer = Args[0];
if (!isa<InitListExpr>(Initializer))
SourceType = Initializer->getType();
@@ -2785,11 +2796,18 @@ InitializationSequence::InitializationSequence(Sema &S,
}
// - If the initializer is (), the object is value-initialized.
- if (Kind.getKind() == InitializationKind::IK_Value) {
+ if (Kind.getKind() == InitializationKind::IK_Value ||
+ (Kind.getKind() == InitializationKind::IK_Direct && NumArgs == 0)) {
TryValueInitialization(S, Entity, Kind, *this);
return;
}
+ // Handle default initialization.
+ if (Kind.getKind() == InitializationKind::IK_Default){
+ TryDefaultInitialization(S, Entity, Kind, *this);
+ return;
+ }
+
// - Otherwise, if the destination type is an array, the program is
// ill-formed.
if (const ArrayType *AT = Context.getAsArrayType(DestType)) {
@@ -2800,6 +2818,13 @@ InitializationSequence::InitializationSequence(Sema &S,
return;
}
+
+ // Handle initialization in C
+ if (!S.getLangOptions().CPlusPlus) {
+ setSequenceKind(CAssignment);
+ AddCAssignmentStep(DestType);
+ return;
+ }
// - If the destination type is a (possibly cv-qualified) class type:
if (DestType->isRecordType()) {
@@ -2812,7 +2837,7 @@ InitializationSequence::InitializationSequence(Sema &S,
(Context.hasSameUnqualifiedType(SourceType, DestType) ||
S.IsDerivedFrom(SourceType, DestType))))
TryConstructorInitialization(S, Entity, Kind, Args, NumArgs,
- Entity.getType().getType(), *this);
+ Entity.getType(), *this);
// - Otherwise (i.e., for the remaining copy-initialization cases),
// user-defined conversion sequences that can convert from the source
// type to the destination type or (when a conversion function is
@@ -2824,9 +2849,15 @@ InitializationSequence::InitializationSequence(Sema &S,
return;
}
+ if (NumArgs > 1) {
+ SetFailed(FK_TooManyInitsForScalar);
+ return;
+ }
+ assert(NumArgs == 1 && "Zero-argument case handled above");
+
// - Otherwise, if the source type is a (possibly cv-qualified) class
// type, conversion functions are considered.
- if (SourceType->isRecordType()) {
+ if (!SourceType.isNull() && SourceType->isRecordType()) {
TryUserDefinedConversion(S, Entity, Kind, Initializer, *this);
return;
}
@@ -2836,6 +2867,7 @@ InitializationSequence::InitializationSequence(Sema &S,
// conversions (Clause 4) will be used, if necessary, to convert the
// initializer expression to the cv-unqualified version of the
// destination type; no user-defined conversions are considered.
+ setSequenceKind(StandardConversion);
TryImplicitConversion(S, Entity, Kind, Initializer, *this);
}
@@ -2849,6 +2881,158 @@ InitializationSequence::~InitializationSequence() {
//===----------------------------------------------------------------------===//
// Perform initialization
//===----------------------------------------------------------------------===//
+static Sema::AssignmentAction
+getAssignmentAction(const InitializedEntity &Entity) {
+ switch(Entity.getKind()) {
+ case InitializedEntity::EK_Variable:
+ case InitializedEntity::EK_New:
+ return Sema::AA_Initializing;
+
+ case InitializedEntity::EK_Parameter:
+ // FIXME: Can we tell when we're sending vs. passing?
+ return Sema::AA_Passing;
+
+ case InitializedEntity::EK_Result:
+ return Sema::AA_Returning;
+
+ case InitializedEntity::EK_Exception:
+ case InitializedEntity::EK_Base:
+ llvm_unreachable("No assignment action for C++-specific initialization");
+ break;
+
+ case InitializedEntity::EK_Temporary:
+ // FIXME: Can we tell apart casting vs. converting?
+ return Sema::AA_Casting;
+
+ case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_ArrayOrVectorElement:
+ return Sema::AA_Initializing;
+ }
+
+ return Sema::AA_Converting;
+}
+
+static bool shouldBindAsTemporary(const InitializedEntity &Entity,
+ bool IsCopy) {
+ switch (Entity.getKind()) {
+ case InitializedEntity::EK_Result:
+ case InitializedEntity::EK_Exception:
+ return !IsCopy;
+
+ case InitializedEntity::EK_New:
+ case InitializedEntity::EK_Variable:
+ case InitializedEntity::EK_Base:
+ case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_ArrayOrVectorElement:
+ return false;
+
+ case InitializedEntity::EK_Parameter:
+ case InitializedEntity::EK_Temporary:
+ return true;
+ }
+
+ llvm_unreachable("missed an InitializedEntity kind?");
+}
+
+/// \brief If we need to perform an additional copy of the initialized object
+/// for this kind of entity (e.g., the result of a function or an object being
+/// thrown), make the copy.
+static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Sema::OwningExprResult CurInit) {
+ SourceLocation Loc;
+
+ switch (Entity.getKind()) {
+ case InitializedEntity::EK_Result:
+ if (Entity.getType()->isReferenceType())
+ return move(CurInit);
+ Loc = Entity.getReturnLoc();
+ break;
+
+ case InitializedEntity::EK_Exception:
+ Loc = Entity.getThrowLoc();
+ break;
+
+ case InitializedEntity::EK_Variable:
+ if (Entity.getType()->isReferenceType() ||
+ Kind.getKind() != InitializationKind::IK_Copy)
+ return move(CurInit);
+ Loc = Entity.getDecl()->getLocation();
+ break;
+
+ case InitializedEntity::EK_Parameter:
+ // FIXME: Do we need this initialization for a parameter?
+ return move(CurInit);
+
+ case InitializedEntity::EK_New:
+ case InitializedEntity::EK_Temporary:
+ case InitializedEntity::EK_Base:
+ case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_ArrayOrVectorElement:
+ // We don't need to copy for any of these initialized entities.
+ return move(CurInit);
+ }
+
+ Expr *CurInitExpr = (Expr *)CurInit.get();
+ CXXRecordDecl *Class = 0;
+ if (const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>())
+ Class = cast<CXXRecordDecl>(Record->getDecl());
+ if (!Class)
+ return move(CurInit);
+
+ // Perform overload resolution using the class's copy constructors.
+ DeclarationName ConstructorName
+ = S.Context.DeclarationNames.getCXXConstructorName(
+ S.Context.getCanonicalType(S.Context.getTypeDeclType(Class)));
+ DeclContext::lookup_iterator Con, ConEnd;
+ OverloadCandidateSet CandidateSet;
+ for (llvm::tie(Con, ConEnd) = Class->lookup(ConstructorName);
+ Con != ConEnd; ++Con) {
+ // Find the constructor (which may be a template).
+ CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(*Con);
+ if (!Constructor || Constructor->isInvalidDecl() ||
+ !Constructor->isCopyConstructor())
+ continue;
+
+ S.AddOverloadCandidate(Constructor, &CurInitExpr, 1, CandidateSet);
+ }
+
+ OverloadCandidateSet::iterator Best;
+ switch (S.BestViableFunction(CandidateSet, Loc, Best)) {
+ case OR_Success:
+ break;
+
+ case OR_No_Viable_Function:
+ S.Diag(Loc, diag::err_temp_copy_no_viable)
+ << (int)Entity.getKind() << CurInitExpr->getType()
+ << CurInitExpr->getSourceRange();
+ S.PrintOverloadCandidates(CandidateSet, false);
+ return S.ExprError();
+
+ case OR_Ambiguous:
+ S.Diag(Loc, diag::err_temp_copy_ambiguous)
+ << (int)Entity.getKind() << CurInitExpr->getType()
+ << CurInitExpr->getSourceRange();
+ S.PrintOverloadCandidates(CandidateSet, true);
+ return S.ExprError();
+
+ case OR_Deleted:
+ S.Diag(Loc, diag::err_temp_copy_deleted)
+ << (int)Entity.getKind() << CurInitExpr->getType()
+ << CurInitExpr->getSourceRange();
+ S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
+ << Best->Function->isDeleted();
+ return S.ExprError();
+ }
+
+ CurInit.release();
+ return S.BuildCXXConstructExpr(Loc, CurInitExpr->getType(),
+ cast<CXXConstructorDecl>(Best->Function),
+ /*Elidable=*/true,
+ Sema::MultiExprArg(S,
+ (void**)&CurInitExpr, 1));
+}
Action::OwningExprResult
InitializationSequence::Perform(Sema &S,
@@ -2866,9 +3050,9 @@ InitializationSequence::Perform(Sema &S,
// 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.
- if (ResultType && !Entity.getType().getType()->isDependentType() &&
+ if (ResultType && !Entity.getType()->isDependentType() &&
Args.size() == 1) {
- QualType DeclType = Entity.getType().getType();
+ QualType DeclType = Entity.getType();
if (const IncompleteArrayType *ArrayT
= S.Context.getAsIncompleteArrayType(DeclType)) {
// FIXME: We don't currently have the ability to accurately
@@ -2880,11 +3064,15 @@ InitializationSequence::Perform(Sema &S,
// bound.
if (isa<InitListExpr>((Expr *)Args.get()[0])) {
SourceRange Brackets;
+
// Scavange the location of the brackets from the entity, if we can.
- if (isa<IncompleteArrayTypeLoc>(Entity.getType())) {
- IncompleteArrayTypeLoc ArrayLoc
- = cast<IncompleteArrayTypeLoc>(Entity.getType());
- Brackets = ArrayLoc.getBracketsRange();
+ if (DeclaratorDecl *DD = Entity.getDecl()) {
+ if (TypeSourceInfo *TInfo = DD->getTypeSourceInfo()) {
+ TypeLoc TL = TInfo->getTypeLoc();
+ if (IncompleteArrayTypeLoc *ArrayLoc
+ = dyn_cast<IncompleteArrayTypeLoc>(&TL))
+ Brackets = ArrayLoc->getBracketsRange();
+ }
}
*ResultType
@@ -2898,7 +3086,7 @@ InitializationSequence::Perform(Sema &S,
}
}
- if (Kind.getKind() == InitializationKind::IK_Copy)
+ if (Kind.getKind() == InitializationKind::IK_Copy || Kind.isExplicitCast())
return Sema::OwningExprResult(S, Args.release()[0]);
unsigned NumArgs = Args.size();
@@ -2909,34 +3097,58 @@ InitializationSequence::Perform(Sema &S,
SourceLocation()));
}
- QualType DestType = Entity.getType().getType().getNonReferenceType();
+ if (SequenceKind == NoInitialization)
+ return S.Owned((Expr *)0);
+
+ QualType DestType = Entity.getType().getNonReferenceType();
+ // FIXME: Ugly hack around the fact that Entity.getType() is not
+ // the same as Entity.getDecl()->getType() in cases involving type merging,
+ // and we want latter when it makes sense.
if (ResultType)
- *ResultType = Entity.getType().getType();
-
- Sema::OwningExprResult CurInit(S);
- // For copy initialization and any other initialization forms that
- // only have a single initializer, we start with the (only)
- // initializer we have.
- // FIXME: DPG is not happy about this. There's confusion regarding whether
- // we're supposed to start the conversion from the solitary initializer or
- // from the set of arguments.
- if (Kind.getKind() == InitializationKind::IK_Copy ||
- SequenceKind != ConstructorInitialization) {
+ *ResultType = Entity.getDecl() ? Entity.getDecl()->getType() :
+ Entity.getType();
+
+ Sema::OwningExprResult 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.
+ switch (Steps.front().Kind) {
+ case SK_ResolveAddressOfOverloadedFunction:
+ case SK_CastDerivedToBaseRValue:
+ case SK_CastDerivedToBaseLValue:
+ case SK_BindReference:
+ case SK_BindReferenceToTemporary:
+ case SK_UserConversion:
+ case SK_QualificationConversionLValue:
+ case SK_QualificationConversionRValue:
+ case SK_ConversionSequence:
+ case SK_ListInitialization:
+ case SK_CAssignment:
+ case SK_StringInit:
assert(Args.size() == 1);
- CurInit = Sema::OwningExprResult(S, Args.release()[0]);
+ CurInit = Sema::OwningExprResult(S, ((Expr **)(Args.get()))[0]->Retain());
if (CurInit.isInvalid())
return S.ExprError();
+ break;
+
+ case SK_ConstructorInitialization:
+ case SK_ZeroInitialization:
+ break;
}
// Walk through the computed steps for the initialization sequence,
// performing the specified conversions along the way.
+ bool ConstructorInitRequiresZeroInit = false;
for (step_iterator Step = step_begin(), StepEnd = step_end();
Step != StepEnd; ++Step) {
if (CurInit.isInvalid())
return S.ExprError();
Expr *CurInitExpr = (Expr *)CurInit.get();
- QualType SourceType = CurInitExpr->getType();
+ QualType SourceType = CurInitExpr? CurInitExpr->getType() : QualType();
switch (Step->Kind) {
case SK_ResolveAddressOfOverloadedFunction:
@@ -2969,7 +3181,7 @@ InitializationSequence::Perform(Sema &S,
if (FieldDecl *BitField = CurInitExpr->getBitField()) {
// References cannot bind to bit fields (C++ [dcl.init.ref]p5).
S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield)
- << Entity.getType().getType().isVolatileQualified()
+ << Entity.getType().isVolatileQualified()
<< BitField->getDeclName()
<< CurInitExpr->getSourceRange();
S.Diag(BitField->getLocation(), diag::note_bitfield_decl);
@@ -2996,6 +3208,7 @@ InitializationSequence::Perform(Sema &S,
// We have a user-defined conversion that invokes either a constructor
// or a conversion function.
CastExpr::CastKind CastKind = CastExpr::CK_Unknown;
+ bool IsCopy = false;
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(Step->Function)) {
// Build a call to the selected constructor.
@@ -3019,10 +3232,14 @@ InitializationSequence::Perform(Sema &S,
return S.ExprError();
CastKind = CastExpr::CK_ConstructorConversion;
+ QualType Class = S.Context.getTypeDeclType(Constructor->getParent());
+ if (S.Context.hasSameUnqualifiedType(SourceType, Class) ||
+ S.IsDerivedFrom(SourceType, Class))
+ IsCopy = true;
} else {
// Build a call to the conversion function.
CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Step->Function);
-
+
// FIXME: Should we move this initialization into a separate
// derived-to-base conversion? I believe the answer is "no", because
// we don't want to turn off access control here for c-style casts.
@@ -3041,12 +3258,17 @@ InitializationSequence::Perform(Sema &S,
CastKind = CastExpr::CK_UserDefinedConversion;
}
- CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+ if (shouldBindAsTemporary(Entity, IsCopy))
+ CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+
CurInitExpr = CurInit.takeAs<Expr>();
CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(),
CastKind,
CurInitExpr,
- false));
+ false));
+
+ if (!IsCopy)
+ CurInit = CopyIfRequiredForEntity(S, Entity, Kind, move(CurInit));
break;
}
@@ -3061,7 +3283,7 @@ InitializationSequence::Perform(Sema &S,
break;
case SK_ConversionSequence:
- if (S.PerformImplicitConversion(CurInitExpr, Step->Type, "converting",
+ if (S.PerformImplicitConversion(CurInitExpr, Step->Type, Sema::AA_Converting,
false, false, *Step->ICS))
return S.ExprError();
@@ -3072,7 +3294,7 @@ InitializationSequence::Perform(Sema &S,
case SK_ListInitialization: {
InitListExpr *InitList = cast<InitListExpr>(CurInitExpr);
QualType Ty = Step->Type;
- if (S.CheckInitList(InitList, ResultType? *ResultType : Ty))
+ if (S.CheckInitList(Entity, InitList, ResultType? *ResultType : Ty))
return S.ExprError();
CurInit.release();
@@ -3095,22 +3317,68 @@ InitializationSequence::Perform(Sema &S,
return S.ExprError();
// Build the an expression that constructs a temporary.
- CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor,
- move_arg(ConstructorArgs));
+ CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
+ Constructor,
+ move_arg(ConstructorArgs),
+ ConstructorInitRequiresZeroInit);
if (CurInit.isInvalid())
return S.ExprError();
-
- CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+
+ bool Elidable
+ = cast<CXXConstructExpr>((Expr *)CurInit.get())->isElidable();
+ if (shouldBindAsTemporary(Entity, Elidable))
+ CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+
+ if (!Elidable)
+ CurInit = CopyIfRequiredForEntity(S, Entity, Kind, move(CurInit));
break;
}
case SK_ZeroInitialization: {
- if (Kind.getKind() == InitializationKind::IK_Value)
+ step_iterator NextStep = Step;
+ ++NextStep;
+ if (NextStep != StepEnd &&
+ NextStep->Kind == SK_ConstructorInitialization) {
+ // The need for zero-initialization is recorded directly into
+ // the call to the object's constructor within the next step.
+ ConstructorInitRequiresZeroInit = true;
+ } else if (Kind.getKind() == InitializationKind::IK_Value &&
+ S.getLangOptions().CPlusPlus &&
+ !Kind.isImplicitValueInit()) {
CurInit = S.Owned(new (S.Context) CXXZeroInitValueExpr(Step->Type,
Kind.getRange().getBegin(),
Kind.getRange().getEnd()));
- else
+ } else {
CurInit = S.Owned(new (S.Context) ImplicitValueInitExpr(Step->Type));
+ }
+ break;
+ }
+
+ case SK_CAssignment: {
+ QualType SourceType = CurInitExpr->getType();
+ Sema::AssignConvertType ConvTy =
+ S.CheckSingleAssignmentConstraints(Step->Type, CurInitExpr);
+
+ // If this is a call, allow conversion to a transparent union.
+ if (ConvTy != Sema::Compatible &&
+ Entity.getKind() == InitializedEntity::EK_Parameter &&
+ S.CheckTransparentUnionArgumentConstraints(Step->Type, CurInitExpr)
+ == Sema::Compatible)
+ ConvTy = Sema::Compatible;
+
+ if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(),
+ Step->Type, SourceType,
+ CurInitExpr, getAssignmentAction(Entity)))
+ return S.ExprError();
+
+ CurInit.release();
+ CurInit = S.Owned(CurInitExpr);
+ break;
+ }
+
+ case SK_StringInit: {
+ QualType Ty = Step->Type;
+ CheckStringInit(CurInitExpr, ResultType ? *ResultType : Ty, S);
break;
}
}
@@ -3129,7 +3397,7 @@ bool InitializationSequence::Diagnose(Sema &S,
if (SequenceKind != FailedSequence)
return false;
- QualType DestType = Entity.getType().getType();
+ QualType DestType = Entity.getType();
switch (Failure) {
case FK_TooManyInitsForReference:
S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits)
@@ -3152,9 +3420,15 @@ bool InitializationSequence::Diagnose(Sema &S,
case FK_UserConversionOverloadFailed:
switch (FailedOverloadResult) {
case OR_Ambiguous:
- S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition)
- << Args[0]->getType() << DestType.getNonReferenceType()
- << Args[0]->getSourceRange();
+ if (Failure == FK_UserConversionOverloadFailed)
+ S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition)
+ << Args[0]->getType() << DestType
+ << Args[0]->getSourceRange();
+ else
+ S.Diag(Kind.getLocation(), diag::err_ref_init_ambiguous)
+ << DestType << Args[0]->getType()
+ << Args[0]->getSourceRange();
+
S.PrintOverloadCandidates(FailedCandidateSet, true);
break;
@@ -3220,7 +3494,8 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
case FK_ConversionFailed:
- S.Diag(Kind.getLocation(), diag::err_cannot_initialize_decl_noname)
+ S.Diag(Kind.getLocation(), diag::err_init_conversion_failed)
+ << (int)Entity.getKind()
<< DestType
<< (Args[0]->isLvalue(S.Context) == Expr::LV_Valid)
<< Args[0]->getType()
@@ -3228,12 +3503,16 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
case FK_TooManyInitsForScalar: {
- InitListExpr *InitList = cast<InitListExpr>(Args[0]);
+ SourceRange R;
+
+ if (InitListExpr *InitList = dyn_cast<InitListExpr>(Args[0]))
+ R = SourceRange(InitList->getInit(1)->getLocStart(),
+ InitList->getLocEnd());
+ else
+ R = SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd());
S.Diag(Kind.getLocation(), diag::err_excess_initializers)
- << /*scalar=*/2
- << SourceRange(InitList->getInit(1)->getLocStart(),
- InitList->getLocEnd());
+ << /*scalar=*/2 << R;
break;
}
@@ -3290,7 +3569,36 @@ bool InitializationSequence::Diagnose(Sema &S,
}
break;
}
+
+ case FK_DefaultInitOfConst:
+ S.Diag(Kind.getLocation(), diag::err_default_init_const)
+ << DestType;
+ break;
}
return true;
}
+
+//===----------------------------------------------------------------------===//
+// Initialization helper functions
+//===----------------------------------------------------------------------===//
+Sema::OwningExprResult
+Sema::PerformCopyInitialization(const InitializedEntity &Entity,
+ SourceLocation EqualLoc,
+ OwningExprResult Init) {
+ if (Init.isInvalid())
+ return ExprError();
+
+ Expr *InitE = (Expr *)Init.get();
+ assert(InitE && "No initialization expression?");
+
+ if (EqualLoc.isInvalid())
+ EqualLoc = InitE->getLocStart();
+
+ InitializationKind Kind = InitializationKind::CreateCopy(InitE->getLocStart(),
+ EqualLoc);
+ InitializationSequence Seq(*this, Entity, Kind, &InitE, 1);
+ Init.release();
+ return Seq.Perform(*this, Entity, Kind,
+ MultiExprArg(*this, (void**)&InitE, 1));
+}
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index 2d4b01f..5eb819a 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -14,7 +14,7 @@
#define LLVM_CLANG_SEMA_INIT_H
#include "SemaOverload.h"
-#include "clang/AST/TypeLoc.h"
+#include "clang/AST/Type.h"
#include "clang/Parse/Action.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/PointerIntPair.h"
@@ -47,72 +47,79 @@ public:
/// \brief The entity being initialized is an exception object that
/// is being thrown.
EK_Exception,
+ /// \brief The entity being initialized is an object (or array of
+ /// objects) allocated via new.
+ EK_New,
/// \brief The entity being initialized is a temporary object.
EK_Temporary,
/// \brief The entity being initialized is a base member subobject.
EK_Base,
/// \brief The entity being initialized is a non-static data member
/// subobject.
- EK_Member
+ EK_Member,
+ /// \brief The entity being initialized is an element of an array
+ /// or vector.
+ EK_ArrayOrVectorElement
};
private:
/// \brief The kind of entity being initialized.
EntityKind Kind;
- /// \brief The type of the object or reference being initialized along with
- /// its location information.
- TypeLoc TL;
+ /// \brief If non-NULL, the parent entity in which this
+ /// initialization occurs.
+ const InitializedEntity *Parent;
+
+ /// \brief The type of the object or reference being initialized.
+ QualType Type;
union {
/// \brief When Kind == EK_Variable, EK_Parameter, or EK_Member,
/// the VarDecl, ParmVarDecl, or FieldDecl, respectively.
DeclaratorDecl *VariableOrMember;
- /// \brief When Kind == EK_Result or EK_Exception, the location of the
- /// 'return' or 'throw' keyword, respectively. When Kind == EK_Temporary,
- /// the location where the temporary is being created.
+ /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the
+ /// location of the 'return', 'throw', or 'new' keyword,
+ /// respectively. When Kind == EK_Temporary, the location where
+ /// the temporary is being created.
unsigned Location;
/// \brief When Kind == EK_Base, the base specifier that provides the
/// base class.
CXXBaseSpecifier *Base;
+
+ /// \brief When Kind = EK_ArrayOrVectorElement, the index of the
+ /// array or vector element being initialized.
+ unsigned Index;
};
InitializedEntity() { }
/// \brief Create the initialization entity for a variable.
InitializedEntity(VarDecl *Var)
- : Kind(EK_Variable),
- VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Var))
- {
- InitDeclLoc();
- }
+ : Kind(EK_Variable), Parent(0), Type(Var->getType()),
+ VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Var)) { }
/// \brief Create the initialization entity for a parameter.
InitializedEntity(ParmVarDecl *Parm)
- : Kind(EK_Parameter),
- VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Parm))
- {
- InitDeclLoc();
- }
+ : Kind(EK_Parameter), Parent(0), Type(Parm->getType().getUnqualifiedType()),
+ VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Parm)) { }
- /// \brief Create the initialization entity for the result of a function,
- /// throwing an object, or performing an explicit cast.
- InitializedEntity(EntityKind Kind, SourceLocation Loc, TypeLoc TL)
- : Kind(Kind), TL(TL), Location(Loc.getRawEncoding()) { }
+ /// \brief Create the initialization entity for the result of a
+ /// function, throwing an object, performing an explicit cast, or
+ /// initializing a parameter for which there is no declaration.
+ InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type)
+ : Kind(Kind), Parent(0), Type(Type), Location(Loc.getRawEncoding()) { }
/// \brief Create the initialization entity for a member subobject.
- InitializedEntity(FieldDecl *Member)
- : Kind(EK_Member),
- VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Member))
- {
- InitDeclLoc();
- }
-
- /// \brief Initialize type-location information from a declaration.
- void InitDeclLoc();
+ InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent)
+ : Kind(EK_Member), Parent(Parent), Type(Member->getType()),
+ VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Member)) { }
+ /// \brief Create the initialization entity for an array element.
+ InitializedEntity(ASTContext &Context, unsigned Index,
+ const InitializedEntity &Parent);
+
public:
/// \brief Create the initialization entity for a variable.
static InitializedEntity InitializeVariable(VarDecl *Var) {
@@ -124,38 +131,69 @@ public:
return InitializedEntity(Parm);
}
+ /// \brief Create the initialization entity for a parameter that is
+ /// only known by its type.
+ static InitializedEntity InitializeParameter(QualType Type) {
+ return InitializedEntity(EK_Parameter, SourceLocation(), Type);
+ }
+
/// \brief Create the initialization entity for the result of a function.
static InitializedEntity InitializeResult(SourceLocation ReturnLoc,
- TypeLoc TL) {
- return InitializedEntity(EK_Result, ReturnLoc, TL);
+ QualType Type) {
+ return InitializedEntity(EK_Result, ReturnLoc, Type);
}
/// \brief Create the initialization entity for an exception object.
static InitializedEntity InitializeException(SourceLocation ThrowLoc,
- TypeLoc TL) {
- return InitializedEntity(EK_Exception, ThrowLoc, TL);
+ QualType Type) {
+ return InitializedEntity(EK_Exception, ThrowLoc, Type);
+ }
+
+ /// \brief Create the initialization entity for an object allocated via new.
+ static InitializedEntity InitializeNew(SourceLocation NewLoc, QualType Type) {
+ return InitializedEntity(EK_New, NewLoc, Type);
}
/// \brief Create the initialization entity for a temporary.
- static InitializedEntity InitializeTemporary(EntityKind Kind, TypeLoc TL) {
- return InitializedEntity(Kind, SourceLocation(), TL);
+ static InitializedEntity InitializeTemporary(QualType Type) {
+ return InitializedEntity(EK_Temporary, SourceLocation(), Type);
}
/// \brief Create the initialization entity for a base class subobject.
static InitializedEntity InitializeBase(ASTContext &Context,
CXXBaseSpecifier *Base);
- /// \brief Create the initialize entity for a member subobject.
- static InitializedEntity InitializeMember(FieldDecl *Member) {
- return InitializedEntity(Member);
+ /// \brief Create the initialization entity for a member subobject.
+ static InitializedEntity InitializeMember(FieldDecl *Member,
+ const InitializedEntity *Parent = 0) {
+ return InitializedEntity(Member, Parent);
}
+ /// \brief Create the initialization entity for an array element.
+ static InitializedEntity InitializeElement(ASTContext &Context,
+ unsigned Index,
+ const InitializedEntity &Parent) {
+ return InitializedEntity(Context, Index, Parent);
+ }
+
/// \brief Determine the kind of initialization.
EntityKind getKind() const { return Kind; }
+ /// \brief Retrieve the parent of the entity being initialized, when
+ /// the initialization itself is occuring within the context of a
+ /// larger initialization.
+ const InitializedEntity *getParent() const { return Parent; }
+
/// \brief Retrieve type being initialized.
- TypeLoc getType() const { return TL; }
+ QualType getType() const { return Type; }
+ /// \brief Retrieve the name of the entity being initialized.
+ DeclarationName getName() const;
+
+ /// \brief Retrieve the variable, parameter, or field being
+ /// initialized.
+ DeclaratorDecl *getDecl() const;
+
/// \brief Determine the location of the 'return' keyword when initializing
/// the result of a function call.
SourceLocation getReturnLoc() const {
@@ -169,6 +207,13 @@ public:
assert(getKind() == EK_Exception && "No 'throw' location!");
return SourceLocation::getFromRawEncoding(Location);
}
+
+ /// \brief If this is already the initializer for an array or vector
+ /// element, sets the element index.
+ void setElementIndex(unsigned Index) {
+ assert(getKind() == EK_ArrayOrVectorElement);
+ this->Index = Index;
+ }
};
/// \brief Describes the kind of initialization being performed, along with
@@ -191,6 +236,7 @@ private:
SIK_Copy = IK_Copy, ///< Copy initialization
SIK_Default = IK_Default, ///< Default initialization
SIK_Value = IK_Value, ///< Value initialization
+ SIK_ImplicitValue, ///< Implicit value initialization
SIK_DirectCast, ///< Direct initialization due to a cast
/// \brief Direct initialization due to a C-style or functional cast.
SIK_DirectCStyleOrFunctionalCast
@@ -242,15 +288,19 @@ public:
/// \brief Create a value initialization.
static InitializationKind CreateValue(SourceLocation InitLoc,
SourceLocation LParenLoc,
- SourceLocation RParenLoc) {
- return InitializationKind(SIK_Value, InitLoc, LParenLoc, RParenLoc);
+ SourceLocation RParenLoc,
+ bool isImplicit = false) {
+ return InitializationKind(isImplicit? SIK_ImplicitValue : SIK_Value,
+ InitLoc, LParenLoc, RParenLoc);
}
/// \brief Determine the initialization kind.
InitKind getKind() const {
- if (Kind > SIK_Value)
+ if (Kind > SIK_ImplicitValue)
return IK_Direct;
-
+ if (Kind == SIK_ImplicitValue)
+ return IK_Value;
+
return (InitKind)Kind;
}
@@ -263,7 +313,12 @@ public:
bool isCStyleOrFunctionalCast() const {
return Kind == SIK_DirectCStyleOrFunctionalCast;
}
-
+
+ /// \brief Determine whether this initialization is an implicit
+ /// value-initialization, e.g., as occurs during aggregate
+ /// initialization.
+ bool isImplicitValueInit() const { return Kind == SIK_ImplicitValue; }
+
/// \brief Retrieve the location at which initialization is occurring.
SourceLocation getLocation() const { return Locations[0]; }
@@ -319,7 +374,19 @@ public:
ListInitialization,
/// \brief Zero-initialization.
- ZeroInitialization
+ ZeroInitialization,
+
+ /// \brief No initialization required.
+ NoInitialization,
+
+ /// \brief Standard conversion sequence.
+ StandardConversion,
+
+ /// \brief C conversion sequence.
+ CAssignment,
+
+ /// \brief String initialization
+ StringInit
};
/// \brief Describes the kind of a particular step in an initialization
@@ -350,7 +417,11 @@ public:
/// \brief Perform initialization via a constructor.
SK_ConstructorInitialization,
/// \brief Zero-initialize the object
- SK_ZeroInitialization
+ SK_ZeroInitialization,
+ /// \brief C assignment
+ SK_CAssignment,
+ /// \brief Initialization by string
+ SK_StringInit
};
/// \brief A single step in the initialization sequence.
@@ -420,7 +491,9 @@ public:
/// \brief Overloading for a user-defined conversion failed.
FK_UserConversionOverloadFailed,
/// \brief Overloaded for initialization by constructor failed.
- FK_ConstructorOverloadFailed
+ FK_ConstructorOverloadFailed,
+ /// \brief Default-initialization of a 'const' object.
+ FK_DefaultInitOfConst
};
private:
@@ -551,6 +624,16 @@ public:
/// \brief Add a zero-initialization step.
void AddZeroInitializationStep(QualType T);
+ /// \brief Add a C assignment step.
+ //
+ // FIXME: It isn't clear whether this should ever be needed;
+ // ideally, we would handle everything needed in C in the common
+ // path. However, that isn't the case yet.
+ void AddCAssignmentStep(QualType T);
+
+ /// \brief Add a string init step.
+ void AddStringInitStep(QualType T);
+
/// \brief Note that this initialization sequence failed.
void SetFailed(FailureKind Failure) {
SequenceKind = FailedSequence;
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 724e2fc..1419ceb 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -27,6 +27,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ErrorHandling.h"
+#include <list>
#include <set>
#include <vector>
#include <iterator>
@@ -192,23 +193,83 @@ namespace {
};
}
+static bool IsAcceptableIDNS(NamedDecl *D, unsigned IDNS) {
+ return D->isInIdentifierNamespace(IDNS);
+}
+
+static bool IsAcceptableOperatorName(NamedDecl *D, unsigned IDNS) {
+ return D->isInIdentifierNamespace(IDNS) &&
+ !D->getDeclContext()->isRecord();
+}
+
+static bool IsAcceptableNestedNameSpecifierName(NamedDecl *D, unsigned IDNS) {
+ // This lookup ignores everything that isn't a type.
+
+ // This is a fast check for the far most common case.
+ if (D->isInIdentifierNamespace(Decl::IDNS_Tag))
+ return true;
+
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+ return isa<TypeDecl>(D);
+}
+
+static bool IsAcceptableNamespaceName(NamedDecl *D, unsigned IDNS) {
+ // We don't need to look through using decls here because
+ // using decls aren't allowed to name namespaces.
+
+ return isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D);
+}
+
+/// Gets the default result filter for the given lookup.
+static inline
+LookupResult::ResultFilter getResultFilter(Sema::LookupNameKind NameKind) {
+ switch (NameKind) {
+ case Sema::LookupOrdinaryName:
+ case Sema::LookupTagName:
+ case Sema::LookupMemberName:
+ case Sema::LookupRedeclarationWithLinkage: // FIXME: check linkage, scoping
+ case Sema::LookupUsingDeclName:
+ case Sema::LookupObjCProtocolName:
+ case Sema::LookupObjCImplementationName:
+ return &IsAcceptableIDNS;
+
+ case Sema::LookupOperatorName:
+ return &IsAcceptableOperatorName;
+
+ case Sema::LookupNestedNameSpecifierName:
+ return &IsAcceptableNestedNameSpecifierName;
+
+ case Sema::LookupNamespaceName:
+ return &IsAcceptableNamespaceName;
+ }
+
+ llvm_unreachable("unkknown lookup kind");
+ return 0;
+}
+
// Retrieve the set of identifier namespaces that correspond to a
// specific kind of name lookup.
-inline unsigned
-getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
- bool CPlusPlus) {
+static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
+ bool CPlusPlus,
+ bool Redeclaration) {
unsigned IDNS = 0;
switch (NameKind) {
case Sema::LookupOrdinaryName:
case Sema::LookupOperatorName:
case Sema::LookupRedeclarationWithLinkage:
IDNS = Decl::IDNS_Ordinary;
- if (CPlusPlus)
+ if (CPlusPlus) {
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member;
+ if (Redeclaration) IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend;
+ }
break;
case Sema::LookupTagName:
IDNS = Decl::IDNS_Tag;
+ if (CPlusPlus && Redeclaration)
+ IDNS |= Decl::IDNS_TagFriend;
break;
case Sema::LookupMemberName:
@@ -238,6 +299,13 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
return IDNS;
}
+void LookupResult::configure() {
+ IDNS = getIDNS(LookupKind,
+ SemaRef.getLangOptions().CPlusPlus,
+ isForRedeclaration());
+ IsAcceptableFn = getResultFilter(LookupKind);
+}
+
// Necessary because CXXBasePaths is not complete in Sema.h
void LookupResult::deletePaths(CXXBasePaths *Paths) {
delete Paths;
@@ -377,8 +445,7 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) {
DeclContext::lookup_const_iterator I, E;
for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I)
- if (Sema::isAcceptableLookupResult(*I, R.getLookupKind(),
- R.getIdentifierNamespace()))
+ if (R.isAcceptableDecl(*I))
R.addDecl(*I), Found = true;
return Found;
@@ -424,19 +491,7 @@ static DeclContext *findOuterContext(Scope *S) {
}
bool Sema::CppLookupName(LookupResult &R, Scope *S) {
- assert(getLangOptions().CPlusPlus &&
- "Can perform only C++ lookup");
- LookupNameKind NameKind = R.getLookupKind();
- unsigned IDNS
- = getIdentifierNamespacesFromLookupNameKind(NameKind, /*CPlusPlus*/ true);
-
- // If we're testing for redeclarations, also look in the friend namespaces.
- if (R.isForRedeclaration()) {
- if (IDNS & Decl::IDNS_Tag) IDNS |= Decl::IDNS_TagFriend;
- if (IDNS & Decl::IDNS_Ordinary) IDNS |= Decl::IDNS_OrdinaryFriend;
- }
-
- R.setIdentifierNamespace(IDNS);
+ assert(getLangOptions().CPlusPlus && "Can perform only C++ lookup");
DeclarationName Name = R.getLookupName();
@@ -467,7 +522,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// Check whether the IdResolver has anything in this scope.
bool Found = false;
for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) {
- if (isAcceptableLookupResult(*I, NameKind, IDNS)) {
+ if (R.isAcceptableDecl(*I)) {
Found = true;
R.addDecl(*I);
}
@@ -531,7 +586,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// Check whether the IdResolver has anything in this scope.
bool Found = false;
for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) {
- if (isAcceptableLookupResult(*I, NameKind, IDNS)) {
+ if (R.isAcceptableDecl(*I)) {
// We found something. Look for anything else in our scope
// with this same name and in an acceptable identifier
// namespace, so that we can construct an overload set if we
@@ -597,47 +652,18 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
if (!getLangOptions().CPlusPlus) {
// Unqualified name lookup in C/Objective-C is purely lexical, so
// search in the declarations attached to the name.
- unsigned IDNS = 0;
- switch (NameKind) {
- case Sema::LookupOrdinaryName:
- IDNS = Decl::IDNS_Ordinary;
- break;
- case Sema::LookupTagName:
- IDNS = Decl::IDNS_Tag;
- break;
-
- case Sema::LookupMemberName:
- IDNS = Decl::IDNS_Member;
- break;
-
- case Sema::LookupOperatorName:
- case Sema::LookupNestedNameSpecifierName:
- case Sema::LookupNamespaceName:
- case Sema::LookupUsingDeclName:
- assert(false && "C does not perform these kinds of name lookup");
- break;
-
- case Sema::LookupRedeclarationWithLinkage:
+ if (NameKind == Sema::LookupRedeclarationWithLinkage) {
// Find the nearest non-transparent declaration scope.
while (!(S->getFlags() & Scope::DeclScope) ||
(S->getEntity() &&
static_cast<DeclContext *>(S->getEntity())
->isTransparentContext()))
S = S->getParent();
- IDNS = Decl::IDNS_Ordinary;
- break;
-
- case Sema::LookupObjCProtocolName:
- IDNS = Decl::IDNS_ObjCProtocol;
- break;
-
- case Sema::LookupObjCImplementationName:
- IDNS = Decl::IDNS_ObjCImplementation;
- break;
-
}
+ unsigned IDNS = R.getIdentifierNamespace();
+
// Scan up the scope chain looking for a decl that matches this
// identifier that is in the appropriate namespace. This search
// should not take long, as shadowing of names is uncommon, and
@@ -864,17 +890,6 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) {
if (!R.getLookupName())
return false;
- // If we're performing qualified name lookup (e.g., lookup into a
- // struct), find fields as part of ordinary name lookup.
- LookupNameKind NameKind = R.getLookupKind();
- unsigned IDNS
- = getIdentifierNamespacesFromLookupNameKind(NameKind,
- getLangOptions().CPlusPlus);
- if (NameKind == LookupOrdinaryName)
- IDNS |= Decl::IDNS_Member;
-
- R.setIdentifierNamespace(IDNS);
-
// Make sure that the declaration context is complete.
assert((!isa<TagDecl>(LookupCtx) ||
LookupCtx->isDependentContext() ||
@@ -1514,15 +1529,12 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Functions.begin(),
E = Functions.end(); I != E; ++I) {
- FunctionDecl *FDecl = dyn_cast<FunctionDecl>(*I);
- if (!FDecl)
- FDecl = cast<FunctionTemplateDecl>(*I)->getTemplatedDecl();
+ // Look through any using declarations to find the underlying function.
+ NamedDecl *Fn = (*I)->getUnderlyingDecl();
- // Add the namespace in which this function was defined. Note
- // that, if this is a member function, we do *not* consider the
- // enclosing namespace of its class.
- DeclContext *Ctx = FDecl->getDeclContext();
- CollectNamespace(AssociatedNamespaces, Ctx);
+ FunctionDecl *FDecl = dyn_cast<FunctionDecl>(Fn);
+ if (!FDecl)
+ FDecl = cast<FunctionTemplateDecl>(Fn)->getTemplatedDecl();
// Add the classes and namespaces associated with the parameter
// types and return type of this function.
@@ -1693,3 +1705,509 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
}
}
}
+
+//----------------------------------------------------------------------------
+// Search for all visible declarations.
+//----------------------------------------------------------------------------
+VisibleDeclConsumer::~VisibleDeclConsumer() { }
+
+namespace {
+
+class ShadowContextRAII;
+
+class VisibleDeclsRecord {
+public:
+ /// \brief An entry in the shadow map, which is optimized to store a
+ /// single declaration (the common case) but can also store a list
+ /// of declarations.
+ class ShadowMapEntry {
+ typedef llvm::SmallVector<NamedDecl *, 4> DeclVector;
+
+ /// \brief Contains either the solitary NamedDecl * or a vector
+ /// of declarations.
+ llvm::PointerUnion<NamedDecl *, DeclVector*> DeclOrVector;
+
+ public:
+ ShadowMapEntry() : DeclOrVector() { }
+
+ void Add(NamedDecl *ND);
+ void Destroy();
+
+ // Iteration.
+ typedef NamedDecl **iterator;
+ iterator begin();
+ iterator end();
+ };
+
+private:
+ /// \brief A mapping from declaration names to the declarations that have
+ /// this name within a particular scope.
+ typedef llvm::DenseMap<DeclarationName, ShadowMapEntry> ShadowMap;
+
+ /// \brief A list of shadow maps, which is used to model name hiding.
+ std::list<ShadowMap> ShadowMaps;
+
+ /// \brief The declaration contexts we have already visited.
+ llvm::SmallPtrSet<DeclContext *, 8> VisitedContexts;
+
+ friend class ShadowContextRAII;
+
+public:
+ /// \brief Determine whether we have already visited this context
+ /// (and, if not, note that we are going to visit that context now).
+ bool visitedContext(DeclContext *Ctx) {
+ return !VisitedContexts.insert(Ctx);
+ }
+
+ /// \brief Determine whether the given declaration is hidden in the
+ /// current scope.
+ ///
+ /// \returns the declaration that hides the given declaration, or
+ /// NULL if no such declaration exists.
+ NamedDecl *checkHidden(NamedDecl *ND);
+
+ /// \brief Add a declaration to the current shadow map.
+ void add(NamedDecl *ND) { ShadowMaps.back()[ND->getDeclName()].Add(ND); }
+};
+
+/// \brief RAII object that records when we've entered a shadow context.
+class ShadowContextRAII {
+ VisibleDeclsRecord &Visible;
+
+ typedef VisibleDeclsRecord::ShadowMap ShadowMap;
+
+public:
+ ShadowContextRAII(VisibleDeclsRecord &Visible) : Visible(Visible) {
+ Visible.ShadowMaps.push_back(ShadowMap());
+ }
+
+ ~ShadowContextRAII() {
+ for (ShadowMap::iterator E = Visible.ShadowMaps.back().begin(),
+ EEnd = Visible.ShadowMaps.back().end();
+ E != EEnd;
+ ++E)
+ E->second.Destroy();
+
+ Visible.ShadowMaps.pop_back();
+ }
+};
+
+} // end anonymous namespace
+
+void VisibleDeclsRecord::ShadowMapEntry::Add(NamedDecl *ND) {
+ if (DeclOrVector.isNull()) {
+ // 0 - > 1 elements: just set the single element information.
+ DeclOrVector = ND;
+ return;
+ }
+
+ if (NamedDecl *PrevND = DeclOrVector.dyn_cast<NamedDecl *>()) {
+ // 1 -> 2 elements: create the vector of results and push in the
+ // existing declaration.
+ DeclVector *Vec = new DeclVector;
+ Vec->push_back(PrevND);
+ DeclOrVector = Vec;
+ }
+
+ // Add the new element to the end of the vector.
+ DeclOrVector.get<DeclVector*>()->push_back(ND);
+}
+
+void VisibleDeclsRecord::ShadowMapEntry::Destroy() {
+ if (DeclVector *Vec = DeclOrVector.dyn_cast<DeclVector *>()) {
+ delete Vec;
+ DeclOrVector = ((NamedDecl *)0);
+ }
+}
+
+VisibleDeclsRecord::ShadowMapEntry::iterator
+VisibleDeclsRecord::ShadowMapEntry::begin() {
+ if (DeclOrVector.isNull())
+ return 0;
+
+ if (DeclOrVector.dyn_cast<NamedDecl *>())
+ return &reinterpret_cast<NamedDecl*&>(DeclOrVector);
+
+ return DeclOrVector.get<DeclVector *>()->begin();
+}
+
+VisibleDeclsRecord::ShadowMapEntry::iterator
+VisibleDeclsRecord::ShadowMapEntry::end() {
+ if (DeclOrVector.isNull())
+ return 0;
+
+ if (DeclOrVector.dyn_cast<NamedDecl *>())
+ return &reinterpret_cast<NamedDecl*&>(DeclOrVector) + 1;
+
+ return DeclOrVector.get<DeclVector *>()->end();
+}
+
+NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
+ unsigned IDNS = ND->getIdentifierNamespace();
+ std::list<ShadowMap>::reverse_iterator SM = ShadowMaps.rbegin();
+ for (std::list<ShadowMap>::reverse_iterator SMEnd = ShadowMaps.rend();
+ SM != SMEnd; ++SM) {
+ ShadowMap::iterator Pos = SM->find(ND->getDeclName());
+ if (Pos == SM->end())
+ continue;
+
+ for (ShadowMapEntry::iterator I = Pos->second.begin(),
+ IEnd = Pos->second.end();
+ I != IEnd; ++I) {
+ // A tag declaration does not hide a non-tag declaration.
+ if ((*I)->getIdentifierNamespace() == Decl::IDNS_Tag &&
+ (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
+ Decl::IDNS_ObjCProtocol)))
+ continue;
+
+ // Protocols are in distinct namespaces from everything else.
+ if ((((*I)->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol)
+ || (IDNS & Decl::IDNS_ObjCProtocol)) &&
+ (*I)->getIdentifierNamespace() != IDNS)
+ continue;
+
+ // We've found a declaration that hides this one.
+ return *I;
+ }
+ }
+
+ return 0;
+}
+
+static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
+ bool QualifiedNameLookup,
+ VisibleDeclConsumer &Consumer,
+ VisibleDeclsRecord &Visited) {
+ // Make sure we don't visit the same context twice.
+ if (Visited.visitedContext(Ctx->getPrimaryContext()))
+ return;
+
+ // Enumerate all of the results in this context.
+ for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx;
+ CurCtx = CurCtx->getNextContext()) {
+ for (DeclContext::decl_iterator D = CurCtx->decls_begin(),
+ DEnd = CurCtx->decls_end();
+ D != DEnd; ++D) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
+ if (Result.isAcceptableDecl(ND)) {
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND));
+ Visited.add(ND);
+ }
+
+ // Visit transparent contexts inside this context.
+ if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) {
+ if (InnerCtx->isTransparentContext())
+ LookupVisibleDecls(InnerCtx, Result, QualifiedNameLookup,
+ Consumer, Visited);
+ }
+ }
+ }
+
+ // Traverse using directives for qualified name lookup.
+ if (QualifiedNameLookup) {
+ ShadowContextRAII Shadow(Visited);
+ DeclContext::udir_iterator I, E;
+ for (llvm::tie(I, E) = Ctx->getUsingDirectives(); I != E; ++I) {
+ LookupVisibleDecls((*I)->getNominatedNamespace(), Result,
+ QualifiedNameLookup, Consumer, Visited);
+ }
+ }
+
+ // Traverse the contexts of inherited classes.
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
+ for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(),
+ BEnd = Record->bases_end();
+ B != BEnd; ++B) {
+ QualType BaseType = B->getType();
+
+ // Don't look into dependent bases, because name lookup can't look
+ // there anyway.
+ if (BaseType->isDependentType())
+ continue;
+
+ const RecordType *Record = BaseType->getAs<RecordType>();
+ if (!Record)
+ continue;
+
+ // FIXME: It would be nice to be able to determine whether referencing
+ // a particular member would be ambiguous. For example, given
+ //
+ // struct A { int member; };
+ // struct B { int member; };
+ // struct C : A, B { };
+ //
+ // void f(C *c) { c->### }
+ //
+ // accessing 'member' would result in an ambiguity. However, we
+ // could be smart enough to qualify the member with the base
+ // class, e.g.,
+ //
+ // c->B::member
+ //
+ // or
+ //
+ // c->A::member
+
+ // Find results in this base class (and its bases).
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(Record->getDecl(), Result, QualifiedNameLookup,
+ Consumer, Visited);
+ }
+ }
+
+ // FIXME: Look into base classes in Objective-C!
+}
+
+static void LookupVisibleDecls(Scope *S, LookupResult &Result,
+ UnqualUsingDirectiveSet &UDirs,
+ VisibleDeclConsumer &Consumer,
+ VisibleDeclsRecord &Visited) {
+ if (!S)
+ return;
+
+ DeclContext *Entity = 0;
+ if (S->getEntity() &&
+ !((DeclContext *)S->getEntity())->isFunctionOrMethod()) {
+ // Look into this scope's declaration context, along with any of its
+ // parent lookup contexts (e.g., enclosing classes), up to the point
+ // where we hit the context stored in the next outer scope.
+ Entity = (DeclContext *)S->getEntity();
+ DeclContext *OuterCtx = findOuterContext(S);
+
+ for (DeclContext *Ctx = Entity; Ctx && Ctx->getPrimaryContext() != OuterCtx;
+ Ctx = Ctx->getLookupParent()) {
+ if (Ctx->isFunctionOrMethod())
+ continue;
+
+ LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false,
+ Consumer, Visited);
+ }
+ } else if (!S->getParent()) {
+ // Look into the translation unit scope. We walk through the translation
+ // unit's declaration context, because the Scope itself won't have all of
+ // the declarations if we loaded a precompiled header.
+ // FIXME: We would like the translation unit's Scope object to point to the
+ // translation unit, so we don't need this special "if" branch. However,
+ // doing so would force the normal C++ name-lookup code to look into the
+ // translation unit decl when the IdentifierInfo chains would suffice.
+ // Once we fix that problem (which is part of a more general "don't look
+ // in DeclContexts unless we have to" optimization), we can eliminate the
+ // TranslationUnit parameter entirely.
+ Entity = Result.getSema().Context.getTranslationUnitDecl();
+ LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false,
+ Consumer, Visited);
+ } else {
+ // Walk through the declarations in this Scope.
+ for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
+ D != DEnd; ++D) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>((Decl *)((*D).get())))
+ if (Result.isAcceptableDecl(ND)) {
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND));
+ Visited.add(ND);
+ }
+ }
+ }
+
+ if (Entity) {
+ // Lookup visible declarations in any namespaces found by using
+ // directives.
+ UnqualUsingDirectiveSet::const_iterator UI, UEnd;
+ llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity);
+ for (; UI != UEnd; ++UI)
+ LookupVisibleDecls(const_cast<DeclContext *>(UI->getNominatedNamespace()),
+ Result, /*QualifiedNameLookup=*/false, Consumer,
+ Visited);
+ }
+
+ // Lookup names in the parent scope.
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(S->getParent(), Result, UDirs, Consumer, Visited);
+}
+
+void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind,
+ VisibleDeclConsumer &Consumer) {
+ // Determine the set of using directives available during
+ // unqualified name lookup.
+ Scope *Initial = S;
+ UnqualUsingDirectiveSet UDirs;
+ if (getLangOptions().CPlusPlus) {
+ // Find the first namespace or translation-unit scope.
+ while (S && !isNamespaceOrTranslationUnitScope(S))
+ S = S->getParent();
+
+ UDirs.visitScopeChain(Initial, S);
+ }
+ UDirs.done();
+
+ // Look for visible declarations.
+ LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind);
+ VisibleDeclsRecord Visited;
+ ShadowContextRAII Shadow(Visited);
+ ::LookupVisibleDecls(Initial, Result, UDirs, Consumer, Visited);
+}
+
+void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
+ VisibleDeclConsumer &Consumer) {
+ LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind);
+ VisibleDeclsRecord Visited;
+ ShadowContextRAII Shadow(Visited);
+ ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, Consumer,
+ Visited);
+}
+
+//----------------------------------------------------------------------------
+// Typo correction
+//----------------------------------------------------------------------------
+
+namespace {
+class TypoCorrectionConsumer : public VisibleDeclConsumer {
+ /// \brief The name written that is a typo in the source.
+ llvm::StringRef Typo;
+
+ /// \brief The results found that have the smallest edit distance
+ /// found (so far) with the typo name.
+ llvm::SmallVector<NamedDecl *, 4> BestResults;
+
+ /// \brief The best edit distance found so far.
+ unsigned BestEditDistance;
+
+public:
+ explicit TypoCorrectionConsumer(IdentifierInfo *Typo)
+ : Typo(Typo->getName()) { }
+
+ virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding);
+
+ typedef llvm::SmallVector<NamedDecl *, 4>::const_iterator iterator;
+ iterator begin() const { return BestResults.begin(); }
+ iterator end() const { return BestResults.end(); }
+ bool empty() const { return BestResults.empty(); }
+
+ unsigned getBestEditDistance() const { return BestEditDistance; }
+};
+
+}
+
+void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding) {
+ // Don't consider hidden names for typo correction.
+ if (Hiding)
+ return;
+
+ // Only consider entities with identifiers for names, ignoring
+ // special names (constructors, overloaded operators, selectors,
+ // etc.).
+ IdentifierInfo *Name = ND->getIdentifier();
+ if (!Name)
+ return;
+
+ // Compute the edit distance between the typo and the name of this
+ // entity. If this edit distance is not worse than the best edit
+ // distance we've seen so far, add it to the list of results.
+ unsigned ED = Typo.edit_distance(Name->getName());
+ if (!BestResults.empty()) {
+ if (ED < BestEditDistance) {
+ // This result is better than any we've seen before; clear out
+ // the previous results.
+ BestResults.clear();
+ BestEditDistance = ED;
+ } else if (ED > BestEditDistance) {
+ // This result is worse than the best results we've seen so far;
+ // ignore it.
+ return;
+ }
+ } else
+ BestEditDistance = ED;
+
+ BestResults.push_back(ND);
+}
+
+/// \brief Try to "correct" a typo in the source code by finding
+/// visible declarations whose names are similar to the name that was
+/// present in the source code.
+///
+/// \param Res the \c LookupResult structure that contains the name
+/// that was present in the source code along with the name-lookup
+/// criteria used to search for the name. On success, this structure
+/// will contain the results of name lookup.
+///
+/// \param S the scope in which name lookup occurs.
+///
+/// \param SS the nested-name-specifier that precedes the name we're
+/// looking for, if present.
+///
+/// \param MemberContext if non-NULL, the context in which to look for
+/// a member access expression.
+///
+/// \param EnteringContext whether we're entering the context described by
+/// the nested-name-specifier SS.
+///
+/// \returns true if the typo was corrected, in which case the \p Res
+/// structure will contain the results of name lookup for the
+/// corrected name. Otherwise, returns false.
+bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
+ DeclContext *MemberContext, bool EnteringContext) {
+ // We only attempt to correct typos for identifiers.
+ IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo();
+ if (!Typo)
+ return false;
+
+ // If the scope specifier itself was invalid, don't try to correct
+ // typos.
+ if (SS && SS->isInvalid())
+ return false;
+
+ // Never try to correct typos during template deduction or
+ // instantiation.
+ if (!ActiveTemplateInstantiations.empty())
+ return false;
+
+ TypoCorrectionConsumer Consumer(Typo);
+ if (MemberContext)
+ LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer);
+ else if (SS && SS->isSet()) {
+ DeclContext *DC = computeDeclContext(*SS, EnteringContext);
+ if (!DC)
+ return false;
+
+ LookupVisibleDecls(DC, Res.getLookupKind(), Consumer);
+ } else {
+ LookupVisibleDecls(S, Res.getLookupKind(), Consumer);
+ }
+
+ if (Consumer.empty())
+ return false;
+
+ // Only allow a single, closest name in the result set (it's okay to
+ // have overloads of that name, though).
+ TypoCorrectionConsumer::iterator I = Consumer.begin();
+ DeclarationName BestName = (*I)->getDeclName();
+ ++I;
+ for(TypoCorrectionConsumer::iterator IEnd = Consumer.end(); I != IEnd; ++I) {
+ if (BestName != (*I)->getDeclName())
+ return false;
+ }
+
+ // BestName is the closest viable name to what the user
+ // typed. However, to make sure that we don't pick something that's
+ // way off, make sure that the user typed at least 3 characters for
+ // each correction.
+ unsigned ED = Consumer.getBestEditDistance();
+ if (ED == 0 || (BestName.getAsIdentifierInfo()->getName().size() / ED) < 3)
+ return false;
+
+ // Perform name lookup again with the name we chose, and declare
+ // success if we found something that was not ambiguous.
+ Res.clear();
+ Res.setLookupName(BestName);
+ if (MemberContext)
+ LookupQualifiedName(Res, MemberContext);
+ else
+ LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false,
+ EnteringContext);
+
+ if (Res.isAmbiguous()) {
+ Res.suppressDiagnostics();
+ return false;
+ }
+
+ return Res.getResultKind() != LookupResult::NotFound;
+}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 561cfdb..5892081 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -13,6 +13,7 @@
#include "Sema.h"
#include "Lookup.h"
+#include "SemaInit.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/AST/ASTContext.h"
@@ -88,7 +89,7 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) {
/// GetImplicitConversionName - Return the name of this kind of
/// implicit conversion.
const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
- static const char* Name[(int)ICK_Num_Conversion_Kinds] = {
+ static const char* const Name[(int)ICK_Num_Conversion_Kinds] = {
"No conversion",
"Lvalue-to-rvalue",
"Array-to-pointer",
@@ -451,7 +452,8 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
QualType FromCanon
= Context.getCanonicalType(From->getType().getUnqualifiedType());
QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType();
- if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) {
+ if (Constructor->isCopyConstructor() &&
+ (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon))) {
// Turn this into a "standard" conversion sequence, so that it
// gets ranked with standard conversion sequences.
ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
@@ -915,6 +917,25 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr,
Quals));
}
+/// BuildSimilarlyQualifiedObjCObjectPointerType - In a pointer conversion from
+/// the FromType, which is an objective-c pointer, to ToType, which may or may
+/// not have the right set of qualifiers.
+static QualType
+BuildSimilarlyQualifiedObjCObjectPointerType(QualType FromType,
+ QualType ToType,
+ ASTContext &Context) {
+ QualType CanonFromType = Context.getCanonicalType(FromType);
+ QualType CanonToType = Context.getCanonicalType(ToType);
+ Qualifiers Quals = CanonFromType.getQualifiers();
+
+ // Exact qualifier match -> return the pointer type we're converting to.
+ if (CanonToType.getLocalQualifiers() == Quals)
+ return ToType;
+
+ // Just build a canonical type that has the right qualifiers.
+ return Context.getQualifiedType(CanonToType.getLocalUnqualifiedType(), Quals);
+}
+
static bool isNullPointerConstantForConversion(Expr *Expr,
bool InOverloadResolution,
ASTContext &Context) {
@@ -992,13 +1013,20 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
return true;
}
- // Beyond this point, both types need to be pointers.
+ // Beyond this point, both types need to be pointers
+ // , including objective-c pointers.
+ QualType ToPointeeType = ToTypePtr->getPointeeType();
+ if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType()) {
+ ConvertedType = BuildSimilarlyQualifiedObjCObjectPointerType(FromType,
+ ToType, Context);
+ return true;
+
+ }
const PointerType *FromTypePtr = FromType->getAs<PointerType>();
if (!FromTypePtr)
return false;
QualType FromPointeeType = FromTypePtr->getPointeeType();
- QualType ToPointeeType = ToTypePtr->getPointeeType();
// An rvalue of type "pointer to cv T," where T is an object type,
// can be converted to an rvalue of type "pointer to cv void" (C++
@@ -1774,7 +1802,16 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
T1 = Context.getCanonicalType(T1);
T2 = Context.getCanonicalType(T2);
- if (Context.hasSameUnqualifiedType(T1, T2)) {
+ Qualifiers T1Quals, T2Quals;
+ QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
+ QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
+ if (UnqualT1 == UnqualT2) {
+ // If the type is an array type, promote the element qualifiers to the type
+ // for comparison.
+ if (isa<ArrayType>(T1) && T1Quals)
+ T1 = Context.getQualifiedType(UnqualT1, T1Quals);
+ if (isa<ArrayType>(T2) && T2Quals)
+ T2 = Context.getQualifiedType(UnqualT2, T2Quals);
if (T2.isMoreQualifiedThan(T1))
return ImplicitConversionSequence::Better;
else if (T1.isMoreQualifiedThan(T2))
@@ -1807,12 +1844,22 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
T1 = Context.getCanonicalType(T1);
T2 = Context.getCanonicalType(T2);
+ Qualifiers T1Quals, T2Quals;
+ QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
+ QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
// If the types are the same, we won't learn anything by unwrapped
// them.
- if (Context.hasSameUnqualifiedType(T1, T2))
+ if (UnqualT1 == UnqualT2)
return ImplicitConversionSequence::Indistinguishable;
+ // If the type is an array type, promote the element qualifiers to the type
+ // for comparison.
+ if (isa<ArrayType>(T1) && T1Quals)
+ T1 = Context.getQualifiedType(UnqualT1, T1Quals);
+ if (isa<ArrayType>(T2) && T2Quals)
+ T2 = Context.getQualifiedType(UnqualT2, T2Quals);
+
ImplicitConversionSequence::CompareKind Result
= ImplicitConversionSequence::Indistinguishable;
while (UnwrapSimilarPointerTypes(T1, T2)) {
@@ -2080,7 +2127,7 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType,
/// be true when the copy may be elided (C++ 12.8p15). Overload resolution works
/// differently in C++0x for this case.
bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
- const char* Flavor, bool Elidable) {
+ AssignmentAction Action, bool Elidable) {
if (!getLangOptions().CPlusPlus) {
// In C, argument passing is the same as performing an assignment.
QualType FromType = From->getType();
@@ -2092,7 +2139,7 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
ConvTy = Compatible;
return DiagnoseAssignmentResult(ConvTy, From->getLocStart(), ToType,
- FromType, From, Flavor);
+ FromType, From, Action);
}
if (ToType->isReferenceType())
@@ -2102,13 +2149,13 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
/*AllowExplicit=*/false,
/*ForceRValue=*/false);
- if (!PerformImplicitConversion(From, ToType, Flavor,
+ if (!PerformImplicitConversion(From, ToType, Action,
/*AllowExplicit=*/false, Elidable))
return false;
if (!DiagnoseMultipleUserDefinedConversion(From, ToType))
return Diag(From->getSourceRange().getBegin(),
diag::err_typecheck_convert_incompatible)
- << ToType << From->getType() << Flavor << From->getSourceRange();
+ << ToType << From->getType() << Action << From->getSourceRange();
return true;
}
@@ -2229,7 +2276,7 @@ ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) {
/// of the expression From to bool (C++0x [conv]p3).
bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
ImplicitConversionSequence ICS = TryContextuallyConvertToBool(From);
- if (!PerformImplicitConversion(From, Context.BoolTy, ICS, "converting"))
+ if (!PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting))
return false;
if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy))
@@ -2622,7 +2669,14 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
Args, NumArgs, Specialization, Info)) {
// FIXME: Record what happened with template argument deduction, so
// that we can give the user a beautiful diagnostic.
- (void)Result;
+ (void) Result;
+
+ CandidateSet.push_back(OverloadCandidate());
+ OverloadCandidate &Candidate = CandidateSet.back();
+ Candidate.Function = FunctionTemplate->getTemplatedDecl();
+ Candidate.Viable = false;
+ Candidate.IsSurrogate = false;
+ Candidate.IgnoreObjectArgument = false;
return;
}
@@ -4430,6 +4484,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
bool FoundNonTemplateFunction = false;
for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(),
E = Fns.end(); I != E; ++I) {
+ // Look through any using declarations to find the underlying function.
+ NamedDecl *Fn = (*I)->getUnderlyingDecl();
+
// C++ [over.over]p3:
// Non-member functions and static member functions match
// targets of type "pointer-to-function" or "reference-to-function."
@@ -4438,7 +4495,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// Note that according to DR 247, the containing class does not matter.
if (FunctionTemplateDecl *FunctionTemplate
- = dyn_cast<FunctionTemplateDecl>(*I)) {
+ = dyn_cast<FunctionTemplateDecl>(Fn)) {
if (CXXMethodDecl *Method
= dyn_cast<CXXMethodDecl>(FunctionTemplate->getTemplatedDecl())) {
// Skip non-static function templates when converting to pointer, and
@@ -4475,7 +4532,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
continue;
}
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*I)) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
// Skip non-static functions when converting to pointer, and static
// when converting to member pointer.
if (Method->isStatic() == IsMember)
@@ -4487,7 +4544,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
} else if (IsMember)
continue;
- if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*I)) {
+ if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(Fn)) {
QualType ResultTy;
if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) ||
IsNoReturnConversion(Context, FunDecl->getType(), FunctionType,
@@ -4558,6 +4615,93 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
return 0;
}
+/// \brief Given an expression that refers to an overloaded function, try to
+/// resolve that overloaded function expression down to a single function.
+///
+/// This routine can only resolve template-ids that refer to a single function
+/// template, where that template-id refers to a single template whose template
+/// arguments are either provided by the template-id or have defaults,
+/// as described in C++0x [temp.arg.explicit]p3.
+FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) {
+ // C++ [over.over]p1:
+ // [...] [Note: any redundant set of parentheses surrounding the
+ // overloaded function name is ignored (5.1). ]
+ Expr *OvlExpr = From->IgnoreParens();
+
+ // C++ [over.over]p1:
+ // [...] The overloaded function name can be preceded by the &
+ // operator.
+ if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(OvlExpr)) {
+ if (UnOp->getOpcode() == UnaryOperator::AddrOf)
+ OvlExpr = UnOp->getSubExpr()->IgnoreParens();
+ }
+
+ bool HasExplicitTemplateArgs = false;
+ TemplateArgumentListInfo ExplicitTemplateArgs;
+
+ llvm::SmallVector<NamedDecl*,8> Fns;
+
+ // Look into the overloaded expression.
+ if (UnresolvedLookupExpr *UL
+ = dyn_cast<UnresolvedLookupExpr>(OvlExpr)) {
+ Fns.append(UL->decls_begin(), UL->decls_end());
+ if (UL->hasExplicitTemplateArgs()) {
+ HasExplicitTemplateArgs = true;
+ UL->copyTemplateArgumentsInto(ExplicitTemplateArgs);
+ }
+ } else if (UnresolvedMemberExpr *ME
+ = dyn_cast<UnresolvedMemberExpr>(OvlExpr)) {
+ Fns.append(ME->decls_begin(), ME->decls_end());
+ if (ME->hasExplicitTemplateArgs()) {
+ HasExplicitTemplateArgs = true;
+ ME->copyTemplateArgumentsInto(ExplicitTemplateArgs);
+ }
+ }
+
+ // If we didn't actually find any template-ids, we're done.
+ if (Fns.empty() || !HasExplicitTemplateArgs)
+ return 0;
+
+ // Look through all of the overloaded functions, searching for one
+ // whose type matches exactly.
+ FunctionDecl *Matched = 0;
+ for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(),
+ E = Fns.end(); I != E; ++I) {
+ // C++0x [temp.arg.explicit]p3:
+ // [...] In contexts where deduction is done and fails, or in contexts
+ // where deduction is not done, if a template argument list is
+ // specified and it, along with any default template arguments,
+ // identifies a single function template specialization, then the
+ // template-id is an lvalue for the function template specialization.
+ FunctionTemplateDecl *FunctionTemplate = cast<FunctionTemplateDecl>(*I);
+
+ // C++ [over.over]p2:
+ // If the name is a function template, template argument deduction is
+ // done (14.8.2.2), and if the argument deduction succeeds, the
+ // resulting template argument list is used to generate a single
+ // function template specialization, which is added to the set of
+ // overloaded functions considered.
+ // FIXME: We don't really want to build the specialization here, do we?
+ FunctionDecl *Specialization = 0;
+ TemplateDeductionInfo Info(Context);
+ if (TemplateDeductionResult Result
+ = DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs,
+ Specialization, Info)) {
+ // FIXME: make a note of the failed deduction for diagnostics.
+ (void)Result;
+ continue;
+ }
+
+ // Multiple matches; we can't resolve to a single declaration.
+ if (Matched)
+ return 0;
+
+ Matched = Specialization;
+ }
+
+ return Matched;
+}
+
/// \brief Add a single candidate to the overload set.
static void AddOverloadedCallCandidate(Sema &S,
NamedDecl *Callee,
@@ -4589,10 +4733,7 @@ static void AddOverloadedCallCandidate(Sema &S,
/// \brief Add the overload candidates named by callee and/or found by argument
/// dependent lookup to the given overload set.
-void Sema::AddOverloadedCallCandidates(llvm::SmallVectorImpl<NamedDecl*> &Fns,
- DeclarationName &UnqualifiedName,
- bool ArgumentDependentLookup,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading) {
@@ -4615,28 +4756,99 @@ void Sema::AddOverloadedCallCandidates(llvm::SmallVectorImpl<NamedDecl*> &Fns,
//
// then Y is empty.
- if (ArgumentDependentLookup) {
- for (unsigned I = 0; I < Fns.size(); ++I) {
- assert(!Fns[I]->getDeclContext()->isRecord());
- assert(isa<UsingShadowDecl>(Fns[I]) ||
- !Fns[I]->getDeclContext()->isFunctionOrMethod());
- assert(Fns[I]->getUnderlyingDecl()->isFunctionOrFunctionTemplate());
+ if (ULE->requiresADL()) {
+ for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(),
+ E = ULE->decls_end(); I != E; ++I) {
+ assert(!(*I)->getDeclContext()->isRecord());
+ assert(isa<UsingShadowDecl>(*I) ||
+ !(*I)->getDeclContext()->isFunctionOrMethod());
+ assert((*I)->getUnderlyingDecl()->isFunctionOrFunctionTemplate());
}
}
#endif
- for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(),
- E = Fns.end(); I != E; ++I)
+ // It would be nice to avoid this copy.
+ TemplateArgumentListInfo TABuffer;
+ const TemplateArgumentListInfo *ExplicitTemplateArgs = 0;
+ if (ULE->hasExplicitTemplateArgs()) {
+ ULE->copyTemplateArgumentsInto(TABuffer);
+ ExplicitTemplateArgs = &TABuffer;
+ }
+
+ for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(),
+ E = ULE->decls_end(); I != E; ++I)
AddOverloadedCallCandidate(*this, *I, ExplicitTemplateArgs,
Args, NumArgs, CandidateSet,
PartialOverloading);
- if (ArgumentDependentLookup)
- AddArgumentDependentLookupCandidates(UnqualifiedName, Args, NumArgs,
+ if (ULE->requiresADL())
+ AddArgumentDependentLookupCandidates(ULE->getName(), Args, NumArgs,
ExplicitTemplateArgs,
CandidateSet,
PartialOverloading);
}
+
+static Sema::OwningExprResult Destroy(Sema &SemaRef, Expr *Fn,
+ Expr **Args, unsigned NumArgs) {
+ Fn->Destroy(SemaRef.Context);
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
+ Args[Arg]->Destroy(SemaRef.Context);
+ return SemaRef.ExprError();
+}
+
+/// Attempts to recover from a call where no functions were found.
+///
+/// Returns true if new candidates were found.
+static Sema::OwningExprResult
+BuildRecoveryCallExpr(Sema &SemaRef, Expr *Fn,
+ UnresolvedLookupExpr *ULE,
+ SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+
+ CXXScopeSpec SS;
+ if (ULE->getQualifier()) {
+ SS.setScopeRep(ULE->getQualifier());
+ SS.setRange(ULE->getQualifierRange());
+ }
+
+ TemplateArgumentListInfo TABuffer;
+ const TemplateArgumentListInfo *ExplicitTemplateArgs = 0;
+ if (ULE->hasExplicitTemplateArgs()) {
+ ULE->copyTemplateArgumentsInto(TABuffer);
+ ExplicitTemplateArgs = &TABuffer;
+ }
+
+ LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
+ Sema::LookupOrdinaryName);
+ if (SemaRef.DiagnoseEmptyLookup(/*Scope=*/0, SS, R))
+ return Destroy(SemaRef, Fn, Args, NumArgs);
+
+ assert(!R.empty() && "lookup results empty despite recovery");
+
+ // Build an implicit member call if appropriate. Just drop the
+ // casts and such from the call, we don't really care.
+ Sema::OwningExprResult NewFn = SemaRef.ExprError();
+ if ((*R.begin())->isCXXClassMember())
+ NewFn = SemaRef.BuildPossibleImplicitMemberExpr(SS, R, ExplicitTemplateArgs);
+ else if (ExplicitTemplateArgs)
+ NewFn = SemaRef.BuildTemplateIdExpr(SS, R, false, *ExplicitTemplateArgs);
+ else
+ NewFn = SemaRef.BuildDeclarationNameExpr(SS, R, false);
+
+ if (NewFn.isInvalid())
+ return Destroy(SemaRef, Fn, Args, NumArgs);
+
+ Fn->Destroy(SemaRef.Context);
+
+ // This shouldn't cause an infinite loop because we're giving it
+ // an expression with non-empty lookup results, which should never
+ // end up here.
+ return SemaRef.ActOnCallExpr(/*Scope*/ 0, move(NewFn), LParenLoc,
+ Sema::MultiExprArg(SemaRef, (void**) Args, NumArgs),
+ CommaLocs, RParenLoc);
+}
/// ResolveOverloadedCallFn - Given the call expression that calls Fn
/// (which eventually refers to the declaration Func) and the call
@@ -4645,44 +4857,68 @@ void Sema::AddOverloadedCallCandidates(llvm::SmallVectorImpl<NamedDecl*> &Fns,
/// the function declaration produced by overload
/// resolution. Otherwise, emits diagnostics, deletes all of the
/// arguments and Fn, and returns NULL.
-FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn,
- llvm::SmallVectorImpl<NamedDecl*> &Fns,
- DeclarationName UnqualifiedName,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
- SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
- SourceLocation *CommaLocs,
- SourceLocation RParenLoc,
- bool ArgumentDependentLookup) {
+Sema::OwningExprResult
+Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
+ SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+#ifndef NDEBUG
+ if (ULE->requiresADL()) {
+ // To do ADL, we must have found an unqualified name.
+ assert(!ULE->getQualifier() && "qualified name with ADL");
+
+ // We don't perform ADL for implicit declarations of builtins.
+ // Verify that this was correctly set up.
+ FunctionDecl *F;
+ if (ULE->decls_begin() + 1 == ULE->decls_end() &&
+ (F = dyn_cast<FunctionDecl>(*ULE->decls_begin())) &&
+ F->getBuiltinID() && F->isImplicit())
+ assert(0 && "performing ADL for builtin");
+
+ // We don't perform ADL in C.
+ assert(getLangOptions().CPlusPlus && "ADL enabled in C");
+ }
+#endif
+
OverloadCandidateSet CandidateSet;
- // Add the functions denoted by Callee to the set of candidate
- // functions.
- AddOverloadedCallCandidates(Fns, UnqualifiedName, ArgumentDependentLookup,
- ExplicitTemplateArgs, Args, NumArgs,
- CandidateSet);
+ // Add the functions denoted by the callee to the set of candidate
+ // functions, including those from argument-dependent lookup.
+ 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.
+ if (CandidateSet.empty())
+ return BuildRecoveryCallExpr(*this, Fn, ULE, LParenLoc, Args, NumArgs,
+ CommaLocs, RParenLoc);
+
OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) {
- case OR_Success:
- return Best->Function;
+ case OR_Success: {
+ FunctionDecl *FDecl = Best->Function;
+ Fn = FixOverloadedFunctionReference(Fn, FDecl);
+ return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc);
+ }
case OR_No_Viable_Function:
Diag(Fn->getSourceRange().getBegin(),
diag::err_ovl_no_viable_function_in_call)
- << UnqualifiedName << Fn->getSourceRange();
+ << ULE->getName() << Fn->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
break;
case OR_Ambiguous:
Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call)
- << UnqualifiedName << Fn->getSourceRange();
+ << ULE->getName() << Fn->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
break;
case OR_Deleted:
Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_deleted_call)
<< Best->Function->isDeleted()
- << UnqualifiedName
+ << ULE->getName()
<< Fn->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
break;
@@ -4693,7 +4929,7 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn,
Fn->Destroy(Context);
for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
Args[Arg]->Destroy(Context);
- return 0;
+ return ExprError();
}
static bool IsOverloaded(const Sema::FunctionSet &Functions) {
@@ -4787,10 +5023,16 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
return ExprError();
} else {
// Convert the arguments.
- if (PerformCopyInitialization(Input,
- FnDecl->getParamDecl(0)->getType(),
- "passing"))
+ OwningExprResult InputInit
+ = PerformCopyInitialization(InitializedEntity::InitializeParameter(
+ FnDecl->getParamDecl(0)),
+ SourceLocation(),
+ move(input));
+ if (InputInit.isInvalid())
return ExprError();
+
+ input = move(InputInit);
+ Input = (Expr *)input.get();
}
// Determine the result type
@@ -4817,7 +5059,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
// break out so that we will build the appropriate built-in
// operator node.
if (PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], "passing"))
+ Best->Conversions[0], AA_Passing))
return ExprError();
break;
@@ -4954,17 +5196,40 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
- if (PerformObjectArgumentInitialization(Args[0], Method) ||
- PerformCopyInitialization(Args[1], FnDecl->getParamDecl(0)->getType(),
- "passing"))
+ OwningExprResult Arg1
+ = PerformCopyInitialization(
+ InitializedEntity::InitializeParameter(
+ FnDecl->getParamDecl(0)),
+ SourceLocation(),
+ Owned(Args[1]));
+ if (Arg1.isInvalid())
+ return ExprError();
+
+ if (PerformObjectArgumentInitialization(Args[0], Method))
return ExprError();
+
+ Args[1] = RHS = Arg1.takeAs<Expr>();
} else {
// Convert the arguments.
- if (PerformCopyInitialization(Args[0], FnDecl->getParamDecl(0)->getType(),
- "passing") ||
- PerformCopyInitialization(Args[1], FnDecl->getParamDecl(1)->getType(),
- "passing"))
+ OwningExprResult Arg0
+ = PerformCopyInitialization(
+ InitializedEntity::InitializeParameter(
+ FnDecl->getParamDecl(0)),
+ SourceLocation(),
+ Owned(Args[0]));
+ if (Arg0.isInvalid())
+ return ExprError();
+
+ OwningExprResult Arg1
+ = PerformCopyInitialization(
+ InitializedEntity::InitializeParameter(
+ FnDecl->getParamDecl(1)),
+ SourceLocation(),
+ Owned(Args[1]));
+ if (Arg1.isInvalid())
return ExprError();
+ Args[0] = LHS = Arg0.takeAs<Expr>();
+ Args[1] = RHS = Arg1.takeAs<Expr>();
}
// Determine the result type
@@ -4992,9 +5257,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// break out so that we will build the appropriate built-in
// operator node.
if (PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], "passing") ||
+ Best->Conversions[0], AA_Passing) ||
PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1],
- Best->Conversions[1], "passing"))
+ Best->Conversions[1], AA_Passing))
return ExprError();
break;
@@ -5106,7 +5371,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
if (PerformObjectArgumentInitialization(Args[0], Method) ||
PerformCopyInitialization(Args[1],
FnDecl->getParamDecl(0)->getType(),
- "passing"))
+ AA_Passing))
return ExprError();
// Determine the result type
@@ -5136,9 +5401,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// break out so that we will build the appropriate built-in
// operator node.
if (PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], "passing") ||
+ Best->Conversions[0], AA_Passing) ||
PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1],
- Best->Conversions[1], "passing"))
+ Best->Conversions[1], AA_Passing))
return ExprError();
break;
@@ -5522,7 +5787,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// Pass the argument.
QualType ProtoArgType = Proto->getArgType(i);
- IsError |= PerformCopyInitialization(Arg, ProtoArgType, "passing");
+ IsError |= PerformCopyInitialization(Arg, ProtoArgType, AA_Passing);
} else {
OwningExprResult DefArg
= BuildCXXDefaultArgExpr(LParenLoc, Method, Method->getParamDecl(i));
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index de67a5f..b8928c3 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "SemaInit.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -95,7 +96,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
// If the callee has attribute pure, const, or warn_unused_result, warn with
// a more specific message to make it clear what is happening.
- if (const FunctionDecl *FD = CE->getDirectCallee()) {
+ if (const Decl *FD = CE->getCalleeDecl()) {
if (FD->getAttr<WarnUnusedResultAttr>()) {
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result";
return;
@@ -902,7 +903,7 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc,
AssignConvertType ConvTy =
CheckSingleAssignmentConstraints(Context.VoidPtrTy, E);
if (DiagnoseAssignmentResult(ConvTy, StarLoc, Context.VoidPtrTy, ETy,
- E, "passing"))
+ E, AA_Passing))
return StmtError();
}
return Owned(new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E));
@@ -977,7 +978,6 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
// we have a non-void block with an expression, continue checking
- QualType RetValType = RetValExp->getType();
// C99 6.8.6.4p3(136): The return statement is not an assignment. The
// overlap restriction of subclause 6.5.16.1 does not apply to the case of
@@ -986,7 +986,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// In C++ the return statement is handled via a copy initialization.
// the C version of which boils down to CheckSingleAssignmentConstraints.
// FIXME: Leaks RetValExp.
- if (PerformCopyInitialization(RetValExp, FnRetType, "returning"))
+ if (PerformCopyInitialization(RetValExp, FnRetType, AA_Returning))
return StmtError();
if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
@@ -1053,7 +1053,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
<< RetValExp->getSourceRange();
}
- RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true);
+ RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp);
}
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
}
@@ -1092,21 +1092,28 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
bool Elidable = getLangOptions().CPlusPlus0x ?
IsReturnCopyElidable(Context, FnRetType, RetValExp) :
false;
+ // FIXME: Elidable
+ (void)Elidable;
// In C++ the return statement is handled via a copy initialization.
// the C version of which boils down to CheckSingleAssignmentConstraints.
- // FIXME: Leaks RetValExp on error.
- if (PerformCopyInitialization(RetValExp, FnRetType, "returning", Elidable)){
- // We should still clean up our temporaries, even when we're failing!
- RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true);
+ OwningExprResult Res = PerformCopyInitialization(
+ InitializedEntity::InitializeResult(ReturnLoc,
+ FnRetType),
+ SourceLocation(),
+ Owned(RetValExp));
+ if (Res.isInvalid()) {
+ // FIXME: Cleanup temporaries here, anyway?
return StmtError();
}
-
- if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+
+ RetValExp = Res.takeAs<Expr>();
+ if (RetValExp)
+ CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
}
if (RetValExp)
- RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true);
+ RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp);
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index ac1b1ec..8c6aa6a 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -102,7 +102,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
- LookupResult R(*this, TName, SourceLocation(), LookupOrdinaryName);
+ LookupResult R(*this, TName, Name.getSourceRange().getBegin(),
+ LookupOrdinaryName);
R.suppressDiagnostics();
LookupTemplateName(R, S, SS, ObjectType, EnteringContext);
if (R.empty())
@@ -202,6 +203,29 @@ void Sema::LookupTemplateName(LookupResult &Found,
assert(!Found.isAmbiguous() &&
"Cannot handle template name-lookup ambiguities");
+ if (Found.empty()) {
+ // If we did not find any names, attempt to correct any typos.
+ DeclarationName Name = Found.getLookupName();
+ if (CorrectTypo(Found, S, &SS, LookupCtx)) {
+ FilterAcceptableTemplateNames(Context, Found);
+ if (!Found.empty() && isa<TemplateDecl>(*Found.begin())) {
+ if (LookupCtx)
+ Diag(Found.getNameLoc(), diag::err_no_member_template_suggest)
+ << Name << LookupCtx << Found.getLookupName() << SS.getRange()
+ << CodeModificationHint::CreateReplacement(Found.getNameLoc(),
+ Found.getLookupName().getAsString());
+ else
+ Diag(Found.getNameLoc(), diag::err_no_template_suggest)
+ << Name << Found.getLookupName()
+ << CodeModificationHint::CreateReplacement(Found.getNameLoc(),
+ Found.getLookupName().getAsString());
+ } else
+ Found.clear();
+ } else {
+ Found.clear();
+ }
+ }
+
FilterAcceptableTemplateNames(Context, Found);
if (Found.empty())
return;
@@ -691,7 +715,27 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (Previous.begin() != Previous.end())
PrevDecl = *Previous.begin();
- if (PrevDecl && TUK == TUK_Friend) {
+ // If there is a previous declaration with the same name, check
+ // whether this is a valid redeclaration.
+ ClassTemplateDecl *PrevClassTemplate
+ = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl);
+
+ // We may have found the injected-class-name of a class template,
+ // class template partial specialization, or class template specialization.
+ // In these cases, grab the template that is being defined or specialized.
+ if (!PrevClassTemplate && PrevDecl && isa<CXXRecordDecl>(PrevDecl) &&
+ cast<CXXRecordDecl>(PrevDecl)->isInjectedClassName()) {
+ PrevDecl = cast<CXXRecordDecl>(PrevDecl->getDeclContext());
+ PrevClassTemplate
+ = cast<CXXRecordDecl>(PrevDecl)->getDescribedClassTemplate();
+ if (!PrevClassTemplate && isa<ClassTemplateSpecializationDecl>(PrevDecl)) {
+ PrevClassTemplate
+ = cast<ClassTemplateSpecializationDecl>(PrevDecl)
+ ->getSpecializedTemplate();
+ }
+ }
+
+ if (TUK == TUK_Friend) {
// C++ [namespace.memdef]p3:
// [...] When looking for a prior declaration of a class or a function
// declared as a friend, and when the name of the friend class or
@@ -700,15 +744,16 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
DeclContext *OutermostContext = CurContext;
while (!OutermostContext->isFileContext())
OutermostContext = OutermostContext->getLookupParent();
-
- if (OutermostContext->Equals(PrevDecl->getDeclContext()) ||
- OutermostContext->Encloses(PrevDecl->getDeclContext())) {
+
+ if (PrevDecl &&
+ (OutermostContext->Equals(PrevDecl->getDeclContext()) ||
+ OutermostContext->Encloses(PrevDecl->getDeclContext()))) {
SemanticContext = PrevDecl->getDeclContext();
} else {
// Declarations in outer scopes don't matter. However, the outermost
// context we computed is the semantic context for our new
// declaration.
- PrevDecl = 0;
+ PrevDecl = PrevClassTemplate = 0;
SemanticContext = OutermostContext;
}
@@ -717,30 +762,10 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// class template to the template in scope, because that would perform
// checking of the template parameter lists that can't be performed
// until the outer context is instantiated.
- PrevDecl = 0;
+ PrevDecl = PrevClassTemplate = 0;
}
} else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S))
- PrevDecl = 0;
-
- // If there is a previous declaration with the same name, check
- // whether this is a valid redeclaration.
- ClassTemplateDecl *PrevClassTemplate
- = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl);
-
- // We may have found the injected-class-name of a class template,
- // class template partial specialization, or class template specialization.
- // In these cases, grab the template that is being defined or specialized.
- if (!PrevClassTemplate && PrevDecl && isa<CXXRecordDecl>(PrevDecl) &&
- cast<CXXRecordDecl>(PrevDecl)->isInjectedClassName()) {
- PrevDecl = cast<CXXRecordDecl>(PrevDecl->getDeclContext());
- PrevClassTemplate
- = cast<CXXRecordDecl>(PrevDecl)->getDescribedClassTemplate();
- if (!PrevClassTemplate && isa<ClassTemplateSpecializationDecl>(PrevDecl)) {
- PrevClassTemplate
- = cast<ClassTemplateSpecializationDecl>(PrevDecl)
- ->getSpecializedTemplate();
- }
- }
+ PrevDecl = PrevClassTemplate = 0;
if (PrevClassTemplate) {
// Ensure that the template parameter lists are compatible.
@@ -2188,6 +2213,9 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
Diag(SR.getBegin(), diag::err_template_arg_unnamed_type) << SR;
Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here);
return true;
+ } else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) {
+ SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange();
+ return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR;
}
return false;
@@ -2484,7 +2512,14 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// Check that we don't overflow the template parameter type.
unsigned AllowedBits = Context.getTypeSize(IntegerType);
- if (Value.getActiveBits() > AllowedBits) {
+ unsigned RequiredBits;
+ if (IntegerType->isUnsignedIntegerType())
+ RequiredBits = Value.getActiveBits();
+ else if (Value.isUnsigned())
+ RequiredBits = Value.getActiveBits() + 1;
+ else
+ RequiredBits = Value.getMinSignedBits();
+ if (RequiredBits > AllowedBits) {
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_too_large)
<< Value.toString(10) << Param->getType()
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index b4754db..21f7996 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -337,58 +337,6 @@ DeduceTemplateArguments(ASTContext &Context,
return Sema::TDK_Success;
}
-/// \brief Returns a completely-unqualified array type, capturing the
-/// qualifiers in Quals.
-///
-/// \param Context the AST context in which the array type was built.
-///
-/// \param T a canonical type that may be an array type.
-///
-/// \param Quals will receive the full set of qualifiers that were
-/// applied to the element type of the array.
-///
-/// \returns if \p T is an array type, the completely unqualified array type
-/// that corresponds to T. Otherwise, returns T.
-static QualType getUnqualifiedArrayType(ASTContext &Context, QualType T,
- Qualifiers &Quals) {
- assert(T.isCanonical() && "Only operates on canonical types");
- if (!isa<ArrayType>(T)) {
- Quals = T.getLocalQualifiers();
- return T.getLocalUnqualifiedType();
- }
-
- assert(!T.hasQualifiers() && "canonical array type has qualifiers!");
-
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) {
- QualType Elt = getUnqualifiedArrayType(Context, CAT->getElementType(),
- Quals);
- if (Elt == CAT->getElementType())
- return T;
-
- return Context.getConstantArrayType(Elt, CAT->getSize(),
- CAT->getSizeModifier(), 0);
- }
-
- if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(T)) {
- QualType Elt = getUnqualifiedArrayType(Context, IAT->getElementType(),
- Quals);
- if (Elt == IAT->getElementType())
- return T;
-
- return Context.getIncompleteArrayType(Elt, IAT->getSizeModifier(), 0);
- }
-
- const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(T);
- QualType Elt = getUnqualifiedArrayType(Context, DSAT->getElementType(),
- Quals);
- if (Elt == DSAT->getElementType())
- return T;
-
- return Context.getDependentSizedArrayType(Elt, DSAT->getSizeExpr()->Retain(),
- DSAT->getSizeModifier(), 0,
- SourceRange());
-}
-
/// \brief Deduce the template arguments by comparing the parameter type and
/// the argument type (C++ [temp.deduct.type]).
///
@@ -427,9 +375,11 @@ DeduceTemplateArguments(ASTContext &Context,
// referred to by the reference) can be more cv-qualified than the
// transformed A.
if (TDF & TDF_ParamWithReferenceType) {
- Qualifiers Quals = Param.getQualifiers();
- Quals.setCVRQualifiers(Quals.getCVRQualifiers() & Arg.getCVRQualifiers());
- Param = Context.getQualifiedType(Param.getUnqualifiedType(), Quals);
+ Qualifiers Quals;
+ QualType UnqualParam = Context.getUnqualifiedArrayType(Param, Quals);
+ Quals.setCVRQualifiers(Quals.getCVRQualifiers() &
+ Arg.getCVRQualifiersThroughArrayTypes());
+ Param = Context.getQualifiedType(UnqualParam, Quals);
}
// If the parameter type is not dependent, there is nothing to deduce.
@@ -459,7 +409,7 @@ DeduceTemplateArguments(ASTContext &Context,
// FIXME: address spaces, ObjC GC qualifiers
if (isa<ArrayType>(Arg)) {
Qualifiers Quals;
- Arg = getUnqualifiedArrayType(Context, Arg, Quals);
+ Arg = Context.getUnqualifiedArrayType(Arg, Quals);
if (Quals) {
Arg = Context.getQualifiedType(Arg, Quals);
RecanonicalizeArg = true;
@@ -476,7 +426,7 @@ DeduceTemplateArguments(ASTContext &Context,
}
assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0");
-
+ assert(Arg != Context.OverloadTy && "Unresolved overloaded function");
QualType DeducedType = Arg;
DeducedType.removeCVRQualifiers(Param.getCVRQualifiers());
if (RecanonicalizeArg)
@@ -1506,15 +1456,39 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
ParamType->getAs<PointerType>()->getPointeeType())))
TDF |= TDF_DerivedClass;
+ // FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function
+ // pointer parameters.
+
+ if (Context.hasSameUnqualifiedType(ArgType, Context.OverloadTy)) {
+ // We know that template argument deduction will fail if the argument is
+ // still an overloaded function. Check whether we can resolve this
+ // argument as a single function template specialization per
+ // C++ [temp.arg.explicit]p3.
+ FunctionDecl *ExplicitSpec
+ = ResolveSingleFunctionTemplateSpecialization(Args[I]);
+ Expr *ResolvedArg = 0;
+ if (ExplicitSpec)
+ ResolvedArg = FixOverloadedFunctionReference(Args[I], ExplicitSpec);
+ if (!ExplicitSpec || !ResolvedArg) {
+ // Template argument deduction fails if we can't resolve the overloaded
+ // function.
+ return TDK_FailedOverloadResolution;
+ }
+
+ // Get the type of the resolved argument.
+ ArgType = ResolvedArg->getType();
+ if (ArgType->isPointerType() || ArgType->isMemberPointerType())
+ TDF |= TDF_IgnoreQualifiers;
+
+ ResolvedArg->Destroy(Context);
+ }
+
if (TemplateDeductionResult Result
= ::DeduceTemplateArguments(Context, TemplateParams,
ParamType, ArgType, Info, Deduced,
TDF))
return Result;
- // FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function
- // pointer parameters.
-
// FIXME: we need to check that the deduced A is the same as A,
// modulo the various allowed differences.
}
@@ -1524,24 +1498,19 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
}
/// \brief Deduce template arguments when taking the address of a function
-/// template (C++ [temp.deduct.funcaddr]) or matching a
+/// template (C++ [temp.deduct.funcaddr]) or matching a specialization to
+/// a template.
///
/// \param FunctionTemplate the function template for which we are performing
/// template argument deduction.
///
-/// \param HasExplicitTemplateArgs whether any template arguments were
-/// explicitly specified.
-///
-/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
-/// the explicitly-specified template arguments.
-///
-/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
-/// the number of explicitly-specified template arguments in
-/// @p ExplicitTemplateArguments. This value may be zero.
+/// \param ExplicitTemplateArguments the explicitly-specified template
+/// arguments.
///
/// \param ArgFunctionType the function type that will be used as the
/// "argument" type (A) when performing template argument deduction from the
-/// function template's function type.
+/// function template's function type. This type may be NULL, if there is no
+/// argument type to compare against, in C++0x [temp.arg.explicit]p3.
///
/// \param Specialization if template argument deduction was successful,
/// this will be set to the function template specialization produced by
@@ -1578,14 +1547,16 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// Trap any errors that might occur.
SFINAETrap Trap(*this);
- // Deduce template arguments from the function type.
- Deduced.resize(TemplateParams->size());
- if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(Context, TemplateParams,
- FunctionType, ArgFunctionType, Info,
- Deduced, 0))
- return Result;
-
+ if (!ArgFunctionType.isNull()) {
+ // Deduce template arguments from the function type.
+ Deduced.resize(TemplateParams->size());
+ if (TemplateDeductionResult Result
+ = ::DeduceTemplateArguments(Context, TemplateParams,
+ FunctionType, ArgFunctionType, Info,
+ Deduced, 0))
+ return Result;
+ }
+
return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
Specialization, Info);
}
@@ -1694,6 +1665,32 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
return Result;
}
+/// \brief Deduce template arguments for a function template when there is
+/// nothing to deduce against (C++0x [temp.arg.explicit]p3).
+///
+/// \param FunctionTemplate the function template for which we are performing
+/// template argument deduction.
+///
+/// \param ExplicitTemplateArguments the explicitly-specified template
+/// arguments.
+///
+/// \param Specialization if template argument deduction was successful,
+/// this will be set to the function template specialization produced by
+/// template argument deduction.
+///
+/// \param Info the argument will be updated to provide additional information
+/// about template argument deduction.
+///
+/// \returns the result of template argument deduction.
+Sema::TemplateDeductionResult
+Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ FunctionDecl *&Specialization,
+ TemplateDeductionInfo &Info) {
+ return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
+ QualType(), Specialization, Info);
+}
+
/// \brief Stores the result of comparing the qualifiers of two types.
enum DeductionQualifierComparison {
NeitherMoreQualified = 0,
@@ -2354,7 +2351,6 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
// None of these types have any template parameters in them.
case Type::Builtin:
- case Type::FixedWidthInt:
case Type::VariableArray:
case Type::FunctionNoProto:
case Type::Record:
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index dddb93c8..d974f89 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -554,7 +554,6 @@ namespace {
Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E);
Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E);
-
Sema::OwningExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E);
/// \brief Transforms a template type parameter type by performing
@@ -785,7 +784,9 @@ Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr(
assert(!cast<FunctionDecl>(E->getParam()->getDeclContext())->
getDescribedFunctionTemplate() &&
"Default arg expressions are never formed in dependent cases.");
- return SemaRef.Owned(E->Retain());
+ return SemaRef.BuildCXXDefaultArgExpr(E->getUsedLocation(),
+ cast<FunctionDecl>(E->getParam()->getDeclContext()),
+ E->getParam());
}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 8d74bd7..e909c4f 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -145,6 +145,11 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
if (Invalid)
Typedef->setInvalidDecl();
+ if (TypedefDecl *Prev = D->getPreviousDeclaration()) {
+ NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(Prev, TemplateArgs);
+ Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev));
+ }
+
Owner->addDecl(Typedef);
return Typedef;
@@ -396,7 +401,16 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
// FIXME: We have a problem here, because the nested call to Visit(ND)
// will inject the thing that the friend references into the current
// owner, which is wrong.
- Decl *NewND = Visit(ND);
+ Decl *NewND;
+
+ // Hack to make this work almost well pending a rewrite.
+ if (ND->getDeclContext()->isRecord())
+ NewND = SemaRef.FindInstantiatedDecl(ND, TemplateArgs);
+ else if (D->wasSpecialization()) {
+ // Totally egregious hack to work around PR5866
+ return 0;
+ } else
+ NewND = Visit(ND);
if (!NewND) return 0;
FU = cast<NamedDecl>(NewND);
@@ -645,6 +659,12 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
CXXRecordDecl *PrevDecl = 0;
if (D->isInjectedClassName())
PrevDecl = cast<CXXRecordDecl>(Owner);
+ else if (D->getPreviousDeclaration()) {
+ NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getPreviousDeclaration(),
+ TemplateArgs);
+ if (!Prev) return 0;
+ PrevDecl = cast<CXXRecordDecl>(Prev);
+ }
CXXRecordDecl *Record
= CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner,
@@ -675,7 +695,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
/// 1) instantiating function templates
/// 2) substituting friend declarations
/// FIXME: preserve function definitions in case #2
- Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
+Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
TemplateParameterList *TemplateParams) {
// Check whether there is already a function template specialization for
// this declaration.
@@ -1149,6 +1169,8 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
if (NewUD->isInvalidDecl())
return NewUD;
+ bool isFunctionScope = Owner->isFunctionOrMethod();
+
// Process the shadow decls.
for (UsingDecl::shadow_iterator I = D->shadow_begin(), E = D->shadow_end();
I != E; ++I) {
@@ -1164,6 +1186,9 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
UsingShadowDecl *InstShadow
= SemaRef.BuildUsingShadowDecl(/*Scope*/ 0, NewUD, InstTarget);
SemaRef.Context.setInstantiatedFromUsingShadowDecl(InstShadow, Shadow);
+
+ if (isFunctionScope)
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(Shadow, InstShadow);
}
return NewUD;
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 37f19f2..ed30229 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -308,7 +308,11 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){
Expr *E = static_cast<Expr *>(DS.getTypeRep());
assert(E && "Didn't get an expression for typeof?");
// TypeQuals handled by caller.
- Result = Context.getTypeOfExprType(E);
+ Result = TheSema.BuildTypeofExprType(E);
+ if (Result.isNull()) {
+ Result = Context.IntTy;
+ TheDeclarator.setInvalidType(true);
+ }
break;
}
case DeclSpec::TST_decltype: {
@@ -1826,14 +1830,41 @@ QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) {
}
QualType Sema::BuildTypeofExprType(Expr *E) {
+ if (E->getType() == Context.OverloadTy) {
+ // C++ [temp.arg.explicit]p3 allows us to resolve a template-id to a
+ // function template specialization wherever deduction cannot occur.
+ if (FunctionDecl *Specialization
+ = ResolveSingleFunctionTemplateSpecialization(E)) {
+ E = FixOverloadedFunctionReference(E, Specialization);
+ if (!E)
+ return QualType();
+ } else {
+ Diag(E->getLocStart(),
+ diag::err_cannot_determine_declared_type_of_overloaded_function)
+ << false << E->getSourceRange();
+ return QualType();
+ }
+ }
+
return Context.getTypeOfExprType(E);
}
QualType Sema::BuildDecltypeType(Expr *E) {
if (E->getType() == Context.OverloadTy) {
- Diag(E->getLocStart(),
- diag::err_cannot_determine_declared_type_of_overloaded_function);
- return QualType();
+ // C++ [temp.arg.explicit]p3 allows us to resolve a template-id to a
+ // function template specialization wherever deduction cannot occur.
+ if (FunctionDecl *Specialization
+ = ResolveSingleFunctionTemplateSpecialization(E)) {
+ E = FixOverloadedFunctionReference(E, Specialization);
+ if (!E)
+ return QualType();
+ } else {
+ Diag(E->getLocStart(),
+ diag::err_cannot_determine_declared_type_of_overloaded_function)
+ << true << E->getSourceRange();
+ return QualType();
+ }
}
+
return Context.getDecltypeType(E);
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index fd19987..208c885 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -956,8 +956,12 @@ public:
// We have a reference to an unnamed field.
assert(!Qualifier && "Can't have an unnamed field with a qualifier!");
+ Expr *BaseExpr = Base.takeAs<Expr>();
+ if (getSema().PerformObjectMemberConversion(BaseExpr, Member))
+ return getSema().ExprError();
+
MemberExpr *ME =
- new (getSema().Context) MemberExpr(Base.takeAs<Expr>(), isArrow,
+ new (getSema().Context) MemberExpr(BaseExpr, isArrow,
Member, MemberLoc,
cast<FieldDecl>(Member)->getType());
return getSema().Owned(ME);
@@ -1358,8 +1362,10 @@ public:
/// By default, builds a new default-argument expression, which does not
/// require any semantic analysis. Subclasses may override this routine to
/// provide different behavior.
- OwningExprResult RebuildCXXDefaultArgExpr(ParmVarDecl *Param) {
- return getSema().Owned(CXXDefaultArgExpr::Create(getSema().Context, Param));
+ OwningExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc,
+ ParmVarDecl *Param) {
+ return getSema().Owned(CXXDefaultArgExpr::Create(getSema().Context, Loc,
+ Param));
}
/// \brief Build a new C++ zero-initialization expression.
@@ -1655,7 +1661,7 @@ Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) {
if (E.isInvalid())
return getSema().StmtError();
- return getSema().ActOnExprStmt(getSema().FullExpr(E));
+ return getSema().ActOnExprStmt(getSema().MakeFullExpr(E));
}
}
@@ -2128,13 +2134,6 @@ QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB,
}
template<typename Derived>
-QualType
-TreeTransform<Derived>::TransformFixedWidthIntType(TypeLocBuilder &TLB,
- FixedWidthIntTypeLoc T) {
- return TransformTypeSpecType(TLB, T);
-}
-
-template<typename Derived>
QualType TreeTransform<Derived>::TransformComplexType(TypeLocBuilder &TLB,
ComplexTypeLoc T) {
// FIXME: recurse?
@@ -3067,7 +3066,7 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
return SemaRef.StmtError();
}
- Sema::FullExprArg FullCond(getSema().FullExpr(Cond));
+ Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
// Transform the "then" branch.
OwningStmtResult Then = getDerived().TransformStmt(S->getThen());
@@ -3110,7 +3109,7 @@ TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
return SemaRef.StmtError();
}
- Sema::FullExprArg FullCond(getSema().FullExpr(Cond));
+ Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
// Rebuild the switch statement.
OwningStmtResult Switch = getDerived().RebuildSwitchStmtStart(FullCond,
@@ -3147,7 +3146,7 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
return SemaRef.StmtError();
}
- Sema::FullExprArg FullCond(getSema().FullExpr(Cond));
+ Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
// Transform the body
OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
@@ -3229,9 +3228,9 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
return SemaRef.Owned(S->Retain());
return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(),
- move(Init), getSema().FullExpr(Cond),
+ move(Init), getSema().MakeFullExpr(Cond),
ConditionVar,
- getSema().FullExpr(Inc),
+ getSema().MakeFullExpr(Inc),
S->getRParenLoc(), move(Body));
}
@@ -3688,8 +3687,13 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
Base.get() == E->getBase() &&
Qualifier == E->getQualifier() &&
Member == E->getMemberDecl() &&
- !E->hasExplicitTemplateArgumentList())
+ !E->hasExplicitTemplateArgumentList()) {
+
+ // Mark it referenced in the new context regardless.
+ // FIXME: this is a bit instantiation-specific.
+ SemaRef.MarkDeclarationReferenced(E->getMemberLoc(), Member);
return SemaRef.Owned(E->Retain());
+ }
TemplateArgumentListInfo TransArgs;
if (E->hasExplicitTemplateArgumentList()) {
@@ -4411,7 +4415,7 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
Param == E->getParam())
return SemaRef.Owned(E->Retain());
- return getDerived().RebuildCXXDefaultArgExpr(Param);
+ return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param);
}
template<typename Derived>
@@ -4476,6 +4480,31 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
!ArgumentChanged)
return SemaRef.Owned(E->Retain());
+ if (!ArraySize.get()) {
+ // If no array size was specified, but the new expression was
+ // instantiated with an array type (e.g., "new T" where T is
+ // instantiated with "int[4]"), extract the outer bound from the
+ // array type as our array size. We do this with constant and
+ // dependently-sized array types.
+ const ArrayType *ArrayT = SemaRef.Context.getAsArrayType(AllocType);
+ if (!ArrayT) {
+ // Do nothing
+ } else if (const ConstantArrayType *ConsArrayT
+ = dyn_cast<ConstantArrayType>(ArrayT)) {
+ ArraySize
+ = SemaRef.Owned(new (SemaRef.Context) IntegerLiteral(
+ ConsArrayT->getSize(),
+ SemaRef.Context.getSizeType(),
+ /*FIXME:*/E->getLocStart()));
+ AllocType = ConsArrayT->getElementType();
+ } else if (const DependentSizedArrayType *DepArrayT
+ = dyn_cast<DependentSizedArrayType>(ArrayT)) {
+ if (DepArrayT->getSizeExpr()) {
+ ArraySize = SemaRef.Owned(DepArrayT->getSizeExpr()->Retain());
+ AllocType = DepArrayT->getElementType();
+ }
+ }
+ }
return getDerived().RebuildCXXNewExpr(E->getLocStart(),
E->isGlobalNew(),
/*FIXME:*/E->getLocStart(),
@@ -4725,38 +4754,24 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
/// \brief Transform a C++ temporary-binding expression.
///
-/// The transformation of a temporary-binding expression always attempts to
-/// bind a new temporary variable to its subexpression, even if the
-/// subexpression itself did not change, because the temporary variable itself
-/// must be unique.
+/// Since CXXBindTemporaryExpr nodes are implicitly generated, we just
+/// transform the subexpression and return that.
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
- OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
- if (SubExpr.isInvalid())
- return SemaRef.ExprError();
-
- return SemaRef.MaybeBindToTemporary(SubExpr.takeAs<Expr>());
+ return getDerived().TransformExpr(E->getSubExpr());
}
/// \brief Transform a C++ expression that contains temporaries that should
/// be destroyed after the expression is evaluated.
///
-/// The transformation of a full expression always attempts to build a new
-/// CXXExprWithTemporaries expression, even if the
-/// subexpression itself did not change, because it will need to capture the
-/// the new temporary variables introduced in the subexpression.
+/// Since CXXExprWithTemporaries nodes are implicitly generated, we
+/// just transform the subexpression and return that.
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXExprWithTemporaries(
- CXXExprWithTemporaries *E) {
- OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
- if (SubExpr.isInvalid())
- return SemaRef.ExprError();
-
- return SemaRef.Owned(
- SemaRef.MaybeCreateCXXExprWithTemporaries(SubExpr.takeAs<Expr>(),
- E->shouldDestroyTemporaries()));
+ CXXExprWithTemporaries *E) {
+ return getDerived().TransformExpr(E->getSubExpr());
}
template<typename Derived>
@@ -5233,9 +5248,6 @@ TreeTransform<Derived>::RebuildArrayType(QualType ElementType,
break;
}
- if (SizeType.isNull())
- SizeType = SemaRef.Context.getFixedWidthIntType(Size->getBitWidth(), false);
-
IntegerLiteral ArraySize(*Size, SizeType, /*FIXME*/BracketsRange.getBegin());
return SemaRef.BuildArrayType(ElementType, SizeMod, &ArraySize,
IndexTypeQuals, BracketsRange,
OpenPOWER on IntegriCloud