summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2010-01-15 15:39:40 +0000
committerrdivacky <rdivacky@FreeBSD.org>2010-01-15 15:39:40 +0000
commita3fa5c7f1b5e2ba4d6ec033dc0e2376326b05824 (patch)
treea6082d4d1d1e9ddaea09a6a04bb4a47da95d642d /lib
parentbb1e3bc1e0be2b8f891db46457a8943451bf4d8b (diff)
downloadFreeBSD-src-a3fa5c7f1b5e2ba4d6ec033dc0e2376326b05824.zip
FreeBSD-src-a3fa5c7f1b5e2ba4d6ec033dc0e2376326b05824.tar.gz
Update clang to r93512.
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/APValue.cpp33
-rw-r--r--lib/AST/ASTContext.cpp62
-rw-r--r--lib/AST/AttrImpl.cpp143
-rw-r--r--lib/AST/CMakeLists.txt1
-rw-r--r--lib/AST/Decl.cpp11
-rw-r--r--lib/AST/DeclCXX.cpp35
-rw-r--r--lib/AST/DeclarationName.cpp51
-rw-r--r--lib/AST/Expr.cpp30
-rw-r--r--lib/AST/ExprConstant.cpp108
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp11
-rw-r--r--lib/AST/Stmt.cpp4
-rw-r--r--lib/AST/StmtPrinter.cpp12
-rw-r--r--lib/AST/TypeLoc.cpp12
-rw-r--r--lib/AST/TypePrinter.cpp9
-rw-r--r--lib/Analysis/AnalysisContext.cpp4
-rw-r--r--lib/Analysis/BasicConstraintManager.cpp11
-rw-r--r--lib/Analysis/BugReporter.cpp19
-rw-r--r--lib/Analysis/CFRefCount.cpp25
-rw-r--r--lib/Analysis/CheckSecuritySyntaxOnly.cpp18
-rw-r--r--lib/Analysis/Environment.cpp7
-rw-r--r--lib/Analysis/GRExprEngine.cpp133
-rw-r--r--lib/Analysis/GRState.cpp3
-rw-r--r--lib/Analysis/MemRegion.cpp65
-rw-r--r--lib/Analysis/OSAtomicChecker.cpp28
-rw-r--r--lib/Analysis/RangeConstraintManager.cpp8
-rw-r--r--lib/Analysis/RegionStore.cpp223
-rw-r--r--lib/Analysis/ReturnStackAddressChecker.cpp14
-rw-r--r--lib/Analysis/SVals.cpp4
-rw-r--r--lib/Analysis/SValuator.cpp8
-rw-r--r--lib/Analysis/SimpleConstraintManager.cpp47
-rw-r--r--lib/Analysis/SimpleConstraintManager.h3
-rw-r--r--lib/Analysis/SimpleSValuator.cpp8
-rw-r--r--lib/Analysis/Store.cpp43
-rw-r--r--lib/Basic/Diagnostic.cpp96
-rw-r--r--lib/Basic/Targets.cpp456
-rw-r--r--lib/CodeGen/CGBlocks.cpp60
-rw-r--r--lib/CodeGen/CGBlocks.h7
-rw-r--r--lib/CodeGen/CGCXX.cpp671
-rw-r--r--lib/CodeGen/CGClass.cpp394
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp63
-rw-r--r--lib/CodeGen/CGDebugInfo.h13
-rw-r--r--lib/CodeGen/CGDecl.cpp2
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp36
-rw-r--r--lib/CodeGen/CGExpr.cpp148
-rw-r--r--lib/CodeGen/CGExprAgg.cpp3
-rw-r--r--lib/CodeGen/CGExprCXX.cpp331
-rw-r--r--lib/CodeGen/CGExprComplex.cpp39
-rw-r--r--lib/CodeGen/CGExprConstant.cpp33
-rw-r--r--lib/CodeGen/CGExprScalar.cpp160
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp32
-rw-r--r--lib/CodeGen/CGRTTI.cpp22
-rw-r--r--lib/CodeGen/CGVtable.cpp259
-rw-r--r--lib/CodeGen/CGVtable.h110
-rw-r--r--lib/CodeGen/CMakeLists.txt2
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp33
-rw-r--r--lib/CodeGen/CodeGenFunction.h28
-rw-r--r--lib/CodeGen/CodeGenModule.cpp72
-rw-r--r--lib/CodeGen/CodeGenModule.h19
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp43
-rw-r--r--lib/CodeGen/CodeGenTypes.h7
-rw-r--r--lib/CodeGen/Mangle.cpp5
-rw-r--r--lib/CodeGen/TargetInfo.cpp1904
-rw-r--r--lib/CodeGen/TargetInfo.h50
-rw-r--r--lib/Driver/ToolChains.cpp12
-rw-r--r--lib/Driver/ToolChains.h2
-rw-r--r--lib/Driver/Tools.cpp19
-rw-r--r--lib/Driver/Types.cpp2
-rw-r--r--lib/Frontend/ASTConsumers.cpp13
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp12
-rw-r--r--lib/Frontend/CompilerInstance.cpp93
-rw-r--r--lib/Frontend/CompilerInvocation.cpp17
-rw-r--r--lib/Frontend/FixItRewriter.cpp3
-rw-r--r--lib/Frontend/FrontendActions.cpp4
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp6
-rw-r--r--lib/Frontend/InitPreprocessor.cpp442
-rw-r--r--lib/Frontend/PCHReader.cpp71
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp7
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp4
-rw-r--r--lib/Frontend/PCHWriter.cpp16
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp4
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp1
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp3
-rw-r--r--lib/Frontend/RewriteObjC.cpp314
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp9
-rw-r--r--lib/Headers/xmmintrin.h2
-rw-r--r--lib/Lex/HeaderMap.cpp27
-rw-r--r--lib/Lex/HeaderSearch.cpp52
-rw-r--r--lib/Lex/Lexer.cpp10
-rw-r--r--lib/Lex/LiteralSupport.cpp9
-rw-r--r--lib/Lex/PPDirectives.cpp79
-rw-r--r--lib/Lex/PPLexerChange.cpp3
-rw-r--r--lib/Lex/PPMacroExpansion.cpp72
-rw-r--r--lib/Lex/Pragma.cpp15
-rw-r--r--lib/Lex/Preprocessor.cpp33
-rw-r--r--lib/Parse/DeclSpec.cpp8
-rw-r--r--lib/Parse/ParseDecl.cpp178
-rw-r--r--lib/Parse/ParseDeclCXX.cpp58
-rw-r--r--lib/Parse/ParseExpr.cpp24
-rw-r--r--lib/Parse/ParseExprCXX.cpp52
-rw-r--r--lib/Parse/ParseObjc.cpp39
-rw-r--r--lib/Parse/ParseStmt.cpp8
-rw-r--r--lib/Parse/ParseTemplate.cpp3
-rw-r--r--lib/Parse/Parser.cpp6
-rw-r--r--lib/Rewrite/Rewriter.cpp4
-rw-r--r--lib/Sema/CMakeLists.txt1
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp51
-rw-r--r--lib/Sema/IdentifierResolver.cpp42
-rw-r--r--lib/Sema/IdentifierResolver.h11
-rw-r--r--lib/Sema/Lookup.h31
-rw-r--r--lib/Sema/Sema.cpp322
-rw-r--r--lib/Sema/Sema.h116
-rw-r--r--lib/Sema/SemaCXXCast.cpp2
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp26
-rw-r--r--lib/Sema/SemaChecking.cpp478
-rw-r--r--lib/Sema/SemaCodeComplete.cpp1598
-rw-r--r--lib/Sema/SemaDecl.cpp319
-rw-r--r--lib/Sema/SemaDeclAttr.cpp21
-rw-r--r--lib/Sema/SemaDeclCXX.cpp244
-rw-r--r--lib/Sema/SemaDeclObjC.cpp110
-rw-r--r--lib/Sema/SemaExpr.cpp340
-rw-r--r--lib/Sema/SemaExprCXX.cpp279
-rw-r--r--lib/Sema/SemaExprObjC.cpp5
-rw-r--r--lib/Sema/SemaInit.cpp62
-rw-r--r--lib/Sema/SemaLookup.cpp295
-rw-r--r--lib/Sema/SemaOverload.cpp816
-rw-r--r--lib/Sema/SemaOverload.h184
-rw-r--r--lib/Sema/SemaStmt.cpp9
-rw-r--r--lib/Sema/SemaTemplate.cpp54
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp29
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp7
-rw-r--r--lib/Sema/SemaType.cpp63
-rw-r--r--lib/Sema/TargetAttributesSema.cpp86
-rw-r--r--lib/Sema/TargetAttributesSema.h27
-rw-r--r--lib/Sema/TreeTransform.h64
134 files changed, 9544 insertions, 4175 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 772a884..50a6e0a 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -12,9 +12,20 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/APValue.h"
+#include "clang/AST/CharUnits.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+namespace {
+ struct LV {
+ Expr* Base;
+ CharUnits Offset;
+ };
+}
+
+APValue::APValue(Expr* B) : Kind(Uninitialized) {
+ MakeLValue(); setLValue(B, CharUnits::Zero());
+}
const APValue &APValue::operator=(const APValue &RHS) {
if (Kind != RHS.Kind) {
@@ -106,3 +117,25 @@ void APValue::print(llvm::raw_ostream &OS) const {
}
}
+Expr* APValue::getLValueBase() const {
+ assert(isLValue() && "Invalid accessor");
+ return ((const LV*)(const void*)Data)->Base;
+}
+
+CharUnits APValue::getLValueOffset() const {
+ assert(isLValue() && "Invalid accessor");
+ return ((const LV*)(const void*)Data)->Offset;
+}
+
+void APValue::setLValue(Expr *B, const CharUnits &O) {
+ assert(isLValue() && "Invalid accessor");
+ ((LV*)(char*)Data)->Base = B;
+ ((LV*)(char*)Data)->Offset = O;
+}
+
+void APValue::MakeLValue() {
+ assert(isUninit() && "Bad state change");
+ new ((void*)(char*)Data) LV();
+ Kind = LValue;
+}
+
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 74e74e7..76ec852 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -814,10 +814,10 @@ ASTContext::getTypeInfo(const Type *T) {
/// 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());
+ return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth());
}
CharUnits ASTContext::getTypeSizeInChars(const Type *T) {
- return CharUnits::fromRaw(getTypeSize(T) / getCharWidth());
+ return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth());
}
/// getPreferredTypeAlign - Return the "preferred" alignment of the specified
@@ -2374,16 +2374,14 @@ CanQualType ASTContext::getCanonicalType(QualType T) {
QualType ASTContext::getUnqualifiedArrayType(QualType T,
Qualifiers &Quals) {
- assert(T.isCanonical() && "Only operates on canonical types");
+ Quals = T.getQualifiers();
if (!isa<ArrayType>(T)) {
- Quals = T.getLocalQualifiers();
- return T.getLocalUnqualifiedType();
+ return T.getUnqualifiedType();
}
- assert(!T.hasQualifiers() && "canonical array type has qualifiers!");
const ArrayType *AT = cast<ArrayType>(T);
QualType Elt = AT->getElementType();
- QualType UnqualElt = getUnqualifiedArrayType(getCanonicalType(Elt), Quals);
+ QualType UnqualElt = getUnqualifiedArrayType(Elt, Quals);
if (Elt == UnqualElt)
return T;
@@ -2396,12 +2394,6 @@ QualType ASTContext::getUnqualifiedArrayType(QualType 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,
@@ -3143,16 +3135,21 @@ static bool isTypeTypedefedAsBOOL(QualType T) {
/// getObjCEncodingTypeSize returns size of type for objective-c encoding
/// purpose.
-int ASTContext::getObjCEncodingTypeSize(QualType type) {
- uint64_t sz = getTypeSize(type);
+CharUnits ASTContext::getObjCEncodingTypeSize(QualType type) {
+ CharUnits sz = getTypeSizeInChars(type);
// Make all integer and enum types at least as large as an int
- if (sz > 0 && type->isIntegralType())
- sz = std::max(sz, getTypeSize(IntTy));
+ if (sz.isPositive() && type->isIntegralType())
+ sz = std::max(sz, getTypeSizeInChars(IntTy));
// Treat arrays as pointers, since that's how they're passed in.
else if (type->isArrayType())
- sz = getTypeSize(VoidPtrTy);
- return sz / getTypeSize(CharTy);
+ sz = getTypeSizeInChars(VoidPtrTy);
+ return sz;
+}
+
+static inline
+std::string charUnitsToString(const CharUnits &CU) {
+ return llvm::itostr(CU.getQuantity());
}
/// getObjCEncodingForBlockDecl - Return the encoded type for this method
@@ -3168,17 +3165,17 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
// Start with computing size of a pointer in number of bytes.
// FIXME: There might(should) be a better way of doing this computation!
SourceLocation Loc;
- int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy);
- int ParmOffset = PtrSize;
+ CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy);
+ CharUnits ParmOffset = PtrSize;
for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
E = Decl->param_end(); PI != E; ++PI) {
QualType PType = (*PI)->getType();
- int sz = getObjCEncodingTypeSize(PType);
- assert (sz > 0 && "BlockExpr - Incomplete param type");
+ CharUnits sz = getObjCEncodingTypeSize(PType);
+ assert (sz.isPositive() && "BlockExpr - Incomplete param type");
ParmOffset += sz;
}
// Size of the argument frame
- S += llvm::utostr(ParmOffset);
+ S += charUnitsToString(ParmOffset);
// Block pointer and offset.
S += "@?0";
ParmOffset = PtrSize;
@@ -3198,7 +3195,7 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
} else if (PType->isFunctionType())
PType = PVDecl->getType();
getObjCEncodingForType(PType, S);
- S += llvm::utostr(ParmOffset);
+ S += charUnitsToString(ParmOffset);
ParmOffset += getObjCEncodingTypeSize(PType);
}
}
@@ -3216,20 +3213,21 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
// Start with computing size of a pointer in number of bytes.
// FIXME: There might(should) be a better way of doing this computation!
SourceLocation Loc;
- int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy);
+ CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy);
// The first two arguments (self and _cmd) are pointers; account for
// their size.
- int ParmOffset = 2 * PtrSize;
+ CharUnits ParmOffset = 2 * PtrSize;
for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
E = Decl->param_end(); PI != E; ++PI) {
QualType PType = (*PI)->getType();
- int sz = getObjCEncodingTypeSize(PType);
- assert (sz > 0 && "getObjCEncodingForMethodDecl - Incomplete param type");
+ CharUnits sz = getObjCEncodingTypeSize(PType);
+ assert (sz.isPositive() &&
+ "getObjCEncodingForMethodDecl - Incomplete param type");
ParmOffset += sz;
}
- S += llvm::utostr(ParmOffset);
+ S += charUnitsToString(ParmOffset);
S += "@0:";
- S += llvm::utostr(PtrSize);
+ S += charUnitsToString(PtrSize);
// Argument types.
ParmOffset = 2 * PtrSize;
@@ -3249,7 +3247,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
// 'in', 'inout', etc.
getObjCEncodingForTypeQualifier(PVDecl->getObjCDeclQualifier(), S);
getObjCEncodingForType(PType, S);
- S += llvm::utostr(ParmOffset);
+ S += charUnitsToString(ParmOffset);
ParmOffset += getObjCEncodingTypeSize(PType);
}
}
diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
new file mode 100644
index 0000000..02c70b6
--- /dev/null
+++ b/lib/AST/AttrImpl.cpp
@@ -0,0 +1,143 @@
+//===--- AttrImpl.cpp - Classes for representing attributes -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains out-of-line virtual methods for Attr classes.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "clang/AST/Attr.h"
+#include "clang/AST/ASTContext.h"
+using namespace clang;
+
+#define DEF_SIMPLE_ATTR_CLONE(ATTR) \
+ Attr *ATTR##Attr::clone(ASTContext &C) const { \
+ return ::new (C) ATTR##Attr; \
+ }
+
+// FIXME: Can we use variadic macro to define DEF_SIMPLE_ATTR_CLONE for
+// "non-simple" classes?
+
+DEF_SIMPLE_ATTR_CLONE(Packed)
+DEF_SIMPLE_ATTR_CLONE(AlwaysInline)
+DEF_SIMPLE_ATTR_CLONE(Malloc)
+DEF_SIMPLE_ATTR_CLONE(NoReturn)
+DEF_SIMPLE_ATTR_CLONE(AnalyzerNoReturn)
+DEF_SIMPLE_ATTR_CLONE(Deprecated)
+DEF_SIMPLE_ATTR_CLONE(Final)
+DEF_SIMPLE_ATTR_CLONE(Unavailable)
+DEF_SIMPLE_ATTR_CLONE(Unused)
+DEF_SIMPLE_ATTR_CLONE(Used)
+DEF_SIMPLE_ATTR_CLONE(Weak)
+DEF_SIMPLE_ATTR_CLONE(WeakImport)
+DEF_SIMPLE_ATTR_CLONE(NoThrow)
+DEF_SIMPLE_ATTR_CLONE(Const)
+DEF_SIMPLE_ATTR_CLONE(Pure)
+DEF_SIMPLE_ATTR_CLONE(FastCall)
+DEF_SIMPLE_ATTR_CLONE(StdCall)
+DEF_SIMPLE_ATTR_CLONE(CDecl)
+DEF_SIMPLE_ATTR_CLONE(TransparentUnion)
+DEF_SIMPLE_ATTR_CLONE(ObjCNSObject)
+DEF_SIMPLE_ATTR_CLONE(ObjCException)
+DEF_SIMPLE_ATTR_CLONE(NoDebug)
+DEF_SIMPLE_ATTR_CLONE(WarnUnusedResult)
+DEF_SIMPLE_ATTR_CLONE(NoInline)
+DEF_SIMPLE_ATTR_CLONE(CFReturnsRetained)
+DEF_SIMPLE_ATTR_CLONE(NSReturnsRetained)
+DEF_SIMPLE_ATTR_CLONE(BaseCheck)
+DEF_SIMPLE_ATTR_CLONE(Hiding)
+DEF_SIMPLE_ATTR_CLONE(Override)
+DEF_SIMPLE_ATTR_CLONE(DLLImport)
+DEF_SIMPLE_ATTR_CLONE(DLLExport)
+
+Attr* PragmaPackAttr::clone(ASTContext &C) const {
+ return ::new (C) PragmaPackAttr(Alignment);
+}
+
+Attr* AlignedAttr::clone(ASTContext &C) const {
+ return ::new (C) AlignedAttr(Alignment);
+}
+
+Attr* AnnotateAttr::clone(ASTContext &C) const {
+ return ::new (C) AnnotateAttr(Annotation);
+}
+
+Attr *AsmLabelAttr::clone(ASTContext &C) const {
+ return ::new (C) AsmLabelAttr(Label);
+}
+
+Attr *AliasAttr::clone(ASTContext &C) const {
+ return ::new (C) AliasAttr(Aliasee);
+}
+
+Attr *ConstructorAttr::clone(ASTContext &C) const {
+ return ::new (C) ConstructorAttr(priority);
+}
+
+Attr *DestructorAttr::clone(ASTContext &C) const {
+ return ::new (C) DestructorAttr(priority);
+}
+
+Attr *IBOutletAttr::clone(ASTContext &C) const {
+ return ::new (C) IBOutletAttr;
+}
+
+Attr *GNUInlineAttr::clone(ASTContext &C) const {
+ return ::new (C) GNUInlineAttr;
+}
+
+Attr *SectionAttr::clone(ASTContext &C) const {
+ return ::new (C) SectionAttr(Name);
+}
+
+Attr *NonNullAttr::clone(ASTContext &C) const {
+ return ::new (C) NonNullAttr(ArgNums, Size);
+}
+
+Attr *FormatAttr::clone(ASTContext &C) const {
+ return ::new (C) FormatAttr(Type, formatIdx, firstArg);
+}
+
+Attr *FormatArgAttr::clone(ASTContext &C) const {
+ return ::new (C) FormatArgAttr(formatIdx);
+}
+
+Attr *SentinelAttr::clone(ASTContext &C) const {
+ return ::new (C) SentinelAttr(sentinel, NullPos);
+}
+
+Attr *VisibilityAttr::clone(ASTContext &C) const {
+ return ::new (C) VisibilityAttr(VisibilityType);
+}
+
+Attr *OverloadableAttr::clone(ASTContext &C) const {
+ return ::new (C) OverloadableAttr;
+}
+
+Attr *BlocksAttr::clone(ASTContext &C) const {
+ return ::new (C) BlocksAttr(BlocksAttrType);
+}
+
+Attr *CleanupAttr::clone(ASTContext &C) const {
+ return ::new (C) CleanupAttr(FD);
+}
+
+Attr *RegparmAttr::clone(ASTContext &C) const {
+ return ::new (C) RegparmAttr(NumParams);
+}
+
+Attr *ReqdWorkGroupSizeAttr::clone(ASTContext &C) const {
+ return ::new (C) ReqdWorkGroupSizeAttr(X, Y, Z);
+}
+
+Attr *MSP430InterruptAttr::clone(ASTContext &C) const {
+ return ::new (C) MSP430InterruptAttr(Number);
+}
+
+
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 5aecf87..dea96e7 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -4,6 +4,7 @@ add_clang_library(clangAST
APValue.cpp
ASTConsumer.cpp
ASTContext.cpp
+ AttrImpl.cpp
CXXInheritance.cpp
Decl.cpp
DeclBase.cpp
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index e112fa3..e77661a 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -957,7 +957,7 @@ bool FunctionDecl::isInlined() const {
/// "externally" visible to other translation units in the program.
///
/// In C99, inline definitions are not externally visible by default. However,
-/// if even one of the globa-scope declarations is marked "extern inline", the
+/// if even one of the global-scope declarations is marked "extern inline", the
/// inline definition becomes externally visible (C99 6.7.4p6).
///
/// In GNU89 mode, or if the gnu_inline attribute is attached to the function
@@ -1039,6 +1039,15 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
return OO_None;
}
+/// getLiteralIdentifier - The literal suffix identifier this function
+/// represents, if any.
+const IdentifierInfo *FunctionDecl::getLiteralIdentifier() const {
+ if (getDeclName().getNameKind() == DeclarationName::CXXLiteralOperatorName)
+ return getDeclName().getCXXLiteralIdentifier();
+ else
+ return 0;
+}
+
FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
if (MemberSpecializationInfo *Info = getMemberSpecializationInfo())
return cast<FunctionDecl>(Info->getInstantiatedFrom());
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index bbbb19a..1cce35c 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -144,6 +144,19 @@ CXXRecordDecl::setBases(ASTContext &C,
}
}
+/// Callback function for CXXRecordDecl::forallBases that acknowledges
+/// that it saw a base class.
+static bool SawBase(const CXXRecordDecl *, void *) {
+ return true;
+}
+
+bool CXXRecordDecl::hasAnyDependentBases() const {
+ if (!isDependentContext())
+ return false;
+
+ return !forallBases(SawBase, 0);
+}
+
bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
return getCopyConstructor(Context, Qualifiers::Const) != 0;
}
@@ -643,23 +656,15 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const {
return C.getPointerType(ClassTy);
}
-static bool MethodHasBody(const CXXMethodDecl *MD, const FunctionDecl *&fn) {
- // Simple case: function has a body
- if (MD->getBody(fn))
- return true;
-
- // Complex case: function is an instantiation of a function which has a
- // body, but the definition hasn't been instantiated.
- const FunctionDecl *PatternDecl = MD->getTemplateInstantiationPattern();
- if (PatternDecl && PatternDecl->getBody(fn))
- return true;
-
- return false;
-}
-
bool CXXMethodDecl::hasInlineBody() const {
+ // If this function is a template instantiation, look at the template from
+ // which it was instantiated.
+ const FunctionDecl *CheckFn = getTemplateInstantiationPattern();
+ if (!CheckFn)
+ CheckFn = this;
+
const FunctionDecl *fn;
- return MethodHasBody(this, fn) && !fn->isOutOfLine();
+ return CheckFn->getBody(fn) && !fn->isOutOfLine();
}
CXXBaseOrMemberInitializer::
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 60c40e2..ff81073 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -56,9 +56,14 @@ public:
/// This identifier is stored here rather than directly in DeclarationName so as
/// to allow Objective-C selectors, which are about a million times more common,
/// to consume minimal memory.
-class CXXLiteralOperatorIdName : public DeclarationNameExtra {
+class CXXLiteralOperatorIdName
+ : public DeclarationNameExtra, public llvm::FoldingSetNode {
public:
IdentifierInfo *ID;
+
+ void Profile(llvm::FoldingSetNodeID &FSID) {
+ FSID.AddPointer(ID);
+ }
};
bool operator<(DeclarationName LHS, DeclarationName RHS) {
@@ -180,6 +185,11 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
return Identifier;
}
+bool DeclarationName::isDependentName() const {
+ QualType T = getCXXNameType();
+ return !T.isNull() && T->isDependentType();
+}
+
std::string DeclarationName::getAsString() const {
switch (getNameKind()) {
case Identifier:
@@ -353,6 +363,7 @@ void DeclarationName::dump() const {
DeclarationNameTable::DeclarationNameTable() {
CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>;
+ CXXLiteralOperatorNames = new llvm::FoldingSet<CXXLiteralOperatorIdName>;
// Initialize the overloaded operator names.
CXXOperatorNames = new CXXOperatorIdName[NUM_OVERLOADED_OPERATORS];
@@ -364,16 +375,30 @@ DeclarationNameTable::DeclarationNameTable() {
}
DeclarationNameTable::~DeclarationNameTable() {
- llvm::FoldingSet<CXXSpecialName> *set =
+ llvm::FoldingSet<CXXSpecialName> *SpecialNames =
static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl);
- llvm::FoldingSetIterator<CXXSpecialName> I = set->begin(), E = set->end();
+ llvm::FoldingSetIterator<CXXSpecialName>
+ SI = SpecialNames->begin(), SE = SpecialNames->end();
+
+ while (SI != SE) {
+ CXXSpecialName *n = &*SI++;
+ delete n;
+ }
- while (I != E) {
- CXXSpecialName *n = &*I++;
+
+ llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames
+ = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*>
+ (CXXLiteralOperatorNames);
+ llvm::FoldingSetIterator<CXXLiteralOperatorIdName>
+ LI = LiteralNames->begin(), LE = LiteralNames->end();
+
+ while (LI != LE) {
+ CXXLiteralOperatorIdName *n = &*LI++;
delete n;
}
- delete set;
+ delete SpecialNames;
+ delete LiteralNames;
delete [] CXXOperatorNames;
}
@@ -428,9 +453,23 @@ DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) {
DeclarationName
DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) {
+ llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames
+ = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*>
+ (CXXLiteralOperatorNames);
+
+ llvm::FoldingSetNodeID ID;
+ ID.AddPointer(II);
+
+ void *InsertPos = 0;
+ if (CXXLiteralOperatorIdName *Name =
+ LiteralNames->FindNodeOrInsertPos(ID, InsertPos))
+ return DeclarationName (Name);
+
CXXLiteralOperatorIdName *LiteralName = new CXXLiteralOperatorIdName;
LiteralName->ExtraKindOrNumArgs = DeclarationNameExtra::CXXLiteralOperator;
LiteralName->ID = II;
+
+ LiteralNames->InsertNode(LiteralName, InsertPos);
return DeclarationName(LiteralName);
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 04a6abc..4c3046b 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -2154,7 +2154,8 @@ IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() {
return getField()->getIdentifier();
}
-DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
+DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
+ unsigned NumDesignators,
const Designator *Designators,
SourceLocation EqualOrColonLoc,
bool GNUSyntax,
@@ -2165,7 +2166,7 @@ DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
Init->isTypeDependent(), Init->isValueDependent()),
EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) {
- this->Designators = new Designator[NumDesignators];
+ this->Designators = new (C) Designator[NumDesignators];
// Record the initializer itself.
child_iterator Child = child_begin();
@@ -2210,7 +2211,7 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
bool UsesColonSyntax, Expr *Init) {
void *Mem = C.Allocate(sizeof(DesignatedInitExpr) +
sizeof(Stmt *) * (NumIndexExprs + 1), 8);
- return new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators, Designators,
+ return new (Mem) DesignatedInitExpr(C, C.VoidTy, NumDesignators, Designators,
ColonOrEqualLoc, UsesColonSyntax,
IndexExprs, NumIndexExprs, Init);
}
@@ -2222,12 +2223,12 @@ DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C,
return new (Mem) DesignatedInitExpr(NumIndexExprs + 1);
}
-void DesignatedInitExpr::setDesignators(const Designator *Desigs,
+void DesignatedInitExpr::setDesignators(ASTContext &C,
+ const Designator *Desigs,
unsigned NumDesigs) {
- if (Designators)
- delete [] Designators;
+ DestroyDesignators(C);
- Designators = new Designator[NumDesigs];
+ Designators = new (C) Designator[NumDesigs];
NumDesignators = NumDesigs;
for (unsigned I = 0; I != NumDesigs; ++I)
Designators[I] = Desigs[I];
@@ -2276,7 +2277,7 @@ Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) {
/// \brief Replaces the designator at index @p Idx with the series
/// of designators in [First, Last).
-void DesignatedInitExpr::ExpandDesignator(unsigned Idx,
+void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx,
const Designator *First,
const Designator *Last) {
unsigned NumNewDesignators = Last - First;
@@ -2292,21 +2293,28 @@ void DesignatedInitExpr::ExpandDesignator(unsigned Idx,
}
Designator *NewDesignators
- = new Designator[NumDesignators - 1 + NumNewDesignators];
+ = new (C) Designator[NumDesignators - 1 + NumNewDesignators];
std::copy(Designators, Designators + Idx, NewDesignators);
std::copy(First, Last, NewDesignators + Idx);
std::copy(Designators + Idx + 1, Designators + NumDesignators,
NewDesignators + Idx + NumNewDesignators);
- delete [] Designators;
+ DestroyDesignators(C);
Designators = NewDesignators;
NumDesignators = NumDesignators - 1 + NumNewDesignators;
}
void DesignatedInitExpr::DoDestroy(ASTContext &C) {
- delete [] Designators;
+ DestroyDesignators(C);
Expr::DoDestroy(C);
}
+void DesignatedInitExpr::DestroyDesignators(ASTContext &C) {
+ for (unsigned I = 0; I != NumDesignators; ++I)
+ Designators[I].~Designator();
+ C.Deallocate(Designators);
+ Designators = 0;
+}
+
ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc,
Expr **exprs, unsigned nexprs,
SourceLocation rparenloc)
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 06afec7..dfff209 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/ASTDiagnostic.h"
@@ -69,11 +70,12 @@ static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info);
static bool EvalPointerValueAsBool(APValue& Value, bool& Result) {
// FIXME: Is this accurate for all kinds of bases? If not, what would
// the check look like?
- Result = Value.getLValueBase() || Value.getLValueOffset();
+ Result = Value.getLValueBase() || !Value.getLValueOffset().isZero();
return true;
}
-static bool HandleConversionToBool(Expr* E, bool& Result, EvalInfo &Info) {
+static bool HandleConversionToBool(const Expr* E, bool& Result,
+ EvalInfo &Info) {
if (E->getType()->isIntegralType()) {
APSInt IntResult;
if (!EvaluateInteger(E, IntResult, Info))
@@ -222,11 +224,11 @@ public:
APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
APValue VisitDeclRefExpr(DeclRefExpr *E);
- APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E, 0); }
+ APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E); }
APValue VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
APValue VisitMemberExpr(MemberExpr *E);
- APValue VisitStringLiteral(StringLiteral *E) { return APValue(E, 0); }
- APValue VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return APValue(E, 0); }
+ APValue VisitStringLiteral(StringLiteral *E) { return APValue(E); }
+ APValue VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return APValue(E); }
APValue VisitArraySubscriptExpr(ArraySubscriptExpr *E);
APValue VisitUnaryDeref(UnaryOperator *E);
APValue VisitUnaryExtension(const UnaryOperator *E)
@@ -254,12 +256,12 @@ static bool EvaluateLValue(const Expr* E, APValue& Result, EvalInfo &Info) {
APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
if (isa<FunctionDecl>(E->getDecl())) {
- return APValue(E, 0);
+ return APValue(E);
} else if (VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) {
if (!Info.AnyLValue && !VD->hasGlobalStorage())
return APValue();
if (!VD->getType()->isReferenceType())
- return APValue(E, 0);
+ return APValue(E);
// FIXME: Check whether VD might be overridden!
const VarDecl *Def = 0;
if (const Expr *Init = VD->getDefinition(Def))
@@ -272,7 +274,7 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
APValue LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
if (!Info.AnyLValue && !E->isFileScope())
return APValue();
- return APValue(E, 0);
+ return APValue(E);
}
APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
@@ -309,7 +311,8 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
}
result.setLValue(result.getLValueBase(),
- result.getLValueOffset() + RL.getFieldOffset(i) / 8);
+ result.getLValueOffset() +
+ CharUnits::fromQuantity(RL.getFieldOffset(i) / 8));
return result;
}
@@ -324,9 +327,9 @@ APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
if (!EvaluateInteger(E->getIdx(), Index, Info))
return APValue();
- uint64_t ElementSize = Info.Ctx.getTypeSize(E->getType()) / 8;
+ CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(E->getType());
- uint64_t Offset = Index.getSExtValue() * ElementSize;
+ CharUnits Offset = Index.getSExtValue() * ElementSize;
Result.setLValue(Result.getLValueBase(),
Result.getLValueOffset() + Offset);
return Result;
@@ -363,22 +366,22 @@ public:
{ return Visit(E->getSubExpr()); }
APValue VisitUnaryAddrOf(const UnaryOperator *E);
APValue VisitObjCStringLiteral(ObjCStringLiteral *E)
- { return APValue(E, 0); }
+ { return APValue(E); }
APValue VisitAddrLabelExpr(AddrLabelExpr *E)
- { return APValue(E, 0); }
+ { return APValue(E); }
APValue VisitCallExpr(CallExpr *E);
APValue VisitBlockExpr(BlockExpr *E) {
if (!E->hasBlockDeclRefExprs())
- return APValue(E, 0);
+ return APValue(E);
return APValue();
}
APValue VisitImplicitValueInitExpr(ImplicitValueInitExpr *E)
- { return APValue((Expr*)0, 0); }
+ { return APValue((Expr*)0); }
APValue VisitConditionalOperator(ConditionalOperator *E);
APValue VisitChooseExpr(ChooseExpr *E)
{ return Visit(E->getChosenSubExpr(Info.Ctx)); }
APValue VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E)
- { return APValue((Expr*)0, 0); }
+ { return APValue((Expr*)0); }
// FIXME: Missing: @protocol, @selector
};
} // end anonymous namespace
@@ -409,15 +412,15 @@ APValue PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return APValue();
QualType PointeeType = PExp->getType()->getAs<PointerType>()->getPointeeType();
- uint64_t SizeOfPointee;
+ CharUnits SizeOfPointee;
// Explicitly handle GNU void* and function pointer arithmetic extensions.
if (PointeeType->isVoidType() || PointeeType->isFunctionType())
- SizeOfPointee = 1;
+ SizeOfPointee = CharUnits::One();
else
- SizeOfPointee = Info.Ctx.getTypeSize(PointeeType) / 8;
+ SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType);
- uint64_t Offset = ResultLValue.getLValueOffset();
+ CharUnits Offset = ResultLValue.getLValueOffset();
if (E->getOpcode() == BinaryOperator::Add)
Offset += AdditionalOffset.getLimitedValue() * SizeOfPointee;
@@ -459,7 +462,8 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
if (Result.isInt()) {
Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
- return APValue(0, Result.getInt().getZExtValue());
+ return APValue(0,
+ CharUnits::fromQuantity(Result.getInt().getZExtValue()));
}
// Cast is of an lvalue, no need to change value.
@@ -481,7 +485,8 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
if (Result.isInt()) {
Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
- return APValue(0, Result.getInt().getZExtValue());
+ return APValue(0,
+ CharUnits::fromQuantity(Result.getInt().getZExtValue()));
}
// Cast is of an lvalue, no need to change value.
@@ -502,7 +507,7 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
APValue PointerExprEvaluator::VisitCallExpr(CallExpr *E) {
if (E->isBuiltinCall(Info.Ctx) ==
Builtin::BI__builtin___CFStringMakeConstantString)
- return APValue(E, 0);
+ return APValue(E);
return APValue();
}
@@ -976,20 +981,20 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
&& VD->getType()->isObjectType()
&& !VD->getType()->isVariablyModifiedType()
&& !VD->getType()->isDependentType()) {
- uint64_t Size = Info.Ctx.getTypeSize(VD->getType()) / 8;
- uint64_t Offset = Base.Val.getLValueOffset();
- if (Offset <= Size)
- Size -= Base.Val.getLValueOffset();
+ CharUnits Size = Info.Ctx.getTypeSizeInChars(VD->getType());
+ CharUnits Offset = Base.Val.getLValueOffset();
+ if (!Offset.isNegative() && Offset <= Size)
+ Size -= Offset;
else
- Size = 0;
- return Success(Size, E);
+ Size = CharUnits::Zero();
+ return Success(Size.getQuantity(), E);
}
}
}
// TODO: Perhaps we should let LLVM lower this?
if (E->getArg(0)->HasSideEffects(Info.Ctx)) {
- if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() == 0)
+ if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() <= 1)
return Success(-1ULL, E);
return Success(0, E);
}
@@ -1151,7 +1156,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (LHSValue.getLValueBase()) {
if (!E->isEqualityOp())
return false;
- if (RHSValue.getLValueBase() || RHSValue.getLValueOffset())
+ if (RHSValue.getLValueBase() || !RHSValue.getLValueOffset().isZero())
return false;
bool bres;
if (!EvalPointerValueAsBool(LHSValue, bres))
@@ -1160,7 +1165,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
} else if (RHSValue.getLValueBase()) {
if (!E->isEqualityOp())
return false;
- if (LHSValue.getLValueBase() || LHSValue.getLValueOffset())
+ if (LHSValue.getLValueBase() || !LHSValue.getLValueOffset().isZero())
return false;
bool bres;
if (!EvalPointerValueAsBool(RHSValue, bres))
@@ -1172,11 +1177,13 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
const QualType Type = E->getLHS()->getType();
const QualType ElementType = Type->getAs<PointerType>()->getPointeeType();
- uint64_t D = LHSValue.getLValueOffset() - RHSValue.getLValueOffset();
+ CharUnits ElementSize = CharUnits::One();
if (!ElementType->isVoidType() && !ElementType->isFunctionType())
- D /= Info.Ctx.getTypeSize(ElementType) / 8;
+ ElementSize = Info.Ctx.getTypeSizeInChars(ElementType);
- return Success(D, E);
+ CharUnits Diff = LHSValue.getLValueOffset() -
+ RHSValue.getLValueOffset();
+ return Success(Diff / ElementSize, E);
}
bool Result;
if (E->getOpcode() == BinaryOperator::EQ) {
@@ -1204,21 +1211,23 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
// Handle cases like (unsigned long)&a + 4.
if (E->isAdditiveOp() && Result.isLValue() && RHSVal.isInt()) {
- uint64_t offset = Result.getLValueOffset();
+ CharUnits Offset = Result.getLValueOffset();
+ CharUnits AdditionalOffset = CharUnits::fromQuantity(
+ RHSVal.getInt().getZExtValue());
if (E->getOpcode() == BinaryOperator::Add)
- offset += RHSVal.getInt().getZExtValue();
+ Offset += AdditionalOffset;
else
- offset -= RHSVal.getInt().getZExtValue();
- Result = APValue(Result.getLValueBase(), offset);
+ Offset -= AdditionalOffset;
+ Result = APValue(Result.getLValueBase(), Offset);
return true;
}
// Handle cases like 4 + (unsigned long)&a
if (E->getOpcode() == BinaryOperator::Add &&
RHSVal.isLValue() && Result.isInt()) {
- uint64_t offset = RHSVal.getLValueOffset();
- offset += Result.getInt().getZExtValue();
- Result = APValue(RHSVal.getLValueBase(), offset);
+ CharUnits Offset = RHSVal.getLValueOffset();
+ Offset += CharUnits::fromQuantity(Result.getInt().getZExtValue());
+ Result = APValue(RHSVal.getLValueBase(), Offset);
return true;
}
@@ -1334,8 +1343,7 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
return false;
// Get information about the size.
- unsigned BitWidth = Info.Ctx.getTypeSize(SrcTy);
- return Success(BitWidth / Info.Ctx.Target.getCharWidth(), E);
+ return Success(Info.Ctx.getTypeSizeInChars(SrcTy).getQuantity(), E);
}
bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
@@ -1349,7 +1357,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
return false;
if (LV.getLValueBase())
return false;
- return Success(LV.getLValueOffset(), E);
+ return Success(LV.getLValueOffset().getQuantity(), E);
}
if (E->getOpcode() == UnaryOperator::LNot) {
@@ -1432,7 +1440,8 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
return true;
}
- APSInt AsInt = Info.Ctx.MakeIntValue(LV.getLValueOffset(), SrcType);
+ APSInt AsInt = Info.Ctx.MakeIntValue(LV.getLValueOffset().getQuantity(),
+ SrcType);
return Success(HandleIntToIntCast(DestType, SrcType, AsInt, Info.Ctx), E);
}
@@ -1978,6 +1987,13 @@ bool Expr::EvaluateAsAny(EvalResult &Result, ASTContext &Ctx) const {
return true;
}
+bool Expr::EvaluateAsBooleanCondition(bool &Result, ASTContext &Ctx) const {
+ EvalResult Scratch;
+ EvalInfo Info(Ctx, Scratch);
+
+ return HandleConversionToBool(this, Result, Info);
+}
+
bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const {
EvalInfo Info(Ctx, Result);
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index c914f3f..cfd89ea 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -719,11 +719,6 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
// If a class isnt' polymorphic it doesn't have a key function.
if (!RD->isPolymorphic())
return 0;
-
- // A class template specialization or instantation does not have a key
- // function.
- if (RD->getTemplateSpecializationKind() != TSK_Undeclared)
- return 0;
// A class inside an anonymous namespace doesn't have a key function. (Or
// at least, there's no point to assigning a key function to such a class;
@@ -741,13 +736,13 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
if (MD->isPure())
continue;
- if (MD->isInlineSpecified())
- continue;
-
// Ignore implicit member functions, they are always marked as inline, but
// they don't have a body until they're defined.
if (MD->isImplicit())
continue;
+
+ if (MD->isInlineSpecified())
+ continue;
if (MD->hasInlineBody())
continue;
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 7c7aeb8..104e336 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -337,12 +337,12 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
//===----------------------------------------------------------------------===//
AsmStmt::AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile,
- unsigned numoutputs, unsigned numinputs,
+ bool msasm, unsigned numoutputs, unsigned numinputs,
std::string *names, StringLiteral **constraints,
Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
StringLiteral **clobbers, SourceLocation rparenloc)
: Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr)
- , IsSimple(issimple), IsVolatile(isvolatile)
+ , IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm)
, NumOutputs(numoutputs), NumInputs(numinputs) {
for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) {
Names.push_back(names[i]);
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index a7e42af..bbb904d 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -739,9 +739,10 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) {
void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
// FIXME: Suppress printing implicit bases (like "this")
PrintExpr(Node->getBase());
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(Node->getMemberDecl()))
+ if (FD->isAnonymousStructOrUnion())
+ return;
OS << (Node->isArrow() ? "->" : ".");
- // FIXME: Suppress printing references to unnamed objects
- // representing anonymous unions/structs
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
@@ -1120,6 +1121,13 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
}
void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ // FIXME. For now we just print a trivial constructor call expression,
+ // constructing its first argument object.
+ if (E->getNumArgs() == 1) {
+ CXXConstructorDecl *CD = E->getConstructor();
+ if (CD->isTrivial())
+ PrintExpr(E->getArg(0));
+ }
// Nothing to print.
}
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 3ccb7a9..0840c52 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -13,6 +13,7 @@
#include "llvm/Support/raw_ostream.h"
#include "clang/AST/TypeLocVisitor.h"
+#include "clang/AST/Expr.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -123,3 +124,14 @@ bool TypeSpecTypeLoc::classof(const TypeLoc *TL) {
if (TL->getType().hasLocalQualifiers()) return false;
return TSTChecker().Visit(*TL);
}
+
+// Reimplemented to account for GNU/C++ extension
+// typeof unary-expression
+// where there are no parentheses.
+SourceRange TypeOfExprTypeLoc::getSourceRange() const {
+ if (getRParenLoc().isValid())
+ return SourceRange(getTypeofLoc(), getRParenLoc());
+ else
+ return SourceRange(getTypeofLoc(),
+ getUnderlyingExpr()->getSourceRange().getEnd());
+}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 818657c..00b74bc 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -271,6 +271,10 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
S += ")";
+ if (T->getNoReturnAttr())
+ S += " __attribute__((noreturn))";
+
+
if (T->hasExceptionSpec()) {
S += " throw(";
if (T->hasAnyExceptionSpec())
@@ -287,10 +291,9 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
S += ")";
}
- if (T->getNoReturnAttr())
- S += " __attribute__((noreturn))";
- Print(T->getResultType(), S);
+ AppendTypeQualList(S, T->getTypeQuals());
+ Print(T->getResultType(), S);
}
void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T,
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 97e6d91..2093b5e 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -18,6 +18,7 @@
#include "clang/Analysis/CFG.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Support/BumpVector.h"
@@ -38,6 +39,9 @@ Stmt *AnalysisContext::getBody() {
return MD->getBody();
else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
return BD->getBody();
+ else if (const FunctionTemplateDecl *FunTmpl
+ = dyn_cast_or_null<FunctionTemplateDecl>(D))
+ return FunTmpl->getTemplatedDecl()->getBody();
llvm_unreachable("unknown code decl");
}
diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp
index 6c3f7b2..6dfc470 100644
--- a/lib/Analysis/BasicConstraintManager.cpp
+++ b/lib/Analysis/BasicConstraintManager.cpp
@@ -49,8 +49,9 @@ class BasicConstraintManager
: public SimpleConstraintManager {
GRState::IntSetTy::Factory ISetFactory;
public:
- BasicConstraintManager(GRStateManager& statemgr)
- : ISetFactory(statemgr.getAllocator()) {}
+ BasicConstraintManager(GRStateManager &statemgr, GRSubEngine &subengine)
+ : SimpleConstraintManager(subengine),
+ ISetFactory(statemgr.getAllocator()) {}
const GRState* AssumeSymNE(const GRState* state, SymbolRef sym,
const llvm::APSInt& V);
@@ -88,9 +89,9 @@ public:
} // end anonymous namespace
-ConstraintManager* clang::CreateBasicConstraintManager(GRStateManager& StateMgr)
-{
- return new BasicConstraintManager(StateMgr);
+ConstraintManager* clang::CreateBasicConstraintManager(GRStateManager& statemgr,
+ GRSubEngine &subengine) {
+ return new BasicConstraintManager(statemgr, subengine);
}
const GRState*
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index e648269..2a9531d 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -1818,8 +1818,23 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
R->getRanges(Beg, End);
Diagnostic& Diag = getDiagnostic();
FullSourceLoc L(R->getLocation(), getSourceManager());
- unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning,
- R->getShortDescription().c_str());
+
+ // Search the description for '%', as that will be interpretted as a
+ // format character by FormatDiagnostics.
+ llvm::StringRef desc = R->getShortDescription();
+ unsigned ErrorDiag;
+ {
+ llvm::SmallString<512> TmpStr;
+ llvm::raw_svector_ostream Out(TmpStr);
+ for (llvm::StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I)
+ if (*I == '%')
+ Out << "%%";
+ else
+ Out << *I;
+
+ Out.flush();
+ ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, TmpStr);
+ }
switch (End-Beg) {
default: assert(0 && "Don't handle this many ranges yet!");
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index a15a8f1..5a15fbf 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -52,8 +52,8 @@ using namespace clang;
// not release it."
//
-using llvm::CStrInCStrNoCase;
-using llvm::StringsEqualNoCase;
+using llvm::StrInStrNoCase;
+using llvm::StringRef;
enum NamingConvention { NoConvention, CreateRule, InitRule };
@@ -122,20 +122,20 @@ static NamingConvention deriveNamingConvention(Selector S) {
break;
case 3:
// Methods starting with 'new' follow the create rule.
- if (AtBeginning && StringsEqualNoCase("new", s, len))
+ if (AtBeginning && StringRef(s, len).equals_lower("new"))
C = CreateRule;
break;
case 4:
// Methods starting with 'alloc' or contain 'copy' follow the
// create rule
- if (C == NoConvention && StringsEqualNoCase("copy", s, len))
+ if (C == NoConvention && StringRef(s, len).equals_lower("copy"))
C = CreateRule;
else // Methods starting with 'init' follow the init rule.
- if (AtBeginning && StringsEqualNoCase("init", s, len))
+ if (AtBeginning && StringRef(s, len).equals_lower("init"))
C = InitRule;
break;
case 5:
- if (AtBeginning && StringsEqualNoCase("alloc", s, len))
+ if (AtBeginning && StringRef(s, len).equals_lower("alloc"))
C = CreateRule;
break;
}
@@ -1372,11 +1372,11 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// "AppendValue", or "SetAttribute", then we assume that arguments may
// "escape." This means that something else holds on to the object,
// allowing it be used even after its local retain count drops to 0.
- ArgEffect E = (CStrInCStrNoCase(FName, "InsertValue") ||
- CStrInCStrNoCase(FName, "AddValue") ||
- CStrInCStrNoCase(FName, "SetValue") ||
- CStrInCStrNoCase(FName, "AppendValue") ||
- CStrInCStrNoCase(FName, "SetAttribute"))
+ ArgEffect E = (StrInStrNoCase(FName, "InsertValue") != StringRef::npos||
+ StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
+ StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
+ StrInStrNoCase(FName, "AppendValue") != StringRef::npos||
+ StrInStrNoCase(FName, "SetAttribute") != StringRef::npos)
? MayEscape : DoNothing;
S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, E);
@@ -1555,7 +1555,8 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
if (S.isKeywordSelector()) {
const std::string &str = S.getAsString();
assert(!str.empty());
- if (CStrInCStrNoCase(&str[0], "delegate:")) ReceiverEff = StopTracking;
+ if (StrInStrNoCase(str, "delegate:") != StringRef::npos)
+ ReceiverEff = StopTracking;
}
// Look for methods that return an owned object.
diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
index 3214101..f4874a5 100644
--- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/TargetInfo.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/AST/StmtVisitor.h"
@@ -18,6 +19,12 @@
using namespace clang;
+static bool isArc4RandomAvailable(const ASTContext &Ctx) {
+ const llvm::Triple &T = Ctx.Target.getTriple();
+ return T.getVendor() == llvm::Triple::Apple ||
+ T.getOS() == llvm::Triple::FreeBSD;
+}
+
namespace {
class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
@@ -29,11 +36,14 @@ class WalkAST : public StmtVisitor<WalkAST> {
IdentifierInfo *II_random;
enum { num_setids = 6 };
IdentifierInfo *II_setid[num_setids];
+
+ const bool CheckRand;
public:
WalkAST(BugReporter &br) : BR(br),
II_gets(0), II_getpw(0), II_mktemp(0),
- II_rand(), II_random(0), II_setid() {}
+ II_rand(), II_random(0), II_setid(),
+ CheckRand(isArc4RandomAvailable(BR.getContext())) {}
// Statement visitor methods.
void VisitCallExpr(CallExpr *CE);
@@ -83,8 +93,10 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
CheckCall_gets(CE, FD);
CheckCall_getpw(CE, FD);
CheckCall_mktemp(CE, FD);
- CheckCall_rand(CE, FD);
- CheckCall_random(CE, FD);
+ if (CheckRand) {
+ CheckCall_rand(CE, FD);
+ CheckCall_random(CE, FD);
+ }
}
// Recurse and check children.
diff --git a/lib/Analysis/Environment.cpp b/lib/Analysis/Environment.cpp
index dd2f08b..f04cf7b 100644
--- a/lib/Analysis/Environment.cpp
+++ b/lib/Analysis/Environment.cpp
@@ -37,7 +37,12 @@ SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const {
}
case Stmt::IntegerLiteralClass: {
- return ValMgr.makeIntVal(cast<IntegerLiteral>(E));
+ // In C++, this expression may have been bound to a temporary object.
+ SVal const *X = ExprBindings.lookup(E);
+ if (X)
+ return *X;
+ else
+ return ValMgr.makeIntVal(cast<IntegerLiteral>(E));
}
// Casts where the source and target type are the same
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 2ce8edd..40c12c9 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -17,6 +17,7 @@
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Builtins.h"
@@ -47,10 +48,9 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
}
-static bool CalleeReturnsReference(const CallExpr *CE) {
+static QualType GetCalleeReturnType(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();
@@ -58,16 +58,35 @@ static bool CalleeReturnsReference(const CallExpr *CE) {
else {
const BlockPointerType *BT = T->getAs<BlockPointerType>();
T = BT->getPointeeType()->getAs<FunctionType>()->getResultType();
- }
- return T->isReferenceType();
+ }
+ return T;
+}
+
+static bool CalleeReturnsReference(const CallExpr *CE) {
+ return (bool) GetCalleeReturnType(CE)->getAs<ReferenceType>();
}
static bool ReceiverReturnsReference(const ObjCMessageExpr *ME) {
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (!MD)
return false;
- return MD->getResultType()->isReferenceType();
+ return MD->getResultType()->getAs<ReferenceType>();
+}
+
+#ifndef NDEBUG
+static bool ReceiverReturnsReferenceOrRecord(const ObjCMessageExpr *ME) {
+ const ObjCMethodDecl *MD = ME->getMethodDecl();
+ if (!MD)
+ return false;
+ QualType T = MD->getResultType();
+ return T->getAs<RecordType>() || T->getAs<ReferenceType>();
+}
+
+static bool CalleeReturnsReferenceOrRecord(const CallExpr *CE) {
+ QualType T = GetCalleeReturnType(CE);
+ return T->getAs<ReferenceType>() || T->getAs<RecordType>();
}
+#endif
//===----------------------------------------------------------------------===//
// Batch auditor. DEPRECATED.
@@ -300,23 +319,27 @@ static void RegisterInternalChecks(GRExprEngine &Eng) {
RegisterOSAtomicChecker(Eng);
}
-GRExprEngine::GRExprEngine(AnalysisManager &mgr)
+GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf)
: AMgr(mgr),
CoreEngine(mgr.getASTContext(), *this),
G(CoreEngine.getGraph()),
Builder(NULL),
StateMgr(G.getContext(), mgr.getStoreManagerCreator(),
- mgr.getConstraintManagerCreator(), G.getAllocator()),
+ mgr.getConstraintManagerCreator(), G.getAllocator(),
+ *this),
SymMgr(StateMgr.getSymbolManager()),
ValMgr(StateMgr.getValueManager()),
SVator(ValMgr.getSValuator()),
CurrentStmt(NULL),
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
RaiseSel(GetNullarySelector("raise", G.getContext())),
- BR(mgr, *this)
-{
+ BR(mgr, *this), TF(tf) {
// Register internal checks.
RegisterInternalChecks(*this);
+
+ // FIXME: Eventually remove the TF object entirely.
+ TF->RegisterChecks(*this);
+ TF->RegisterPrinters(getStateManager().Printers);
}
GRExprEngine::~GRExprEngine() {
@@ -330,13 +353,6 @@ GRExprEngine::~GRExprEngine() {
// Utility methods.
//===----------------------------------------------------------------------===//
-void GRExprEngine::setTransferFunctionsAndCheckers(GRTransferFuncs* tf) {
- StateMgr.TF = tf;
- StateMgr.Checkers = &Checkers;
- tf->RegisterChecks(*this);
- tf->RegisterPrinters(getStateManager().Printers);
-}
-
void GRExprEngine::AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C) {
if (!BatchAuditor)
BatchAuditor.reset(new MappedBatchAuditor(getGraph().getAllocator()));
@@ -415,6 +431,25 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
// Top-level transfer function logic (Dispatcher).
//===----------------------------------------------------------------------===//
+/// EvalAssume - Called by ConstraintManager. Used to call checker-specific
+/// logic for handling assumptions on symbolic values.
+const GRState *GRExprEngine::ProcessAssume(const GRState *state, SVal cond,
+ bool assumption) {
+ for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
+ I != E; ++I) {
+
+ if (!state)
+ return NULL;
+
+ state = I->second->EvalAssume(state, cond, assumption);
+ }
+
+ if (!state)
+ return NULL;
+
+ return TF->EvalAssume(state, cond, assumption);
+}
+
void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) {
CurrentStmt = CE.getStmt();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
@@ -809,7 +844,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass: {
CallExpr *C = cast<CallExpr>(Ex);
- assert(CalleeReturnsReference(C));
+ assert(CalleeReturnsReferenceOrRecord(C));
VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true);
break;
}
@@ -840,7 +875,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
case Stmt::ObjCMessageExprClass: {
ObjCMessageExpr *ME = cast<ObjCMessageExpr>(Ex);
- assert(ReceiverReturnsReference(ME));
+ assert(ReceiverReturnsReferenceOrRecord(ME));
VisitObjCMessageExpr(ME, Pred, Dst, true);
return;
}
@@ -871,6 +906,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
case Stmt::UnaryOperatorClass:
VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true);
return;
+
+ // In C++, binding an rvalue to a reference requires to create an object.
+ case Stmt::IntegerLiteralClass:
+ CreateCXXTemporaryObject(Ex, Pred, Dst);
+ return;
default:
// Arbitrary subexpressions can return aggregate temporaries that
@@ -1205,7 +1245,8 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
do {
nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt()));
- DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt, CondV, CaseVal);
+ DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt ? DefaultSt : state,
+ CondV, CaseVal);
// Now "assume" that the case matches.
if (const GRState* stateNew = state->Assume(Res, true)) {
@@ -1220,11 +1261,17 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
// Now "assume" that the case doesn't match. Add this state
// to the default state (if it is feasible).
- if (const GRState *stateNew = DefaultSt->Assume(Res, false)) {
- defaultIsFeasible = true;
- DefaultSt = stateNew;
+ if (DefaultSt) {
+ if (const GRState *stateNew = DefaultSt->Assume(Res, false)) {
+ defaultIsFeasible = true;
+ DefaultSt = stateNew;
+ }
+ else {
+ defaultIsFeasible = false;
+ DefaultSt = NULL;
+ }
}
-
+
// Concretize the next value in the range.
if (V1.Val.getInt() == V2.Val.getInt())
break;
@@ -2375,12 +2422,12 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
QualType T = Ex->getTypeOfArgument();
- uint64_t amt;
+ CharUnits amt;
if (Ex->isSizeOf()) {
if (T == getContext().VoidTy) {
// sizeof(void) == 1 byte.
- amt = 1;
+ amt = CharUnits::One();
}
else if (!T.getTypePtr()->isConstantSizeType()) {
// FIXME: Add support for VLAs.
@@ -2394,14 +2441,15 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
}
else {
// All other cases.
- amt = getContext().getTypeSize(T) / 8;
+ amt = getContext().getTypeSizeInChars(T);
}
}
else // Get alignment of the type.
- amt = getContext().getTypeAlign(T) / 8;
+ amt = CharUnits::fromQuantity(getContext().getTypeAlign(T) / 8);
MakeNode(Dst, Ex, Pred,
- GetState(Pred)->BindExpr(Ex, ValMgr.makeIntVal(amt, Ex->getType())));
+ GetState(Pred)->BindExpr(Ex,
+ ValMgr.makeIntVal(amt.getQuantity(), Ex->getType())));
}
@@ -2695,8 +2743,13 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
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));
+ const MemRegion *R =
+ ValMgr.getRegionManager().getCXXThisRegion(TE->getType(),
+ Pred->getLocationContext());
+
+ const GRState *state = GetState(Pred);
+ SVal V = state->getSVal(loc::MemRegionVal(R));
+ MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
}
void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred,
@@ -2964,6 +3017,26 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
CheckerVisit(B, Dst, Tmp3, false);
}
+void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ ExplodedNodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
+ const GRState *state = GetState(*I);
+
+ // Bind the temporary object to the value of the expression. Then bind
+ // the expression to the location of the object.
+ SVal V = state->getSVal(Ex);
+
+ const MemRegion *R =
+ ValMgr.getRegionManager().getCXXObjectRegion(Ex,
+ Pred->getLocationContext());
+
+ state = state->bindLoc(loc::MemRegionVal(R), V);
+ MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R)));
+ }
+}
+
//===----------------------------------------------------------------------===//
// Checker registration/lookup.
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp
index 7415fa5..051d465 100644
--- a/lib/Analysis/GRState.cpp
+++ b/lib/Analysis/GRState.cpp
@@ -267,6 +267,9 @@ bool ScanReachableSymbols::scan(SVal val) {
if (loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&val))
return scan(X->getRegion());
+ if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&val))
+ return scan(X->getLoc());
+
if (SymbolRef Sym = val.getAsSymbol())
return visitor.VisitSymbol(Sym);
diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp
index 74fe3bf..87d60d3 100644
--- a/lib/Analysis/MemRegion.cpp
+++ b/lib/Analysis/MemRegion.cpp
@@ -17,6 +17,7 @@
#include "clang/Analysis/PathSensitive/MemRegion.h"
#include "clang/Analysis/PathSensitive/ValueManager.h"
#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/StmtVisitor.h"
using namespace clang;
@@ -215,6 +216,18 @@ void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
ID.AddPointer(superRegion);
}
+void CXXThisRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const PointerType *PT,
+ const MemRegion *sRegion) {
+ ID.AddInteger((unsigned) CXXThisRegionKind);
+ ID.AddPointer(PT);
+ ID.AddPointer(sRegion);
+}
+
+void CXXThisRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion);
+}
+
void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
const MemRegion* superRegion, Kind k) {
ID.AddInteger((unsigned) k);
@@ -292,14 +305,14 @@ void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
}
void CXXObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
- QualType T,
+ Expr const *Ex,
const MemRegion *sReg) {
- ID.AddPointer(T.getTypePtr());
+ ID.AddPointer(Ex);
ID.AddPointer(sReg);
}
void CXXObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- ProfileRegion(ID, T, getSuperRegion());
+ ProfileRegion(ID, Ex, getSuperRegion());
}
//===----------------------------------------------------------------------===//
@@ -343,6 +356,10 @@ void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const {
os << "{ " << (void*) CL << " }";
}
+void CXXThisRegion::dumpToStream(llvm::raw_ostream &os) const {
+ os << "this";
+}
+
void ElementRegion::dumpToStream(llvm::raw_ostream& os) const {
os << "element{" << superRegion << ','
<< Index << ',' << getElementType().getAsString() << '}';
@@ -551,7 +568,7 @@ const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) {
return getSubRegion<SymbolicRegion>(sym, getUnknownRegion());
}
-const FieldRegion *
+const FieldRegion*
MemRegionManager::getFieldRegion(const FieldDecl* d,
const MemRegion* superRegion){
return getSubRegion<FieldRegion>(d, superRegion);
@@ -563,9 +580,22 @@ MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
return getSubRegion<ObjCIvarRegion>(d, superRegion);
}
-const CXXObjectRegion *
-MemRegionManager::getCXXObjectRegion(QualType T) {
- return getSubRegion<CXXObjectRegion>(T, getUnknownRegion());
+const CXXObjectRegion*
+MemRegionManager::getCXXObjectRegion(Expr const *E,
+ LocationContext const *LC) {
+ const StackFrameContext *SFC = LC->getCurrentStackFrame();
+ assert(SFC);
+ return getSubRegion<CXXObjectRegion>(E, getStackLocalsRegion(SFC));
+}
+
+const CXXThisRegion*
+MemRegionManager::getCXXThisRegion(QualType thisPointerTy,
+ const LocationContext *LC) {
+ const StackFrameContext *STC = LC->getCurrentStackFrame();
+ assert(STC);
+ const PointerType *PT = thisPointerTy->getAs<PointerType>();
+ assert(PT);
+ return getSubRegion<CXXThisRegion>(PT, getStackArgumentsRegion(STC));
}
const AllocaRegion*
@@ -592,20 +622,11 @@ bool MemRegion::hasStackStorage() const {
return isa<StackSpaceRegion>(getMemorySpace());
}
-bool MemRegion::hasHeapStorage() const {
- return isa<HeapSpaceRegion>(getMemorySpace());
-}
-
-bool MemRegion::hasHeapOrStackStorage() const {
- const MemSpaceRegion *MS = getMemorySpace();
- return isa<StackSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS);
-}
-
-bool MemRegion::hasGlobalsStorage() const {
- return isa<GlobalsSpaceRegion>(getMemorySpace());
+bool MemRegion::hasStackNonParametersStorage() const {
+ return isa<StackLocalsSpaceRegion>(getMemorySpace());
}
-bool MemRegion::hasParametersStorage() const {
+bool MemRegion::hasStackParametersStorage() const {
return isa<StackArgumentsSpaceRegion>(getMemorySpace());
}
@@ -669,7 +690,7 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
}
RegionRawOffset ElementRegion::getAsRawOffset() const {
- int64_t offset = 0;
+ CharUnits offset = CharUnits::Zero();
const ElementRegion *ER = this;
const MemRegion *superR = NULL;
ASTContext &C = getContext();
@@ -694,7 +715,7 @@ RegionRawOffset ElementRegion::getAsRawOffset() const {
break;
}
- int64_t size = (int64_t) (C.getTypeSize(elemType) / 8);
+ CharUnits size = C.getTypeSizeInChars(elemType);
offset += (i * size);
}
@@ -707,7 +728,7 @@ RegionRawOffset ElementRegion::getAsRawOffset() const {
}
assert(superR && "super region cannot be NULL");
- return RegionRawOffset(superR, offset);
+ return RegionRawOffset(superR, offset.getQuantity());
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/OSAtomicChecker.cpp b/lib/Analysis/OSAtomicChecker.cpp
index cf16796..9d34e9e 100644
--- a/lib/Analysis/OSAtomicChecker.cpp
+++ b/lib/Analysis/OSAtomicChecker.cpp
@@ -103,19 +103,9 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C,
SVal location = state->getSVal(theValueExpr);
// Here we should use the value type of the region as the load type.
QualType LoadTy;
- if (const MemRegion *R = location.getAsRegion()) {
- // We must be careful, as SymbolicRegions aren't typed.
- const MemRegion *strippedR = R->StripCasts();
- // FIXME: This isn't quite the right solution. One test case in 'test/Analysis/NSString.m'
- // is giving the wrong result.
- const TypedRegion *typedR =
- isa<SymbolicRegion>(strippedR) ? cast<TypedRegion>(R) :
- dyn_cast<TypedRegion>(strippedR);
-
- if (typedR) {
- LoadTy = typedR->getValueType(Ctx);
- location = loc::MemRegionVal(typedR);
- }
+ if (const TypedRegion *TR =
+ dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
+ LoadTy = TR->getValueType(Ctx);
}
Engine.EvalLoad(Tmp, const_cast<Expr *>(theValueExpr), C.getPredecessor(),
state, location, OSAtomicLoadTag, LoadTy);
@@ -184,14 +174,22 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C,
E2 = TmpStore.end(); I2 != E2; ++I2) {
ExplodedNode *predNew = *I2;
const GRState *stateNew = predNew->getState();
- SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType());
+ // Check for 'void' return type if we have a bogus function prototype.
+ SVal Res = UnknownVal();
+ QualType T = CE->getType();
+ if (!T->isVoidType())
+ Res = Engine.getValueManager().makeTruthVal(true, T);
C.GenerateNode(stateNew->BindExpr(CE, Res), predNew);
}
}
// Were they not equal?
if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) {
- SVal Res = Engine.getValueManager().makeTruthVal(false, CE->getType());
+ // Check for 'void' return type if we have a bogus function prototype.
+ SVal Res = UnknownVal();
+ QualType T = CE->getType();
+ if (!T->isVoidType())
+ Res = Engine.getValueManager().makeTruthVal(false, CE->getType());
C.GenerateNode(stateNotEqual->BindExpr(CE, Res), N);
}
}
diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp
index 7330b62..2cf3dfb 100644
--- a/lib/Analysis/RangeConstraintManager.cpp
+++ b/lib/Analysis/RangeConstraintManager.cpp
@@ -234,7 +234,8 @@ namespace {
class RangeConstraintManager : public SimpleConstraintManager{
RangeSet GetRange(const GRState *state, SymbolRef sym);
public:
- RangeConstraintManager() {}
+ RangeConstraintManager(GRSubEngine &subengine)
+ : SimpleConstraintManager(subengine) {}
const GRState* AssumeSymNE(const GRState* St, SymbolRef sym,
const llvm::APSInt& V);
@@ -273,8 +274,9 @@ private:
} // end anonymous namespace
-ConstraintManager* clang::CreateRangeConstraintManager(GRStateManager&) {
- return new RangeConstraintManager();
+ConstraintManager* clang::CreateRangeConstraintManager(GRStateManager&,
+ GRSubEngine &subeng) {
+ return new RangeConstraintManager(subeng);
}
const llvm::APSInt* RangeConstraintManager::getSymVal(const GRState* St,
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index 3bc9dcc..9b5b44b 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -28,9 +28,12 @@
using namespace clang;
-#define HEAP_UNDEFINED 0
#define USE_EXPLICIT_COMPOUND 0
+//===----------------------------------------------------------------------===//
+// Representation of value bindings.
+//===----------------------------------------------------------------------===//
+
namespace {
class BindingVal {
public:
@@ -77,8 +80,41 @@ llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingVal V) {
}
} // end llvm namespace
+//===----------------------------------------------------------------------===//
+// Representation of binding keys.
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class BindingKey : public std::pair<const MemRegion*, uint64_t> {
+public:
+ explicit BindingKey(const MemRegion *r, uint64_t offset)
+ : std::pair<const MemRegion*,uint64_t>(r, offset) { assert(r); }
+
+ const MemRegion *getRegion() const { return first; }
+ uint64_t getOffset() const { return second; }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddPointer(getRegion());
+ ID.AddInteger(getOffset());
+ }
+
+ static BindingKey Make(const MemRegion *R);
+};
+} // end anonymous namespace
+
+namespace llvm {
+ static inline
+ llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingKey K) {
+ os << '(' << K.getRegion() << ',' << K.getOffset() << ')';
+ return os;
+ }
+} // end llvm namespace
+
+//===----------------------------------------------------------------------===//
// Actual Store type.
-typedef llvm::ImmutableMap<const MemRegion*, BindingVal> RegionBindings;
+//===----------------------------------------------------------------------===//
+
+typedef llvm::ImmutableMap<BindingKey, BindingVal> RegionBindings;
//===----------------------------------------------------------------------===//
// Fine-grained control of RegionStoreManager.
@@ -283,6 +319,16 @@ private:
void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R,
RegionStoreSubRegionMap &M);
+ RegionBindings Add(RegionBindings B, BindingKey K, BindingVal V);
+ RegionBindings Add(RegionBindings B, const MemRegion *R, BindingVal V);
+
+ const BindingVal *Lookup(RegionBindings B, BindingKey K);
+ const BindingVal *Lookup(RegionBindings B, const MemRegion *R);
+
+ RegionBindings Remove(RegionBindings B, BindingKey K);
+ RegionBindings Remove(RegionBindings B, const MemRegion *R);
+ Store Remove(Store store, BindingKey K);
+
public:
const GRState *Bind(const GRState *state, Loc LV, SVal V);
@@ -308,6 +354,7 @@ public:
Store KillStruct(Store store, const TypedRegion* R);
Store Remove(Store store, Loc LV);
+
//===------------------------------------------------------------------===//
// Loading values from regions.
@@ -438,7 +485,7 @@ RegionStoreManager::getRegionStoreSubRegionMap(Store store) {
llvm::SmallVector<const SubRegion*, 10> WL;
for (RegionBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I)
- if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey()))
+ if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey().getRegion()))
M->process(WL, R);
// We also need to record in the subregion map "intermediate" regions that
@@ -467,8 +514,8 @@ void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B,
for (llvm::tie(I, E) = M.begin_end(R); I != E; ++I)
RemoveSubRegionBindings(B, *I, M);
-
- B = RBFactory.Remove(B, R);
+
+ B = Remove(B, R);
}
const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
@@ -544,8 +591,8 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
// 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,
- Count);
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ Count);
+ B = Add(B, R, BindingVal(V, BindingVal::Default));
continue;
}
@@ -566,7 +613,7 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
// conjured symbol. The type of the symbol is irrelavant.
DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
Count);
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ B = Add(B, R, BindingVal(V, BindingVal::Default));
continue;
}
@@ -574,7 +621,7 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
// Set the default value of the array to conjured symbol.
DefinedOrUnknownSVal V =
ValMgr.getConjuredSymbolVal(R, Ex, AT->getElementType(), Count);
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ B = Add(B, R, BindingVal(V, BindingVal::Default));
continue;
}
@@ -583,14 +630,14 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
// For fields and elements whose super region has also been invalidated,
// only remove the old binding. The super region will get set with a
// default value from which we can lazily derive a new symbolic value.
- B = RBFactory.Remove(B, R);
+ B = Remove(B, R);
continue;
}
// Invalidate the binding.
DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, T, Count);
assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct));
+ B = Add(B, R, BindingVal(V, BindingVal::Direct));
}
// Create a new state with the updated bindings.
@@ -723,6 +770,8 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
const MemRegion *R) {
switch (R->getKind()) {
+ case MemRegion::CXXThisRegionKind:
+ assert(0 && "Cannot get size of 'this' region");
case MemRegion::GenericMemSpaceRegionKind:
case MemRegion::StackLocalsSpaceRegionKind:
case MemRegion::StackArgumentsSpaceRegionKind:
@@ -877,6 +926,9 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
// Technically this can happen if people do funny things with casts.
return UnknownVal();
+ case MemRegion::CXXThisRegionKind:
+ assert(0 &&
+ "Cannot perform pointer arithmetic on implicit argument 'this'");
case MemRegion::GenericMemSpaceRegionKind:
case MemRegion::StackLocalsSpaceRegionKind:
case MemRegion::StackArgumentsSpaceRegionKind:
@@ -921,7 +973,7 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B,
const MemRegion *R) {
- if (const BindingVal *BV = B.lookup(R))
+ if (const BindingVal *BV = Lookup(B, R))
return Optional<SVal>::create(BV->getDirectValue());
return Optional<SVal>();
@@ -935,7 +987,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
if (TR->getValueType(getContext())->isUnionType())
return UnknownVal();
- if (BindingVal const *V = B.lookup(R))
+ if (const BindingVal *V = Lookup(B, R))
return Optional<SVal>::create(V->getDefaultValue());
return Optional<SVal>();
@@ -943,7 +995,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
Optional<SVal> RegionStoreManager::getBinding(RegionBindings B,
const MemRegion *R) {
- if (const BindingVal *BV = B.lookup(R))
+ if (const BindingVal *BV = Lookup(B, R))
return Optional<SVal>::create(BV->getValue());
return Optional<SVal>();
@@ -1051,22 +1103,46 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveField(state, FR), FR, T));
-
- if (const ElementRegion* ER = dyn_cast<ElementRegion>(R))
+ CastRetrievedVal(RetrieveField(state, FR), FR,
+ T, false));
+
+ if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) {
+ // FIXME: Here we actually perform an implicit conversion from the loaded
+ // value to the element type. Eventually we want to compose these values
+ // more intelligently. For example, an 'element' can encompass multiple
+ // bound regions (e.g., several bound bytes), or could be a subset of
+ // a larger value.
return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveElement(state, ER), ER, T));
-
- if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R))
+ CastRetrievedVal(RetrieveElement(state, ER),
+ ER, T, false));
+ }
+
+ if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
+ // FIXME: Here we actually perform an implicit conversion from the loaded
+ // value to the ivar type. What we should model is stores to ivars
+ // that blow past the extent of the ivar. If the address of the ivar is
+ // reinterpretted, it is possible we stored a different value that could
+ // fit within the ivar. Either we need to cast these when storing them
+ // or reinterpret them lazily (as we do here).
return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveObjCIvar(state, IVR), IVR, T));
+ CastRetrievedVal(RetrieveObjCIvar(state, IVR),
+ IVR, T, false));
+ }
- if (const VarRegion *VR = dyn_cast<VarRegion>(R))
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ // FIXME: Here we actually perform an implicit conversion from the loaded
+ // value to the variable type. What we should model is stores to variables
+ // that blow past the extent of the variable. If the address of the
+ // variable is reinterpretted, it is possible we stored a different value
+ // that could fit within the variable. Either we need to cast these when
+ // storing them or reinterpret them lazily (as we do here).
return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveVar(state, VR), VR, T));
+ CastRetrievedVal(RetrieveVar(state, VR), VR, T,
+ false));
+ }
RegionBindings B = GetRegionBindings(state->getStore());
- RegionBindings::data_type* V = B.lookup(R);
+ const BindingVal *V = Lookup(B, R);
// Check if the region has a binding.
if (V)
@@ -1076,12 +1152,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
// The location does not have a bound value. This means that it has
// the value it had upon its creation and/or entry to the analyzed
// function/method. These are either symbolic values or 'undefined'.
-
-#if HEAP_UNDEFINED
- if (R->hasHeapOrStackStorage()) {
-#else
- if (R->hasStackStorage()) {
-#endif
+ if (R->hasStackNonParametersStorage()) {
// All stack variables are considered to have undefined values
// upon creation. All heap allocated blocks are considered to
// have undefined values as well unless they are explicitly bound
@@ -1124,7 +1195,7 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state,
const ElementRegion* R) {
// Check if the region has a binding.
RegionBindings B = GetRegionBindings(state->getStore());
- if (Optional<SVal> V = getDirectBinding(B, R))
+ if (Optional<SVal> V = getDirectBinding(B, R))
return *V;
const MemRegion* superR = R->getSuperRegion();
@@ -1174,7 +1245,7 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state,
// Other cases: give up.
return UnknownVal();
}
-
+
return RetrieveFieldOrElementCommon(state, R, R->getElementType(), superR);
}
@@ -1240,8 +1311,7 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state,
cast<FieldRegion>(lazyBindingRegion));
}
- if (R->hasStackStorage() && !R->hasParametersStorage()) {
-
+ if (R->hasStackNonParametersStorage()) {
if (isa<ElementRegion>(R)) {
// Currently we don't reason specially about Clang-style vectors. Check
// if superR is a vector and if so return Unknown.
@@ -1369,15 +1439,9 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state,
//===----------------------------------------------------------------------===//
Store RegionStoreManager::Remove(Store store, Loc L) {
- const MemRegion* R = 0;
-
if (isa<loc::MemRegionVal>(L))
- R = cast<loc::MemRegionVal>(L).getRegion();
-
- if (R) {
- RegionBindings B = GetRegionBindings(store);
- return RBFactory.Remove(B, R).getRoot();
- }
+ if (const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion())
+ return Remove(store, BindingKey::Make(R));
return store;
}
@@ -1436,8 +1500,8 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
// Perform the binding.
RegionBindings B = GetRegionBindings(state->getStore());
- return state->makeWithStore(
- RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot());
+ return state->makeWithStore(Add(B, R,
+ BindingVal(V, BindingVal::Direct)).getRoot());
}
const GRState *RegionStoreManager::BindDecl(const GRState *ST,
@@ -1483,9 +1547,9 @@ const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state,
else {
return state;
}
-
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
- return state->makeWithStore(B.getRoot());
+
+ return state->makeWithStore(Add(B, R,
+ BindingVal(V, BindingVal::Default)).getRoot());
}
const GRState *RegionStoreManager::BindArray(const GRState *state,
@@ -1610,8 +1674,7 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
if (FI != FE) {
Store store = state->getStore();
RegionBindings B = GetRegionBindings(store);
- B = RBFactory.Add(B, R,
- BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default));
+ B = Add(B, R, BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default));
state = state->makeWithStore(B.getRoot());
}
@@ -1625,7 +1688,7 @@ Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) {
RemoveSubRegionBindings(B, R, *SubRegions);
// Set the default value of the struct region to "unknown".
- B = RBFactory.Add(B, R, BindingVal(UnknownVal(), BindingVal::Default));
+ B = Add(B, R, BindingVal(UnknownVal(), BindingVal::Default));
return B.getRoot();
}
@@ -1646,8 +1709,58 @@ RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
// Now copy the bindings. This amounts to just binding 'V' to 'R'. This
// results in a zero-copy algorithm.
- return state->makeWithStore(
- RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot());
+ return state->makeWithStore(Add(B, R,
+ BindingVal(V, BindingVal::Direct)).getRoot());
+}
+
+//===----------------------------------------------------------------------===//
+// "Raw" retrievals and bindings.
+//===----------------------------------------------------------------------===//
+
+BindingKey BindingKey::Make(const MemRegion *R) {
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ const RegionRawOffset &O = ER->getAsRawOffset();
+
+ if (O.getRegion())
+ return BindingKey(O.getRegion(), O.getByteOffset());
+
+ // FIXME: There are some ElementRegions for which we cannot compute
+ // raw offsets yet, including regions with symbolic offsets.
+ }
+
+ return BindingKey(R, 0);
+}
+
+RegionBindings RegionStoreManager::Add(RegionBindings B, BindingKey K,
+ BindingVal V) {
+ return RBFactory.Add(B, K, V);
+}
+
+RegionBindings RegionStoreManager::Add(RegionBindings B, const MemRegion *R,
+ BindingVal V) {
+ return Add(B, BindingKey::Make(R), V);
+}
+
+const BindingVal *RegionStoreManager::Lookup(RegionBindings B, BindingKey K) {
+ return B.lookup(K);
+}
+
+const BindingVal *RegionStoreManager::Lookup(RegionBindings B,
+ const MemRegion *R) {
+ return Lookup(B, BindingKey::Make(R));
+}
+
+RegionBindings RegionStoreManager::Remove(RegionBindings B, BindingKey K) {
+ return RBFactory.Remove(B, K);
+}
+
+RegionBindings RegionStoreManager::Remove(RegionBindings B, const MemRegion *R){
+ return Remove(B, BindingKey::Make(R));
+}
+
+Store RegionStoreManager::Remove(Store store, BindingKey K) {
+ RegionBindings B = GetRegionBindings(store);
+ return Remove(B, K).getRoot();
}
//===----------------------------------------------------------------------===//
@@ -1674,7 +1787,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
// Scan the direct bindings for "intermediate" roots.
for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- const MemRegion *R = I.getKey();
+ const MemRegion *R = I.getKey().getRegion();
IntermediateRoots.push_back(R);
}
@@ -1831,13 +1944,13 @@ tryAgain:
// as live. We now remove all the regions that are dead from the store
// as well as update DSymbols with the set symbols that are now dead.
for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- const MemRegion* R = I.getKey();
+ const MemRegion* R = I.getKey().getRegion();
// If this region live? Is so, none of its symbols are dead.
if (Visited.count(std::make_pair(&state, R)))
continue;
// Remove this dead region from the store.
- store = Remove(store, ValMgr.makeLoc(R));
+ store = Remove(store, I.getKey());
// Mark all non-live symbols that this region references as dead.
if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
diff --git a/lib/Analysis/ReturnStackAddressChecker.cpp b/lib/Analysis/ReturnStackAddressChecker.cpp
index 3a6d8a4..4d7e8ad 100644
--- a/lib/Analysis/ReturnStackAddressChecker.cpp
+++ b/lib/Analysis/ReturnStackAddressChecker.cpp
@@ -67,6 +67,9 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
llvm::raw_svector_ostream os(buf);
SourceRange range;
+ // Get the base region, stripping away fields and elements.
+ R = R->getBaseRegion();
+
// Check if the region is a compound literal.
if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
const CompoundLiteralExpr* CL = CR->getLiteralExpr();
@@ -92,13 +95,18 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
<< C.getSourceManager().getInstantiationLineNumber(L)
<< " returned to caller";
}
- else {
+ else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
os << "Address of stack memory associated with local variable '"
- << R->getString() << "' returned.";
+ << VR->getString() << "' returned";
+ range = VR->getDecl()->getSourceRange();
+ }
+ else {
+ assert(false && "Invalid region in ReturnStackAddressChecker.");
+ return;
}
RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
- report->addRange(RS->getSourceRange());
+ report->addRange(RetE->getSourceRange());
if (range.isValid())
report->addRange(range);
diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp
index 9163b27..fbdb73b 100644
--- a/lib/Analysis/SVals.cpp
+++ b/lib/Analysis/SVals.cpp
@@ -97,6 +97,10 @@ const MemRegion *SVal::getAsRegion() const {
if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this))
return X->getRegion();
+ if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this)) {
+ return X->getLoc().getAsRegion();
+ }
+
return 0;
}
diff --git a/lib/Analysis/SValuator.cpp b/lib/Analysis/SValuator.cpp
index 49bc0c4..8392fcf 100644
--- a/lib/Analysis/SValuator.cpp
+++ b/lib/Analysis/SValuator.cpp
@@ -62,8 +62,12 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
ASTContext &C = ValMgr.getContext();
// For const casts, just propagate the value.
- if (C.hasSameUnqualifiedType(castTy, originalTy))
- return CastResult(state, val);
+ if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType())
+ if (C.hasSameUnqualifiedType(castTy, originalTy))
+ return CastResult(state, val);
+
+ if (castTy->isIntegerType() && originalTy->isIntegerType())
+ return CastResult(state, EvalCastNL(cast<NonLoc>(val), castTy));
// Check for casts from pointers to integers.
if (castTy->isIntegerType() && Loc::IsLocType(originalTy))
diff --git a/lib/Analysis/SimpleConstraintManager.cpp b/lib/Analysis/SimpleConstraintManager.cpp
index 23c3b41..eca20d5 100644
--- a/lib/Analysis/SimpleConstraintManager.cpp
+++ b/lib/Analysis/SimpleConstraintManager.cpp
@@ -65,25 +65,10 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state,
return Assume(state, cast<Loc>(Cond), Assumption);
}
-const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc Cond,
- bool Assumption) {
-
- state = AssumeAux(state, Cond, Assumption);
-
- // 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.
-
- 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::Assume(const GRState *state, Loc cond,
+ bool assumption) {
+ state = AssumeAux(state, cond, assumption);
+ return SU.ProcessAssume(state, cond, assumption);
}
const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
@@ -130,26 +115,10 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
}
const GRState *SimpleConstraintManager::Assume(const GRState *state,
- NonLoc Cond,
- bool Assumption) {
-
- state = AssumeAux(state, Cond, Assumption);
-
- // 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.
-
- 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);
+ NonLoc cond,
+ bool assumption) {
+ state = AssumeAux(state, cond, assumption);
+ return SU.ProcessAssume(state, cond, assumption);
}
const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
diff --git a/lib/Analysis/SimpleConstraintManager.h b/lib/Analysis/SimpleConstraintManager.h
index 0c58440..8182398 100644
--- a/lib/Analysis/SimpleConstraintManager.h
+++ b/lib/Analysis/SimpleConstraintManager.h
@@ -20,8 +20,9 @@
namespace clang {
class SimpleConstraintManager : public ConstraintManager {
+ GRSubEngine &SU;
public:
- SimpleConstraintManager() {}
+ SimpleConstraintManager(GRSubEngine &subengine) : SU(subengine) {}
virtual ~SimpleConstraintManager();
//===------------------------------------------------------------------===//
diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp
index 2afcd3e..8f2f5a1 100644
--- a/lib/Analysis/SimpleSValuator.cpp
+++ b/lib/Analysis/SimpleSValuator.cpp
@@ -53,13 +53,13 @@ SVal SimpleSValuator::EvalCastNL(NonLoc val, QualType castTy) {
if (isLocType)
return LI->getLoc();
+ // FIXME: Correctly support promotions/truncations.
ASTContext &Ctx = ValMgr.getContext();
-
- // FIXME: Support promotions/truncations.
- if (Ctx.getTypeSize(castTy) == Ctx.getTypeSize(Ctx.VoidPtrTy))
+ unsigned castSize = Ctx.getTypeSize(castTy);
+ if (castSize == LI->getNumBits())
return val;
- return UnknownVal();
+ return ValMgr.makeLocAsInteger(LI->getLoc(), castSize);
}
if (const SymExpr *se = val.getAsSymbolicExpression()) {
diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp
index 8d911b8..1724a92 100644
--- a/lib/Analysis/Store.cpp
+++ b/lib/Analysis/Store.cpp
@@ -13,6 +13,7 @@
#include "clang/Analysis/PathSensitive/Store.h"
#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/AST/CharUnits.h"
using namespace clang;
@@ -77,6 +78,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
// Process region cast according to the kind of the region being cast.
switch (R->getKind()) {
+ case MemRegion::CXXThisRegionKind:
case MemRegion::GenericMemSpaceRegionKind:
case MemRegion::StackLocalsSpaceRegionKind:
case MemRegion::StackArgumentsSpaceRegionKind:
@@ -137,9 +139,9 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
if (!baseR)
return NULL;
- int64_t off = rawOff.getByteOffset();
+ CharUnits off = CharUnits::fromQuantity(rawOff.getByteOffset());
- if (off == 0) {
+ if (off.isZero()) {
// Edge case: we are at 0 bytes off the beginning of baseR. We
// check to see if type we are casting to is the same as the base
// region. If so, just return the base region.
@@ -167,7 +169,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
// We can only compute sizeof(PointeeTy) if it is a complete type.
if (IsCompleteType(Ctx, PointeeTy)) {
// Compute the size in **bytes**.
- int64_t pointeeTySize = (int64_t) (Ctx.getTypeSize(PointeeTy) / 8);
+ CharUnits pointeeTySize = Ctx.getTypeSizeInChars(PointeeTy);
// Is the offset a multiple of the size? If so, we can layer the
// ElementRegion (with elementType == PointeeTy) directly on top of
@@ -181,7 +183,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
if (!newSuperR) {
// Create an intermediate ElementRegion to represent the raw byte.
// This will be the super region of the final ElementRegion.
- newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off);
+ newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off.getQuantity());
}
return MakeElementRegion(newSuperR, PointeeTy, newIndex);
@@ -196,23 +198,29 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
/// as another region.
-SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
- QualType castTy) {
+SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
+ QualType castTy, bool performTestOnly) {
-#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
+ if (performTestOnly) {
+ // Automatically translate references to pointers.
+ QualType T = R->getValueType(Ctx);
+ if (const ReferenceType *RT = T->getAs<ReferenceType>())
+ T = Ctx.getPointerType(RT->getPointeeType());
+
+ assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, T));
+ return V;
+ }
+
+ if (const Loc *L = dyn_cast<Loc>(&V))
+ return ValMgr.getSValuator().EvalCastL(*L, castTy);
+ else if (const NonLoc *NL = dyn_cast<NonLoc>(&V))
+ return ValMgr.getSValuator().EvalCastNL(*NL, castTy);
+
return V;
}
@@ -240,8 +248,3 @@ 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 4351f66..abbf6f9 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -541,19 +541,46 @@ static bool ModifierIs(const char *Modifier, unsigned ModifierLen,
return StrLen-1 == ModifierLen && !memcmp(Modifier, Str, StrLen-1);
}
+/// ScanForward - Scans forward, looking for the given character, skipping
+/// nested clauses and escaped characters.
+static const char *ScanFormat(const char *I, const char *E, char Target) {
+ unsigned Depth = 0;
+
+ for ( ; I != E; ++I) {
+ if (Depth == 0 && *I == Target) return I;
+ if (Depth != 0 && *I == '}') Depth--;
+
+ if (*I == '%') {
+ I++;
+ if (I == E) break;
+
+ // Escaped characters get implicitly skipped here.
+
+ // Format specifier.
+ if (!isdigit(*I) && !ispunct(*I)) {
+ for (I++; I != E && !isdigit(*I) && *I != '{'; I++) ;
+ if (I == E) break;
+ if (*I == '{')
+ Depth++;
+ }
+ }
+ }
+ return E;
+}
+
/// HandleSelectModifier - Handle the integer 'select' modifier. This is used
/// like this: %select{foo|bar|baz}2. This means that the integer argument
/// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'.
/// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'.
/// This is very useful for certain classes of variant diagnostics.
-static void HandleSelectModifier(unsigned ValNo,
+static void HandleSelectModifier(const DiagnosticInfo &DInfo, unsigned ValNo,
const char *Argument, unsigned ArgumentLen,
llvm::SmallVectorImpl<char> &OutStr) {
const char *ArgumentEnd = Argument+ArgumentLen;
// Skip over 'ValNo' |'s.
while (ValNo) {
- const char *NextVal = std::find(Argument, ArgumentEnd, '|');
+ const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|');
assert(NextVal != ArgumentEnd && "Value for integer select modifier was"
" larger than the number of options in the diagnostic string!");
Argument = NextVal+1; // Skip this string.
@@ -561,9 +588,10 @@ static void HandleSelectModifier(unsigned ValNo,
}
// Get the end of the value. This is either the } or the |.
- const char *EndPtr = std::find(Argument, ArgumentEnd, '|');
- // Add the value to the output string.
- OutStr.append(Argument, EndPtr);
+ const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|');
+
+ // Recursively format the result of the select clause into the output string.
+ DInfo.FormatDiagnostic(Argument, EndPtr, OutStr);
}
/// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the
@@ -575,6 +603,37 @@ static void HandleIntegerSModifier(unsigned ValNo,
OutStr.push_back('s');
}
+/// HandleOrdinalModifier - Handle the integer 'ord' modifier. This
+/// prints the ordinal form of the given integer, with 1 corresponding
+/// to the first ordinal. Currently this is hard-coded to use the
+/// English form.
+static void HandleOrdinalModifier(unsigned ValNo,
+ llvm::SmallVectorImpl<char> &OutStr) {
+ assert(ValNo != 0 && "ValNo must be strictly positive!");
+
+ llvm::raw_svector_ostream Out(OutStr);
+
+ // We could use text forms for the first N ordinals, but the numeric
+ // forms are actually nicer in diagnostics because they stand out.
+ Out << ValNo;
+
+ // It is critically important that we do this perfectly for
+ // user-written sequences with over 100 elements.
+ switch (ValNo % 100) {
+ case 11:
+ case 12:
+ case 13:
+ Out << "th"; return;
+ default:
+ switch (ValNo % 10) {
+ case 1: Out << "st"; return;
+ case 2: Out << "nd"; return;
+ case 3: Out << "rd"; return;
+ default: Out << "th"; return;
+ }
+ }
+}
+
/// PluralNumber - Parse an unsigned integer and advance Start.
static unsigned PluralNumber(const char *&Start, const char *End) {
@@ -685,11 +744,11 @@ static void HandlePluralModifier(unsigned ValNo,
}
if (EvalPluralExpr(ValNo, Argument, ExprEnd)) {
Argument = ExprEnd + 1;
- ExprEnd = std::find(Argument, ArgumentEnd, '|');
+ ExprEnd = ScanFormat(Argument, ArgumentEnd, '|');
OutStr.append(Argument, ExprEnd);
return;
}
- Argument = std::find(Argument, ArgumentEnd - 1, '|') + 1;
+ Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1;
}
}
@@ -702,6 +761,13 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
const char *DiagStr = getDiags()->getDescription(getID());
const char *DiagEnd = DiagStr+strlen(DiagStr);
+ FormatDiagnostic(DiagStr, DiagEnd, OutStr);
+}
+
+void DiagnosticInfo::
+FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
+ llvm::SmallVectorImpl<char> &OutStr) const {
+
/// FormattedArgs - Keep track of all of the arguments formatted by
/// ConvertArgToString and pass them into subsequent calls to
/// ConvertArgToString, allowing the implementation to avoid redundancies in
@@ -715,8 +781,8 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
OutStr.append(DiagStr, StrEnd);
DiagStr = StrEnd;
continue;
- } else if (DiagStr[1] == '%') {
- OutStr.push_back('%'); // %% -> %.
+ } else if (ispunct(DiagStr[1])) {
+ OutStr.push_back(DiagStr[1]); // %% -> %.
DiagStr += 2;
continue;
}
@@ -745,8 +811,8 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
++DiagStr; // Skip {.
Argument = DiagStr;
- for (; DiagStr[0] != '}'; ++DiagStr)
- assert(DiagStr[0] && "Mismatched {}'s in diagnostic string!");
+ DiagStr = ScanFormat(DiagStr, DiagEnd, '}');
+ assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!");
ArgumentLen = DiagStr-Argument;
++DiagStr; // Skip }.
}
@@ -781,11 +847,13 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
int Val = getArgSInt(ArgNo);
if (ModifierIs(Modifier, ModifierLen, "select")) {
- HandleSelectModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
+ HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen, OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "s")) {
HandleIntegerSModifier(Val, OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "plural")) {
HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
+ } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
+ HandleOrdinalModifier((unsigned)Val, OutStr);
} else {
assert(ModifierLen == 0 && "Unknown integer modifier");
llvm::raw_svector_ostream(OutStr) << Val;
@@ -796,11 +864,13 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
unsigned Val = getArgUInt(ArgNo);
if (ModifierIs(Modifier, ModifierLen, "select")) {
- HandleSelectModifier(Val, Argument, ArgumentLen, OutStr);
+ HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "s")) {
HandleIntegerSModifier(Val, OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "plural")) {
HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
+ } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
+ HandleOrdinalModifier(Val, OutStr);
} else {
assert(ModifierLen == 0 && "Unknown integer modifier");
llvm::raw_svector_ostream(OutStr) << Val;
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index b6b5c6c..bba2c3f 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -18,51 +18,38 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetOptions.h"
+#include "clang/Frontend/Utils.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/MC/MCSectionMachO.h"
+#include <algorithm>
using namespace clang;
//===----------------------------------------------------------------------===//
// Common code shared among targets.
//===----------------------------------------------------------------------===//
-static void Define(std::vector<char> &Buf, const llvm::StringRef &Macro,
- const llvm::StringRef &Val = "1") {
- const char *Def = "#define ";
- Buf.insert(Buf.end(), Def, Def+strlen(Def));
- Buf.insert(Buf.end(), Macro.begin(), Macro.end());
- Buf.push_back(' ');
- Buf.insert(Buf.end(), Val.begin(), Val.end());
- Buf.push_back('\n');
-}
-
/// DefineStd - Define a macro name and standard variants. For example if
/// MacroName is "unix", then this will define "__unix", "__unix__", and "unix"
/// when in GNU mode.
-static void DefineStd(std::vector<char> &Buf, const char *MacroName,
+static void DefineStd(MacroBuilder &Builder, llvm::StringRef MacroName,
const LangOptions &Opts) {
assert(MacroName[0] != '_' && "Identifier should be in the user's namespace");
// If in GNU mode (e.g. -std=gnu99 but not -std=c99) define the raw identifier
// in the user's namespace.
if (Opts.GNUMode)
- Define(Buf, MacroName);
+ Builder.defineMacro(MacroName);
// Define __unix.
- llvm::SmallString<20> TmpStr;
- TmpStr = "__";
- TmpStr += MacroName;
- Define(Buf, TmpStr.str());
+ Builder.defineMacro("__" + MacroName);
// Define __unix__.
- TmpStr += "__";
- Define(Buf, TmpStr.str());
+ Builder.defineMacro("__" + MacroName + "__");
}
//===----------------------------------------------------------------------===//
@@ -74,44 +61,44 @@ template<typename TgtInfo>
class OSTargetInfo : public TgtInfo {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defines) const=0;
+ MacroBuilder &Builder) const=0;
public:
OSTargetInfo(const std::string& triple) : TgtInfo(triple) {}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- TgtInfo::getTargetDefines(Opts, Defines);
- getOSDefines(Opts, TgtInfo::getTriple(), Defines);
+ MacroBuilder &Builder) const {
+ TgtInfo::getTargetDefines(Opts, Builder);
+ getOSDefines(Opts, TgtInfo::getTriple(), Builder);
}
};
} // end anonymous namespace
-static void getDarwinDefines(std::vector<char> &Defs, const LangOptions &Opts) {
- Define(Defs, "__APPLE_CC__", "5621");
- Define(Defs, "__APPLE__");
- Define(Defs, "__MACH__");
- Define(Defs, "OBJC_NEW_PROPERTIES");
+static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts) {
+ Builder.defineMacro("__APPLE_CC__", "5621");
+ Builder.defineMacro("__APPLE__");
+ Builder.defineMacro("__MACH__");
+ Builder.defineMacro("OBJC_NEW_PROPERTIES");
// __weak is always defined, for use in blocks and with objc pointers.
- Define(Defs, "__weak", "__attribute__((objc_gc(weak)))");
+ Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
// Darwin defines __strong even in C mode (just to nothing).
if (!Opts.ObjC1 || Opts.getGCMode() == LangOptions::NonGC)
- Define(Defs, "__strong", "");
+ Builder.defineMacro("__strong", "");
else
- Define(Defs, "__strong", "__attribute__((objc_gc(strong)))");
+ Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))");
if (Opts.Static)
- Define(Defs, "__STATIC__");
+ Builder.defineMacro("__STATIC__");
else
- Define(Defs, "__DYNAMIC__");
+ Builder.defineMacro("__DYNAMIC__");
if (Opts.POSIXThreads)
- Define(Defs, "_REENTRANT", "1");
+ Builder.defineMacro("_REENTRANT");
}
-static void getDarwinOSXDefines(std::vector<char> &Defs,
+static void getDarwinOSXDefines(MacroBuilder &Builder,
const llvm::Triple &Triple) {
if (Triple.getOS() != llvm::Triple::Darwin)
return;
@@ -129,10 +116,11 @@ static void getDarwinOSXDefines(std::vector<char> &Defs,
// Handle minor version: 10.4.9 -> darwin8.9 -> "1049"
// Cap 10.4.11 -> darwin8.11 -> "1049"
MacOSXStr[3] = std::min(Min, 9U)+'0';
- Define(Defs, "__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", MacOSXStr);
+ Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__",
+ MacOSXStr);
}
-static void getDarwinIPhoneOSDefines(std::vector<char> &Defs,
+static void getDarwinIPhoneOSDefines(MacroBuilder &Builder,
const llvm::Triple &Triple) {
if (Triple.getOS() != llvm::Triple::Darwin)
return;
@@ -151,8 +139,8 @@ static void getDarwinIPhoneOSDefines(std::vector<char> &Defs,
// Handle minor version: 2.2 -> darwin9.2.2 -> 20200
iPhoneOSStr[2] = std::min(Rev, 9U)+'0';
- Define(Defs, "__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__",
- iPhoneOSStr);
+ Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__",
+ iPhoneOSStr);
}
namespace {
@@ -160,9 +148,9 @@ template<typename Target>
class DarwinTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defines) const {
- getDarwinDefines(Defines, Opts);
- getDarwinOSXDefines(Defines, Triple);
+ MacroBuilder &Builder) const {
+ getDarwinDefines(Builder, Opts);
+ getDarwinOSXDefines(Builder, Triple);
}
public:
@@ -190,14 +178,14 @@ template<typename Target>
class DragonFlyBSDTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// DragonFly defines; list based off of gcc output
- Define(Defs, "__DragonFly__");
- Define(Defs, "__DragonFly_cc_version", "100001");
- Define(Defs, "__ELF__");
- Define(Defs, "__KPRINTF_ATTRIBUTE__");
- Define(Defs, "__tune_i386__");
- DefineStd(Defs, "unix", Opts);
+ Builder.defineMacro("__DragonFly__");
+ Builder.defineMacro("__DragonFly_cc_version", "100001");
+ Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
+ Builder.defineMacro("__tune_i386__");
+ DefineStd(Builder, "unix", Opts);
}
public:
DragonFlyBSDTargetInfo(const std::string &triple)
@@ -209,7 +197,7 @@ template<typename Target>
class FreeBSDTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// FreeBSD defines; list based off of gcc output
// FIXME: Move version number handling to llvm::Triple.
@@ -221,11 +209,11 @@ protected:
char version[] = "X00001";
version[0] = FreeBSD[0];
- Define(Defs, "__FreeBSD__", release);
- Define(Defs, "__FreeBSD_cc_version", version);
- Define(Defs, "__KPRINTF_ATTRIBUTE__");
- DefineStd(Defs, "unix", Opts);
- Define(Defs, "__ELF__", "1");
+ Builder.defineMacro("__FreeBSD__", release);
+ Builder.defineMacro("__FreeBSD_cc_version", version);
+ Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
}
public:
FreeBSDTargetInfo(const std::string &triple)
@@ -239,14 +227,14 @@ template<typename Target>
class LinuxTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// Linux defines; list based off of gcc output
- DefineStd(Defs, "unix", Opts);
- DefineStd(Defs, "linux", Opts);
- Define(Defs, "__gnu_linux__");
- Define(Defs, "__ELF__", "1");
+ DefineStd(Builder, "unix", Opts);
+ DefineStd(Builder, "linux", Opts);
+ Builder.defineMacro("__gnu_linux__");
+ Builder.defineMacro("__ELF__");
if (Opts.POSIXThreads)
- Define(Defs, "_REENTRANT", "1");
+ Builder.defineMacro("_REENTRANT");
}
public:
LinuxTargetInfo(const std::string& triple)
@@ -260,13 +248,13 @@ template<typename Target>
class NetBSDTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// NetBSD defines; list based off of gcc output
- Define(Defs, "__NetBSD__", "1");
- Define(Defs, "__unix__", "1");
- Define(Defs, "__ELF__", "1");
+ Builder.defineMacro("__NetBSD__");
+ Builder.defineMacro("__unix__");
+ Builder.defineMacro("__ELF__");
if (Opts.POSIXThreads)
- Define(Defs, "_POSIX_THREADS", "1");
+ Builder.defineMacro("_POSIX_THREADS");
}
public:
NetBSDTargetInfo(const std::string &triple)
@@ -280,14 +268,14 @@ template<typename Target>
class OpenBSDTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// OpenBSD defines; list based off of gcc output
- Define(Defs, "__OpenBSD__", "1");
- DefineStd(Defs, "unix", Opts);
- Define(Defs, "__ELF__", "1");
+ Builder.defineMacro("__OpenBSD__");
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
if (Opts.POSIXThreads)
- Define(Defs, "_POSIX_THREADS", "1");
+ Builder.defineMacro("_POSIX_THREADS");
}
public:
OpenBSDTargetInfo(const std::string &triple)
@@ -299,12 +287,12 @@ template<typename Target>
class PSPTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// PSP defines; list based on the output of the pspdev gcc toolchain.
- Define(Defs, "PSP", "1");
- Define(Defs, "_PSP", "1");
- Define(Defs, "__psp__", "1");
- Define(Defs, "__ELF__", "1");
+ Builder.defineMacro("PSP");
+ Builder.defineMacro("_PSP");
+ Builder.defineMacro("__psp__");
+ Builder.defineMacro("__ELF__");
}
public:
PSPTargetInfo(const std::string& triple)
@@ -318,12 +306,12 @@ template<typename Target>
class PS3PPUTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// PS3 PPU defines.
- Define(Defs, "__PPU__", "1");
- Define(Defs, "__CELLOS_LV2__", "1");
- Define(Defs, "__ELF__", "1");
- Define(Defs, "__LP32__", "1");
+ Builder.defineMacro("__PPU__");
+ Builder.defineMacro("__CELLOS_LV2__");
+ Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__LP32__");
}
public:
PS3PPUTargetInfo(const std::string& triple)
@@ -340,10 +328,10 @@ template<typename Target>
class PS3SPUTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// PS3 PPU defines.
- Define(Defs, "__SPU__", "1");
- Define(Defs, "__ELF__", "1");
+ Builder.defineMacro("__SPU__");
+ Builder.defineMacro("__ELF__");
}
public:
PS3SPUTargetInfo(const std::string& triple)
@@ -357,12 +345,12 @@ template<typename Target>
class AuroraUXTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
- DefineStd(Defs, "sun", Opts);
- DefineStd(Defs, "unix", Opts);
- Define(Defs, "__ELF__");
- Define(Defs, "__svr4__");
- Define(Defs, "__SVR4");
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "sun", Opts);
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__svr4__");
+ Builder.defineMacro("__SVR4");
}
public:
AuroraUXTargetInfo(const std::string& triple)
@@ -378,12 +366,12 @@ template<typename Target>
class SolarisTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
- DefineStd(Defs, "sun", Opts);
- DefineStd(Defs, "unix", Opts);
- Define(Defs, "__ELF__");
- Define(Defs, "__svr4__");
- Define(Defs, "__SVR4");
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "sun", Opts);
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__svr4__");
+ Builder.defineMacro("__SVR4");
}
public:
SolarisTargetInfo(const std::string& triple)
@@ -416,7 +404,7 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const;
+ MacroBuilder &Builder) const;
virtual const char *getVAListDeclaration() const {
return "typedef char* __builtin_va_list;";
@@ -460,34 +448,34 @@ const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
/// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific
/// #defines that are not tied to a specific subtarget.
void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// Target identification.
- Define(Defs, "__ppc__");
- Define(Defs, "_ARCH_PPC");
- Define(Defs, "__POWERPC__");
+ Builder.defineMacro("__ppc__");
+ Builder.defineMacro("_ARCH_PPC");
+ Builder.defineMacro("__POWERPC__");
if (PointerWidth == 64) {
- Define(Defs, "_ARCH_PPC64");
- Define(Defs, "_LP64");
- Define(Defs, "__LP64__");
- Define(Defs, "__ppc64__");
+ Builder.defineMacro("_ARCH_PPC64");
+ Builder.defineMacro("_LP64");
+ Builder.defineMacro("__LP64__");
+ Builder.defineMacro("__ppc64__");
} else {
- Define(Defs, "__ppc__");
+ Builder.defineMacro("__ppc__");
}
// Target properties.
- Define(Defs, "_BIG_ENDIAN");
- Define(Defs, "__BIG_ENDIAN__");
+ Builder.defineMacro("_BIG_ENDIAN");
+ Builder.defineMacro("__BIG_ENDIAN__");
// Subtarget options.
- Define(Defs, "__NATURAL_ALIGNMENT__");
- Define(Defs, "__REGISTER_PREFIX__", "");
+ Builder.defineMacro("__NATURAL_ALIGNMENT__");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
// FIXME: Should be controlled by command line option.
- Define(Defs, "__LONG_DOUBLE_128__");
+ Builder.defineMacro("__LONG_DOUBLE_128__");
if (Opts.AltiVec) {
- Define(Defs, "__VEC__", "10206");
- Define(Defs, "__ALTIVEC__", "1");
+ Builder.defineMacro("__VEC__", "10206");
+ Builder.defineMacro("__ALTIVEC__");
}
}
@@ -682,7 +670,7 @@ public:
return "~{dirflag},~{fpsr},~{flags}";
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const;
+ MacroBuilder &Builder) const;
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
const std::string &Name,
bool Enabled) const;
@@ -828,51 +816,51 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
/// X86TargetInfo::getTargetDefines - Return a set of the X86-specific #defines
/// that are not tied to a specific subtarget.
void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// Target identification.
if (PointerWidth == 64) {
- Define(Defs, "_LP64");
- Define(Defs, "__LP64__");
- Define(Defs, "__amd64__");
- Define(Defs, "__amd64");
- Define(Defs, "__x86_64");
- Define(Defs, "__x86_64__");
+ Builder.defineMacro("_LP64");
+ Builder.defineMacro("__LP64__");
+ Builder.defineMacro("__amd64__");
+ Builder.defineMacro("__amd64");
+ Builder.defineMacro("__x86_64");
+ Builder.defineMacro("__x86_64__");
} else {
- DefineStd(Defs, "i386", Opts);
+ DefineStd(Builder, "i386", Opts);
}
// Target properties.
- Define(Defs, "__LITTLE_ENDIAN__");
+ Builder.defineMacro("__LITTLE_ENDIAN__");
// Subtarget options.
- Define(Defs, "__nocona");
- Define(Defs, "__nocona__");
- Define(Defs, "__tune_nocona__");
- Define(Defs, "__REGISTER_PREFIX__", "");
+ Builder.defineMacro("__nocona");
+ Builder.defineMacro("__nocona__");
+ Builder.defineMacro("__tune_nocona__");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
// Define __NO_MATH_INLINES on linux/x86 so that we don't get inline
// functions in glibc header files that use FP Stack inline asm which the
// backend can't deal with (PR879).
- Define(Defs, "__NO_MATH_INLINES");
+ Builder.defineMacro("__NO_MATH_INLINES");
// Each case falls through to the previous one here.
switch (SSELevel) {
case SSE42:
- Define(Defs, "__SSE4_2__");
+ Builder.defineMacro("__SSE4_2__");
case SSE41:
- Define(Defs, "__SSE4_1__");
+ Builder.defineMacro("__SSE4_1__");
case SSSE3:
- Define(Defs, "__SSSE3__");
+ Builder.defineMacro("__SSSE3__");
case SSE3:
- Define(Defs, "__SSE3__");
+ Builder.defineMacro("__SSE3__");
case SSE2:
- Define(Defs, "__SSE2__");
- Define(Defs, "__SSE2_MATH__"); // -mfp-math=sse always implied.
+ Builder.defineMacro("__SSE2__");
+ Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied.
case SSE1:
- Define(Defs, "__SSE__");
- Define(Defs, "__SSE_MATH__"); // -mfp-math=sse always implied.
+ Builder.defineMacro("__SSE__");
+ Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied.
case MMX:
- Define(Defs, "__MMX__");
+ Builder.defineMacro("__MMX__");
case NoMMXSSE:
break;
}
@@ -999,13 +987,13 @@ public:
"v128:128:128-a0:0:64-f80:32:32-n8:16:32";
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- X86_32TargetInfo::getTargetDefines(Opts, Defines);
+ MacroBuilder &Builder) const {
+ X86_32TargetInfo::getTargetDefines(Opts, Builder);
// This list is based off of the the list of things MingW defines
- Define(Defines, "_WIN32");
- DefineStd(Defines, "WIN32", Opts);
- DefineStd(Defines, "WINNT", Opts);
- Define(Defines, "_X86_");
+ Builder.defineMacro("_WIN32");
+ DefineStd(Builder, "WIN32", Opts);
+ DefineStd(Builder, "WINNT", Opts);
+ Builder.defineMacro("_X86_");
}
};
} // end anonymous namespace
@@ -1019,12 +1007,12 @@ public:
: WindowsX86_32TargetInfo(triple) {
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- WindowsX86_32TargetInfo::getTargetDefines(Opts, Defines);
+ MacroBuilder &Builder) const {
+ WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
// The value of the following reflects processor type.
// 300=386, 400=486, 500=Pentium, 600=Blend (default)
// We lost the original triple, so we use the default.
- Define(Defines, "_M_IX86", "600");
+ Builder.defineMacro("_M_IX86", "600");
}
};
} // end anonymous namespace
@@ -1037,11 +1025,11 @@ public:
: WindowsX86_32TargetInfo(triple) {
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- WindowsX86_32TargetInfo::getTargetDefines(Opts, Defines);
- Define(Defines, "__MSVCRT__");
- Define(Defines, "__MINGW32__");
- Define(Defines, "__declspec", "__declspec");
+ MacroBuilder &Builder) const {
+ WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__MSVCRT__");
+ Builder.defineMacro("__MINGW32__");
+ Builder.defineMacro("__declspec", "__declspec");
}
};
} // end anonymous namespace
@@ -1060,11 +1048,11 @@ public:
"a0:0:64-f80:32:32-n8:16:32";
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- X86_32TargetInfo::getTargetDefines(Opts, Defines);
- Define(Defines, "__CYGWIN__");
- Define(Defines, "__CYGWIN32__");
- DefineStd(Defines, "unix", Opts);
+ MacroBuilder &Builder) const {
+ X86_32TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__CYGWIN__");
+ Builder.defineMacro("__CYGWIN32__");
+ DefineStd(Builder, "unix", Opts);
}
};
} // end anonymous namespace
@@ -1116,10 +1104,10 @@ public:
DoubleAlign = LongLongAlign = 64;
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- X86_64TargetInfo::getTargetDefines(Opts, Defines);
- Define(Defines, "_WIN64");
- DefineStd(Defines, "WIN64", Opts);
+ MacroBuilder &Builder) const {
+ X86_64TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("_WIN64");
+ DefineStd(Builder, "WIN64", Opts);
}
};
} // end anonymous namespace
@@ -1132,9 +1120,9 @@ public:
: WindowsX86_64TargetInfo(triple) {
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- WindowsX86_64TargetInfo::getTargetDefines(Opts, Defines);
- Define(Defines, "_M_X64");
+ MacroBuilder &Builder) const {
+ WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("_M_X64");
}
virtual const char *getVAListDeclaration() const {
return "typedef char* va_list;";
@@ -1150,11 +1138,11 @@ public:
: WindowsX86_64TargetInfo(triple) {
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- WindowsX86_64TargetInfo::getTargetDefines(Opts, Defines);
- Define(Defines, "__MSVCRT__");
- Define(Defines, "__MINGW64__");
- Define(Defines, "__declspec");
+ MacroBuilder &Builder) const {
+ WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__MSVCRT__");
+ Builder.defineMacro("__MINGW64__");
+ Builder.defineMacro("__declspec");
}
};
} // end anonymous namespace
@@ -1342,61 +1330,58 @@ public:
return true;
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// Target identification.
- Define(Defs, "__arm");
- Define(Defs, "__arm__");
+ Builder.defineMacro("__arm");
+ Builder.defineMacro("__arm__");
// Target properties.
- Define(Defs, "__ARMEL__");
- Define(Defs, "__LITTLE_ENDIAN__");
- Define(Defs, "__REGISTER_PREFIX__", "");
+ Builder.defineMacro("__ARMEL__");
+ Builder.defineMacro("__LITTLE_ENDIAN__");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
llvm::StringRef CPUArch = getCPUDefineSuffix(CPU);
- std::string ArchName = "__ARM_ARCH_";
- ArchName += CPUArch;
- ArchName += "__";
- Define(Defs, ArchName);
+ Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__");
// Subtarget options.
// 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__");
+ Builder.defineMacro("__THUMB_INTERWORK__");
if (ABI == "aapcs" || ABI == "aapcs-linux")
- Define(Defs, "__ARM_EABI__");
+ Builder.defineMacro("__ARM_EABI__");
if (SoftFloat)
- Define(Defs, "__SOFTFP__");
+ Builder.defineMacro("__SOFTFP__");
if (CPU == "xscale")
- Define(Defs, "__XSCALE__");
+ Builder.defineMacro("__XSCALE__");
bool IsThumb2 = IsThumb && (CPUArch == "6T2" || CPUArch.startswith("7"));
if (IsThumb) {
- Define(Defs, "__THUMBEL__");
- Define(Defs, "__thumb__");
+ Builder.defineMacro("__THUMBEL__");
+ Builder.defineMacro("__thumb__");
if (IsThumb2)
- Define(Defs, "__thumb2__");
+ Builder.defineMacro("__thumb2__");
}
// Note, this is always on in gcc, even though it doesn't make sense.
- Define(Defs, "__APCS_32__");
+ Builder.defineMacro("__APCS_32__");
if (FPUModeIsVFP((FPUMode) FPU))
- Define(Defs, "__VFP_FP__");
+ Builder.defineMacro("__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__");
+ Builder.defineMacro("__ARM_NEON__");
if (getTriple().getOS() == llvm::Triple::Darwin)
- Define(Defs, "__USING_SJLJ_EXCEPTIONS__");
+ Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -1475,9 +1460,9 @@ class DarwinARMTargetInfo :
public DarwinTargetInfo<ARMTargetInfo> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defines) const {
- getDarwinDefines(Defines, Opts);
- getDarwinIPhoneOSDefines(Defines, Triple);
+ MacroBuilder &Builder) const {
+ getDarwinDefines(Builder, Opts);
+ getDarwinIPhoneOSDefines(Builder, Triple);
}
public:
@@ -1497,10 +1482,10 @@ public:
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- DefineStd(Defines, "sparc", Opts);
- Define(Defines, "__sparcv8");
- Define(Defines, "__REGISTER_PREFIX__", "");
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "sparc", Opts);
+ Builder.defineMacro("__sparcv8");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -1630,18 +1615,18 @@ namespace {
virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return 16; }
virtual uint64_t getPointerAlignV(unsigned AddrSpace) const { return 8; }
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- Define(Defines, "__pic16");
- Define(Defines, "rom", "__attribute__((address_space(1)))");
- Define(Defines, "ram", "__attribute__((address_space(0)))");
- Define(Defines, "_section(SectName)",
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__pic16");
+ Builder.defineMacro("rom", "__attribute__((address_space(1)))");
+ Builder.defineMacro("ram", "__attribute__((address_space(0)))");
+ Builder.defineMacro("_section(SectName)",
"__attribute__((section(SectName)))");
- Define(Defines, "near",
+ Builder.defineMacro("near",
"__attribute__((section(\"Address=NEAR\")))");
- Define(Defines, "_address(Addr)",
+ Builder.defineMacro("_address(Addr)",
"__attribute__((section(\"Address=\"#Addr)))");
- Define(Defines, "_CONFIG(conf)", "asm(\"CONFIG \"#conf)");
- Define(Defines, "_interrupt",
+ Builder.defineMacro("_CONFIG(conf)", "asm(\"CONFIG \"#conf)");
+ Builder.defineMacro("_interrupt",
"__attribute__((section(\"interrupt=0x4\"))) \
__attribute__((used))");
}
@@ -1672,7 +1657,8 @@ namespace {
MSP430TargetInfo(const std::string& triple) : TargetInfo(triple) {
TLSSupported = false;
IntWidth = 16;
- LongWidth = LongLongWidth = 32;
+ LongWidth = 32;
+ LongLongWidth = 64;
PointerWidth = 16;
IntAlign = 8;
LongAlign = LongLongAlign = 8;
@@ -1686,9 +1672,9 @@ namespace {
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 {
- Define(Defines, "MSP430");
- Define(Defines, "__MSP430__");
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("MSP430");
+ Builder.defineMacro("__MSP430__");
// FIXME: defines for different 'flavours' of MCU
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
@@ -1746,9 +1732,9 @@ namespace {
"i64:64:64-f32:32:32-f64:64:64-f128:128:128-a0:16:16-n32:64";
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- Define(Defines, "__s390__");
- Define(Defines, "__s390x__");
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__s390__");
+ Builder.defineMacro("__s390x__");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -1805,12 +1791,12 @@ namespace {
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- DefineStd(Defines, "bfin", Opts);
- DefineStd(Defines, "BFIN", Opts);
- Define(Defines, "__ADSPBLACKFIN__");
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "bfin", Opts);
+ DefineStd(Builder, "BFIN", Opts);
+ Builder.defineMacro("__ADSPBLACKFIN__");
// FIXME: This one is really dependent on -mcpu
- Define(Defines, "__ADSPLPBLACKFIN__");
+ Builder.defineMacro("__ADSPLPBLACKFIN__");
// FIXME: Add cpu-dependent defines and __SILICON_REVISION__
}
@@ -1906,10 +1892,10 @@ namespace {
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- DefineStd(Defines, "tce", Opts);
- Define(Defines, "__TCE__");
- Define(Defines, "__TCE_V1__");
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "tce", Opts);
+ Builder.defineMacro("__TCE__");
+ Builder.defineMacro("__TCE_V1__");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {}
@@ -1940,12 +1926,12 @@ public:
"i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32";
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- DefineStd(Defines, "mips", Opts);
- Define(Defines, "_mips");
- DefineStd(Defines, "MIPSEB", Opts);
- Define(Defines, "_MIPSEB");
- Define(Defines, "__REGISTER_PREFIX__", "");
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "mips", Opts);
+ Builder.defineMacro("_mips");
+ DefineStd(Builder, "MIPSEB", Opts);
+ Builder.defineMacro("_MIPSEB");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -2047,16 +2033,16 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const;
+ MacroBuilder &Builder) const;
};
void MipselTargetInfo::getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- DefineStd(Defines, "mips", Opts);
- Define(Defines, "_mips");
- DefineStd(Defines, "MIPSEL", Opts);
- Define(Defines, "_MIPSEL");
- Define(Defines, "__REGISTER_PREFIX__", "");
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "mips", Opts);
+ Builder.defineMacro("_mips");
+ DefineStd(Builder, "MIPSEL", Opts);
+ Builder.defineMacro("_MIPSEL");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
}
} // end anonymous namespace.
@@ -2171,6 +2157,8 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new DarwinX86_64TargetInfo(T);
case llvm::Triple::Linux:
return new LinuxTargetInfo<X86_64TargetInfo>(T);
+ case llvm::Triple::DragonFly:
+ return new DragonFlyBSDTargetInfo<X86_64TargetInfo>(T);
case llvm::Triple::NetBSD:
return new NetBSDTargetInfo<X86_64TargetInfo>(T);
case llvm::Triple::OpenBSD:
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 1bece7f..1fa422f 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -24,7 +24,7 @@ using namespace clang;
using namespace CodeGen;
llvm::Constant *CodeGenFunction::
-BuildDescriptorBlockDecl(bool BlockHasCopyDispose, uint64_t Size,
+BuildDescriptorBlockDecl(bool BlockHasCopyDispose, CharUnits Size,
const llvm::StructType* Ty,
std::vector<HelperInfo> *NoteForHelper) {
const llvm::Type *UnsignedLongTy
@@ -40,7 +40,7 @@ BuildDescriptorBlockDecl(bool BlockHasCopyDispose, uint64_t Size,
// FIXME: What is the right way to say this doesn't fit? We should give
// a user diagnostic in that case. Better fix would be to change the
// API to size_t.
- C = llvm::ConstantInt::get(UnsignedLongTy, Size);
+ C = llvm::ConstantInt::get(UnsignedLongTy, Size.getQuantity());
Elts.push_back(C);
if (BlockHasCopyDispose) {
@@ -176,7 +176,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
// We run this first so that we set BlockHasCopyDispose from the entire
// block literal.
// __invoke
- uint64_t subBlockSize, subBlockAlign;
+ CharUnits subBlockSize;
+ uint64_t subBlockAlign;
llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
bool subBlockHasCopyDispose = false;
llvm::Function *Fn
@@ -321,13 +322,13 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
// compared to gcc by not grabbing the forwarding slot as this must
// be done during Block_copy for us, and we can postpone the work
// until then.
- uint64_t offset = BlockDecls[BDRE->getDecl()];
+ CharUnits offset = BlockDecls[BDRE->getDecl()];
llvm::Value *BlockLiteral = LoadBlockStruct();
Loc = Builder.CreateGEP(BlockLiteral,
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset),
+ offset.getQuantity()),
"block.literal");
Ty = llvm::PointerType::get(Ty, 0);
Loc = Builder.CreateBitCast(Loc, Ty);
@@ -513,12 +514,12 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
return EmitCall(FnInfo, Func, ReturnValue, Args);
}
-uint64_t CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
+CharUnits CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
const ValueDecl *VD = E->getDecl();
- uint64_t &offset = BlockDecls[VD];
+ CharUnits &offset = BlockDecls[VD];
// See if we have already allocated an offset for this variable.
- if (offset)
+ if (offset.isPositive())
return offset;
// Don't run the expensive check, unless we have to.
@@ -535,13 +536,13 @@ uint64_t CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
const ValueDecl *VD = E->getDecl();
- uint64_t offset = AllocateBlockDecl(E);
+ CharUnits offset = AllocateBlockDecl(E);
llvm::Value *BlockLiteral = LoadBlockStruct();
llvm::Value *V = Builder.CreateGEP(BlockLiteral,
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset),
+ offset.getQuantity()),
"block.literal");
if (E->isByRef()) {
const llvm::Type *PtrStructTy
@@ -594,10 +595,10 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
// Block literal size. For global blocks we just use the size of the generic
// block literal struct.
- uint64_t BlockLiteralSize =
- TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType()) / 8;
+ CharUnits BlockLiteralSize = CharUnits::fromQuantity(
+ TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType()) / 8);
DescriptorFields[1] =
- llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize);
+ llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize.getQuantity());
llvm::Constant *DescriptorStruct =
llvm::ConstantStruct::get(VMContext, &DescriptorFields[0], 2, false);
@@ -615,7 +616,8 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
std::vector<llvm::Constant*> LiteralFields(FieldCount);
CodeGenFunction::BlockInfo Info(0, n);
- uint64_t subBlockSize, subBlockAlign;
+ CharUnits subBlockSize;
+ uint64_t subBlockAlign;
llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
bool subBlockHasCopyDispose = false;
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
@@ -677,7 +679,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
const BlockInfo& Info,
const Decl *OuterFuncDecl,
llvm::DenseMap<const Decl*, llvm::Value*> ldm,
- uint64_t &Size,
+ CharUnits &Size,
uint64_t &Align,
llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls,
bool &subBlockHasCopyDispose) {
@@ -698,8 +700,9 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
LocalDeclMap[VD] = i->second;
}
- BlockOffset = CGM.getTargetData()
- .getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8;
+ BlockOffset = CharUnits::fromQuantity(
+ CGM.getTargetData()
+ .getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8);
BlockAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
const FunctionType *BlockFunctionType = BExpr->getFunctionType();
@@ -799,7 +802,8 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
// The runtime needs a minimum alignment of a void *.
uint64_t MinAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
- BlockOffset = llvm::RoundUpToAlignment(BlockOffset, MinAlign);
+ BlockOffset = CharUnits::fromQuantity(
+ llvm::RoundUpToAlignment(BlockOffset.getQuantity(), MinAlign));
Size = BlockOffset;
Align = BlockAlign;
@@ -808,30 +812,32 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
return Fn;
}
-uint64_t BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
+CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
const ValueDecl *D = dyn_cast<ValueDecl>(BDRE->getDecl());
- uint64_t Size = getContext().getTypeSize(D->getType()) / 8;
+ CharUnits Size = getContext().getTypeSizeInChars(D->getType());
uint64_t Align = getContext().getDeclAlignInBytes(D);
if (BDRE->isByRef()) {
- Size = getContext().getTypeSize(getContext().VoidPtrTy) / 8;
+ Size = getContext().getTypeSizeInChars(getContext().VoidPtrTy);
Align = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
}
assert ((Align > 0) && "alignment must be 1 byte or more");
- uint64_t OldOffset = BlockOffset;
+ CharUnits OldOffset = BlockOffset;
// Ensure proper alignment, even if it means we have to have a gap
- BlockOffset = llvm::RoundUpToAlignment(BlockOffset, Align);
+ BlockOffset = CharUnits::fromQuantity(
+ llvm::RoundUpToAlignment(BlockOffset.getQuantity(), Align));
BlockAlign = std::max(Align, BlockAlign);
- uint64_t Pad = BlockOffset - OldOffset;
- if (Pad) {
- llvm::ArrayType::get(llvm::Type::getInt8Ty(VMContext), Pad);
+ CharUnits Pad = BlockOffset - OldOffset;
+ if (Pad.isPositive()) {
+ llvm::ArrayType::get(llvm::Type::getInt8Ty(VMContext), Pad.getQuantity());
QualType PadTy = getContext().getConstantArrayType(getContext().CharTy,
- llvm::APInt(32, Pad),
+ llvm::APInt(32,
+ Pad.getQuantity()),
ArrayType::Normal, 0);
ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(),
0, QualType(PadTy), 0, VarDecl::None);
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 38e02a7..f42244c 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -20,6 +20,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
@@ -175,13 +176,13 @@ public:
/// BlockOffset - The offset in bytes for the next allocation of an
/// imported block variable.
- uint64_t BlockOffset;
+ CharUnits BlockOffset;
/// BlockAlign - Maximal alignment needed for the Block expressed in bytes.
uint64_t BlockAlign;
/// getBlockOffset - Allocate an offset for the ValueDecl from a
/// BlockDeclRefExpr in a block literal (BlockExpr).
- uint64_t getBlockOffset(const BlockDeclRefExpr *E);
+ CharUnits getBlockOffset(const BlockDeclRefExpr *E);
/// BlockHasCopyDispose - True iff the block uses copy/dispose.
bool BlockHasCopyDispose;
@@ -191,7 +192,7 @@ public:
llvm::SmallVector<const Expr *, 8> BlockDeclRefDecls;
/// BlockDecls - Offsets for all Decls in BlockDeclRefExprs.
- std::map<const Decl*, uint64_t> BlockDecls;
+ std::map<const Decl*, CharUnits> BlockDecls;
ImplicitParamDecl *BlockStructDecl;
ImplicitParamDecl *getBlockStructDecl() { return BlockStructDecl; }
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index cc006d9..4323f84 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -26,269 +26,7 @@
using namespace clang;
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) {
- assert(MD->isInstance() &&
- "Trying to emit a member call expr on a static method!");
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
-
- CallArgList Args;
-
- // Push the this ptr.
- Args.push_back(std::make_pair(RValue::get(This),
- MD->getThisType(getContext())));
-
- // And the rest of the call args
- EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
-
- QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
- return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
- ReturnValue, Args, MD);
-}
-
-/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
-/// expr can be devirtualized.
-static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) {
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
- // This is a record decl. We know the type and can devirtualize it.
- return VD->getType()->isRecordType();
- }
-
- return false;
- }
-
- // We can always devirtualize calls on temporary object expressions.
- if (isa<CXXTemporaryObjectExpr>(Base))
- return true;
-
- // And calls on bound temporaries.
- if (isa<CXXBindTemporaryExpr>(Base))
- return true;
-
- // Check if this is a call expr that returns a record type.
- if (const CallExpr *CE = dyn_cast<CallExpr>(Base))
- return CE->getCallReturnType()->isRecordType();
-
- // We can't devirtualize the call.
- return false;
-}
-
-RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
- ReturnValueSlot ReturnValue) {
- if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens()))
- return EmitCXXMemberPointerCallExpr(CE, ReturnValue);
-
- const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens());
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
-
- if (MD->isStatic()) {
- // The method is static, emit it as we would a regular call.
- llvm::Value *Callee = CGM.GetAddrOfFunction(MD);
- return EmitCall(getContext().getPointerType(MD->getType()), Callee,
- ReturnValue, CE->arg_begin(), CE->arg_end());
- }
-
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
-
- const llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
- llvm::Value *This;
-
- if (ME->isArrow())
- This = EmitScalarExpr(ME->getBase());
- else {
- LValue BaseLV = EmitLValue(ME->getBase());
- This = BaseLV.getAddress();
- }
-
- if (MD->isCopyAssignment() && MD->isTrivial()) {
- // We don't like to generate the trivial copy assignment operator when
- // it isn't necessary; just produce the proper effect here.
- llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress();
- EmitAggregateCopy(This, RHS, CE->getType());
- return RValue::get(This);
- }
-
- // C++ [class.virtual]p12:
- // Explicit qualification with the scope operator (5.1) suppresses the
- // virtual call mechanism.
- //
- // We also don't emit a virtual call if the base expression has a record type
- // because then we know what the type is.
- llvm::Value *Callee;
- if (const CXXDestructorDecl *Destructor
- = dyn_cast<CXXDestructorDecl>(MD)) {
- if (Destructor->isTrivial())
- return RValue::get(0);
- if (MD->isVirtual() && !ME->hasQualifier() &&
- !canDevirtualizeMemberFunctionCalls(ME->getBase())) {
- Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty);
- } else {
- Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty);
- }
- } else if (MD->isVirtual() && !ME->hasQualifier() &&
- !canDevirtualizeMemberFunctionCalls(ME->getBase())) {
- Callee = BuildVirtualCall(MD, This, Ty);
- } else {
- Callee = CGM.GetAddrOfFunction(MD, Ty);
- }
-
- return EmitCXXMemberCall(MD, Callee, ReturnValue, This,
- CE->arg_begin(), CE->arg_end());
-}
-
-RValue
-CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
- ReturnValueSlot ReturnValue) {
- const BinaryOperator *BO =
- cast<BinaryOperator>(E->getCallee()->IgnoreParens());
- const Expr *BaseExpr = BO->getLHS();
- const Expr *MemFnExpr = BO->getRHS();
-
- const MemberPointerType *MPT =
- MemFnExpr->getType()->getAs<MemberPointerType>();
- const FunctionProtoType *FPT =
- MPT->getPointeeType()->getAs<FunctionProtoType>();
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
-
- const llvm::FunctionType *FTy =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
- FPT->isVariadic());
-
- const llvm::Type *Int8PtrTy =
- llvm::Type::getInt8Ty(VMContext)->getPointerTo();
-
- // Get the member function pointer.
- llvm::Value *MemFnPtr =
- CreateTempAlloca(ConvertType(MemFnExpr->getType()), "mem.fn");
- EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false);
-
- // Emit the 'this' pointer.
- llvm::Value *This;
-
- if (BO->getOpcode() == BinaryOperator::PtrMemI)
- This = EmitScalarExpr(BaseExpr);
- else
- This = EmitLValue(BaseExpr).getAddress();
-
- // Adjust it.
- llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1);
- Adj = Builder.CreateLoad(Adj, "mem.fn.adj");
-
- llvm::Value *Ptr = Builder.CreateBitCast(This, Int8PtrTy, "ptr");
- Ptr = Builder.CreateGEP(Ptr, Adj, "adj");
-
- This = Builder.CreateBitCast(Ptr, This->getType(), "this");
-
- llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr");
-
- const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
-
- llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn");
-
- // If the LSB in the function pointer is 1, the function pointer points to
- // a virtual function.
- llvm::Value *IsVirtual
- = Builder.CreateAnd(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1),
- "and");
-
- IsVirtual = Builder.CreateTrunc(IsVirtual,
- llvm::Type::getInt1Ty(VMContext));
-
- llvm::BasicBlock *FnVirtual = createBasicBlock("fn.virtual");
- llvm::BasicBlock *FnNonVirtual = createBasicBlock("fn.nonvirtual");
- llvm::BasicBlock *FnEnd = createBasicBlock("fn.end");
-
- Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual);
- EmitBlock(FnVirtual);
-
- const llvm::Type *VTableTy =
- FTy->getPointerTo()->getPointerTo()->getPointerTo();
-
- llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy);
- VTable = Builder.CreateLoad(VTable);
-
- VTable = Builder.CreateGEP(VTable, FnAsInt, "fn");
-
- // Since the function pointer is 1 plus the virtual table offset, we
- // subtract 1 by using a GEP.
- VTable = Builder.CreateConstGEP1_64(VTable, (uint64_t)-1);
-
- llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn");
-
- EmitBranch(FnEnd);
- EmitBlock(FnNonVirtual);
-
- // If the function is not virtual, just load the pointer.
- llvm::Value *NonVirtualFn = Builder.CreateLoad(FnPtr, "fn");
- NonVirtualFn = Builder.CreateIntToPtr(NonVirtualFn, FTy->getPointerTo());
-
- EmitBlock(FnEnd);
-
- llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo());
- Callee->reserveOperandSpace(2);
- Callee->addIncoming(VirtualFn, FnVirtual);
- Callee->addIncoming(NonVirtualFn, FnNonVirtual);
-
- CallArgList Args;
-
- QualType ThisType =
- getContext().getPointerType(getContext().getTagDeclType(RD));
-
- // Push the this ptr.
- Args.push_back(std::make_pair(RValue::get(This), ThisType));
-
- // 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,
- ReturnValue, Args);
-}
-
-RValue
-CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
- const CXXMethodDecl *MD,
- ReturnValueSlot ReturnValue) {
- assert(MD->isInstance() &&
- "Trying to emit a member call expr on a static method!");
-
- if (MD->isCopyAssignment()) {
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext());
- if (ClassDecl->hasTrivialCopyAssignment()) {
- assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
- "EmitCXXOperatorMemberCallExpr - user declared copy assignment");
- llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
- llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
- QualType Ty = E->getType();
- EmitAggregateCopy(This, Src, Ty);
- return RValue::get(This);
- }
- }
-
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
-
- llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
-
- llvm::Value *Callee;
- if (MD->isVirtual() && !canDevirtualizeMemberFunctionCalls(E->getArg(0)))
- Callee = BuildVirtualCall(MD, This, Ty);
- else
- Callee = CGM.GetAddrOfFunction(MD, Ty);
-
- return EmitCXXMemberCall(MD, Callee, ReturnValue, This,
- E->arg_begin() + 1, E->arg_end());
-}
llvm::Value *CodeGenFunction::LoadCXXThis() {
assert(isa<CXXMethodDecl>(CurFuncDecl) &&
@@ -302,320 +40,6 @@ llvm::Value *CodeGenFunction::LoadCXXThis() {
return Builder.CreateLoad(LocalDeclMap[CXXThisDecl], "this");
}
-/// EmitCXXAggrConstructorCall - This routine essentially creates a (nested)
-/// for-loop to call the default constructor on individual members of the
-/// array.
-/// 'D' is the default constructor for elements of the array, 'ArrayTy' is the
-/// array type and 'ArrayPtr' points to the beginning fo the array.
-/// It is assumed that all relevant checks have been made by the caller.
-void
-CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
- const ConstantArrayType *ArrayTy,
- llvm::Value *ArrayPtr,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd) {
-
- const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
- llvm::Value * NumElements =
- llvm::ConstantInt::get(SizeTy,
- getContext().getConstantArrayElementCount(ArrayTy));
-
- EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr, ArgBeg, ArgEnd);
-}
-
-void
-CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
- llvm::Value *NumElements,
- llvm::Value *ArrayPtr,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd) {
- const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
-
- // Create a temporary for the loop index and initialize it with 0.
- llvm::Value *IndexPtr = CreateTempAlloca(SizeTy, "loop.index");
- llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy);
- Builder.CreateStore(Zero, 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.
- llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
- llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElements, "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);
- llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter,
- "arrayidx");
-
- // C++ [class.temporary]p4:
- // There are two contexts in which temporaries are destroyed at a different
- // point than the end of the full-expression. The first context is when a
- // default constructor is called to initialize an element of an array.
- // If the constructor has one or more default arguments, the destruction of
- // every temporary created in a default argument expression is sequenced
- // before the construction of the next array element, if any.
-
- // Keep track of the current number of live temporaries.
- unsigned OldNumLiveTemporaries = LiveTemporaries.size();
-
- EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd);
-
- // Pop temporaries.
- while (LiveTemporaries.size() > OldNumLiveTemporaries)
- PopCXXTemporary();
-
- EmitBlock(ContinueBlock);
-
- // Emit the increment of the loop counter.
- llvm::Value *NextVal = llvm::ConstantInt::get(SizeTy, 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);
-}
-
-/// EmitCXXAggrDestructorCall - calls the default destructor on array
-/// elements in reverse order of construction.
-void
-CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
- const ArrayType *Array,
- llvm::Value *This) {
- const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
- assert(CA && "Do we support VLA for destruction ?");
- uint64_t ElementCount = getContext().getConstantArrayElementCount(CA);
-
- const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
- llvm::Value* ElementCountPtr = llvm::ConstantInt::get(SizeLTy, ElementCount);
- EmitCXXAggrDestructorCall(D, ElementCountPtr, This);
-}
-
-/// EmitCXXAggrDestructorCall - calls the default destructor on array
-/// elements in reverse order of construction.
-void
-CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
- llvm::Value *UpperCount,
- llvm::Value *This) {
- const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
- llvm::Value *One = llvm::ConstantInt::get(SizeLTy, 1);
-
- // Create a temporary for the loop index and initialize it with count of
- // array elements.
- llvm::Value *IndexPtr = CreateTempAlloca(SizeLTy, "loop.index");
-
- // Store the number of elements in the index pointer.
- Builder.CreateStore(UpperCount, 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 != 0 fall to the loop body,
- // otherwise, go to the block after the for-loop.
- llvm::Value* zeroConstant =
- llvm::Constant::getNullValue(SizeLTy);
- llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
- llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant,
- "isne");
- // If the condition is true, execute the body.
- Builder.CreateCondBr(IsNE, 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);
- Counter = Builder.CreateSub(Counter, One);
- llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx");
- EmitCXXDestructorCall(D, Dtor_Complete, Address);
-
- EmitBlock(ContinueBlock);
-
- // Emit the decrement of the loop counter.
- Counter = Builder.CreateLoad(IndexPtr);
- Counter = Builder.CreateSub(Counter, One, "dec");
- Builder.CreateStore(Counter, IndexPtr);
-
- // Finally, branch back up to the condition for the next iteration.
- EmitBranch(CondBlock);
-
- // Emit the fall-through block.
- EmitBlock(AfterFor, true);
-}
-
-/// GenerateCXXAggrDestructorHelper - Generates a helper function which when
-/// invoked, calls the default destructor on array elements in reverse order of
-/// construction.
-llvm::Constant *
-CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
- const ArrayType *Array,
- llvm::Value *This) {
- FunctionArgList Args;
- ImplicitParamDecl *Dst =
- ImplicitParamDecl::Create(getContext(), 0,
- SourceLocation(), 0,
- getContext().getPointerType(getContext().VoidTy));
- Args.push_back(std::make_pair(Dst, Dst->getType()));
-
- llvm::SmallString<16> Name;
- llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount);
- QualType R = getContext().VoidTy;
- const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args);
- const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
- llvm::Function *Fn =
- llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
- Name.str(),
- &CGM.getModule());
- IdentifierInfo *II = &CGM.getContext().Idents.get(Name.str());
- FunctionDecl *FD = FunctionDecl::Create(getContext(),
- getContext().getTranslationUnitDecl(),
- SourceLocation(), II, R, 0,
- FunctionDecl::Static,
- false, true);
- StartFunction(FD, R, Fn, Args, SourceLocation());
- QualType BaseElementTy = getContext().getBaseElementType(Array);
- const llvm::Type *BasePtr = ConvertType(BaseElementTy);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr = Builder.CreateBitCast(This, BasePtr);
- EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
- FinishFunction();
- llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),
- 0);
- llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
- return m;
-}
-
-void
-CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
- CXXCtorType Type,
- llvm::Value *This,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd) {
- if (D->isCopyConstructor()) {
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D->getDeclContext());
- if (ClassDecl->hasTrivialCopyConstructor()) {
- assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
- "EmitCXXConstructorCall - user declared copy constructor");
- const Expr *E = (*ArgBeg);
- QualType Ty = E->getType();
- llvm::Value *Src = EmitLValue(E).getAddress();
- EmitAggregateCopy(This, Src, Ty);
- return;
- }
- } else if (D->isTrivial()) {
- // FIXME: Track down why we're trying to generate calls to the trivial
- // default constructor!
- return;
- }
-
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
-
- EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, ArgBeg, ArgEnd);
-}
-
-void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
- CXXDtorType Type,
- llvm::Value *This) {
- llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
-
- CallArgList Args;
-
- // Push the this ptr.
- Args.push_back(std::make_pair(RValue::get(This),
- DD->getThisType(getContext())));
-
- // Add a VTT parameter if necessary.
- // FIXME: This should not be a dummy null parameter!
- if (Type == Dtor_Base && DD->getParent()->getNumVBases() != 0) {
- QualType T = getContext().getPointerType(getContext().VoidPtrTy);
-
- Args.push_back(std::make_pair(RValue::get(CGM.EmitNullConstant(T)), T));
- }
-
- // FIXME: We should try to share this code with EmitCXXMemberCall.
-
- QualType ResultType = DD->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
- ReturnValueSlot(), Args, DD);
-}
-
-void
-CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
- const CXXConstructExpr *E) {
- assert(Dest && "Must have a destination!");
- const CXXConstructorDecl *CD = E->getConstructor();
- const ConstantArrayType *Array =
- 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()) {
- QualType InitType = E->getType();
- if (Array)
- InitType = getContext().getBaseElementType(Array);
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(InitType->getAs<RecordType>()->getDecl());
- if (RD->hasTrivialConstructor())
- 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))
- Arg = BindExpr->getSubExpr();
-
- EmitAggExpr(Arg, Dest, false);
- return;
- }
- if (Array) {
- QualType BaseElementTy = getContext().getBaseElementType(Array);
- const llvm::Type *BasePtr = ConvertType(BaseElementTy);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(Dest, BasePtr);
-
- EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
- E->arg_begin(), E->arg_end());
- }
- else
- // Call the constructor.
- EmitCXXConstructorCall(CD, Ctor_Complete, Dest,
- E->arg_begin(), E->arg_end());
-}
-
void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) {
EmitGlobal(GlobalDecl(D, Ctor_Complete));
EmitGlobal(GlobalDecl(D, Ctor_Base));
@@ -1001,33 +425,6 @@ CodeGenModule::BuildCovariantThunk(const GlobalDecl &GD, bool Extern,
return m;
}
-llvm::Value *
-CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl) {
- const llvm::Type *Int8PtrTy =
- llvm::Type::getInt8Ty(VMContext)->getPointerTo();
-
- llvm::Value *VTablePtr = Builder.CreateBitCast(This,
- Int8PtrTy->getPointerTo());
- VTablePtr = Builder.CreateLoad(VTablePtr, "vtable");
-
- int64_t VBaseOffsetIndex =
- CGM.getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl);
-
- llvm::Value *VBaseOffsetPtr =
- Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr");
- const llvm::Type *PtrDiffTy =
- ConvertType(getContext().getPointerDiffType());
-
- VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr,
- PtrDiffTy->getPointerTo());
-
- llvm::Value *VBaseOffset = Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset");
-
- return VBaseOffset;
-}
-
static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex,
llvm::Value *This, const llvm::Type *Ty) {
Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo();
@@ -1058,71 +455,3 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
}
-
-void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) {
- if (!ClassDecl->isDynamicClass())
- return;
-
- 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());
- uint64_t Offset = Layout.getVBaseClassOffset(BaseClassDecl);
- InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
- ThisPtr, Offset);
- }
-
- // Store address points for non-virtual bases and current class
- InitializeVtablePtrsRecursive(ClassDecl, Vtable, AddressPoints, ThisPtr, 0);
-}
-
-void CodeGenFunction::InitializeVtablePtrsRecursive(
- const CXXRecordDecl *ClassDecl,
- llvm::Constant *Vtable,
- CodeGenModule::AddrSubMap_t& AddressPoints,
- llvm::Value *ThisPtr,
- uint64_t Offset) {
- if (!ClassDecl->isDynamicClass())
- return;
-
- // 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;
- if (Base.isVirtual())
- continue;
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- uint64_t NewOffset = Offset + Layout.getBaseClassOffset(BaseClassDecl);
- InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
- ThisPtr, NewOffset);
- }
-
- // 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);
-
- // 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);
-
- // Store address point
- Builder.CreateStore(VtableAddressPoint, VtableField);
-}
-
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 953b8c8..ab3fece 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -431,6 +431,37 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
EmitBlock(AfterFor, true);
}
+/// GetVTTParameter - Return the VTT parameter that should be passed to a
+/// base constructor/destructor with virtual bases.
+static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) {
+ if (!CGVtableInfo::needsVTTParameter(GD)) {
+ // This constructor/destructor does not need a VTT parameter.
+ return 0;
+ }
+
+ const CXXRecordDecl *RD = cast<CXXMethodDecl>(CGF.CurFuncDecl)->getParent();
+ const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent();
+
+ llvm::Value *VTT;
+
+ uint64_t SubVTTIndex =
+ CGF.CGM.getVtableInfo().getSubVTTIndex(RD, Base);
+ assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!");
+
+ if (CGVtableInfo::needsVTTParameter(CGF.CurGD)) {
+ // A VTT parameter was passed to the constructor, use it.
+ VTT = CGF.LoadCXXVTT();
+ VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex);
+ } else {
+ // We're the complete constructor, so get the VTT by name.
+ VTT = CGF.CGM.getVtableInfo().getVTT(RD);
+ VTT = CGF.Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex);
+ }
+
+ return VTT;
+}
+
+
/// 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.
@@ -438,11 +469,16 @@ void CodeGenFunction::EmitClassMemberwiseCopy(
llvm::Value *Dest, llvm::Value *Src,
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl, QualType Ty) {
+ CXXCtorType CtorType = Ctor_Complete;
+
if (ClassDecl) {
Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
/*NullCheckValue=*/false);
Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
/*NullCheckValue=*/false);
+
+ // We want to call the base constructor.
+ CtorType = Ctor_Base;
}
if (BaseClassDecl->hasTrivialCopyConstructor()) {
EmitAggregateCopy(Dest, Src, Ty);
@@ -451,13 +487,19 @@ void CodeGenFunction::EmitClassMemberwiseCopy(
if (CXXConstructorDecl *BaseCopyCtor =
BaseClassDecl->getCopyConstructor(getContext(), 0)) {
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor,
- Ctor_Complete);
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, CtorType);
CallArgList CallArgs;
// Push the this (Dest) ptr.
CallArgs.push_back(std::make_pair(RValue::get(Dest),
BaseCopyCtor->getThisType(getContext())));
+ // Push the VTT parameter, if necessary.
+ if (llvm::Value *VTT =
+ GetVTTParameter(*this, GlobalDecl(BaseCopyCtor, CtorType))) {
+ QualType T = getContext().getPointerType(getContext().VoidPtrTy);
+ CallArgs.push_back(std::make_pair(RValue::get(VTT), T));
+ }
+
// Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src),
BaseCopyCtor->getParamDecl(0)->getType()));
@@ -787,10 +829,8 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
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,
+ Ctor_Base, V,
BaseInit->const_arg_begin(),
BaseInit->const_arg_end());
}
@@ -1044,3 +1084,347 @@ void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor,
EmitDtorEpilogue(Dtor, DtorType);
FinishFunction();
}
+
+/// EmitCXXAggrConstructorCall - This routine essentially creates a (nested)
+/// for-loop to call the default constructor on individual members of the
+/// array.
+/// 'D' is the default constructor for elements of the array, 'ArrayTy' is the
+/// array type and 'ArrayPtr' points to the beginning fo the array.
+/// It is assumed that all relevant checks have been made by the caller.
+void
+CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
+ const ConstantArrayType *ArrayTy,
+ llvm::Value *ArrayPtr,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) {
+
+ const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
+ llvm::Value * NumElements =
+ llvm::ConstantInt::get(SizeTy,
+ getContext().getConstantArrayElementCount(ArrayTy));
+
+ EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr, ArgBeg, ArgEnd);
+}
+
+void
+CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
+ llvm::Value *NumElements,
+ llvm::Value *ArrayPtr,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) {
+ const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
+
+ // Create a temporary for the loop index and initialize it with 0.
+ llvm::Value *IndexPtr = CreateTempAlloca(SizeTy, "loop.index");
+ llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy);
+ Builder.CreateStore(Zero, 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.
+ llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
+ llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElements, "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);
+ llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter,
+ "arrayidx");
+
+ // C++ [class.temporary]p4:
+ // There are two contexts in which temporaries are destroyed at a different
+ // point than the end of the full-expression. The first context is when a
+ // default constructor is called to initialize an element of an array.
+ // If the constructor has one or more default arguments, the destruction of
+ // every temporary created in a default argument expression is sequenced
+ // before the construction of the next array element, if any.
+
+ // Keep track of the current number of live temporaries.
+ unsigned OldNumLiveTemporaries = LiveTemporaries.size();
+
+ EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd);
+
+ // Pop temporaries.
+ while (LiveTemporaries.size() > OldNumLiveTemporaries)
+ PopCXXTemporary();
+
+ EmitBlock(ContinueBlock);
+
+ // Emit the increment of the loop counter.
+ llvm::Value *NextVal = llvm::ConstantInt::get(SizeTy, 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);
+}
+
+/// EmitCXXAggrDestructorCall - calls the default destructor on array
+/// elements in reverse order of construction.
+void
+CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
+ const ArrayType *Array,
+ llvm::Value *This) {
+ const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
+ assert(CA && "Do we support VLA for destruction ?");
+ uint64_t ElementCount = getContext().getConstantArrayElementCount(CA);
+
+ const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
+ llvm::Value* ElementCountPtr = llvm::ConstantInt::get(SizeLTy, ElementCount);
+ EmitCXXAggrDestructorCall(D, ElementCountPtr, This);
+}
+
+/// EmitCXXAggrDestructorCall - calls the default destructor on array
+/// elements in reverse order of construction.
+void
+CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
+ llvm::Value *UpperCount,
+ llvm::Value *This) {
+ const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
+ llvm::Value *One = llvm::ConstantInt::get(SizeLTy, 1);
+
+ // Create a temporary for the loop index and initialize it with count of
+ // array elements.
+ llvm::Value *IndexPtr = CreateTempAlloca(SizeLTy, "loop.index");
+
+ // Store the number of elements in the index pointer.
+ Builder.CreateStore(UpperCount, 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 != 0 fall to the loop body,
+ // otherwise, go to the block after the for-loop.
+ llvm::Value* zeroConstant =
+ llvm::Constant::getNullValue(SizeLTy);
+ llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
+ llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant,
+ "isne");
+ // If the condition is true, execute the body.
+ Builder.CreateCondBr(IsNE, 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);
+ Counter = Builder.CreateSub(Counter, One);
+ llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx");
+ EmitCXXDestructorCall(D, Dtor_Complete, Address);
+
+ EmitBlock(ContinueBlock);
+
+ // Emit the decrement of the loop counter.
+ Counter = Builder.CreateLoad(IndexPtr);
+ Counter = Builder.CreateSub(Counter, One, "dec");
+ Builder.CreateStore(Counter, IndexPtr);
+
+ // Finally, branch back up to the condition for the next iteration.
+ EmitBranch(CondBlock);
+
+ // Emit the fall-through block.
+ EmitBlock(AfterFor, true);
+}
+
+/// GenerateCXXAggrDestructorHelper - Generates a helper function which when
+/// invoked, calls the default destructor on array elements in reverse order of
+/// construction.
+llvm::Constant *
+CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
+ const ArrayType *Array,
+ llvm::Value *This) {
+ FunctionArgList Args;
+ ImplicitParamDecl *Dst =
+ ImplicitParamDecl::Create(getContext(), 0,
+ SourceLocation(), 0,
+ getContext().getPointerType(getContext().VoidTy));
+ Args.push_back(std::make_pair(Dst, Dst->getType()));
+
+ llvm::SmallString<16> Name;
+ llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount);
+ QualType R = getContext().VoidTy;
+ const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args);
+ const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
+ llvm::Function *Fn =
+ llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
+ Name.str(),
+ &CGM.getModule());
+ IdentifierInfo *II = &CGM.getContext().Idents.get(Name.str());
+ FunctionDecl *FD = FunctionDecl::Create(getContext(),
+ getContext().getTranslationUnitDecl(),
+ SourceLocation(), II, R, 0,
+ FunctionDecl::Static,
+ false, true);
+ StartFunction(FD, R, Fn, Args, SourceLocation());
+ QualType BaseElementTy = getContext().getBaseElementType(Array);
+ const llvm::Type *BasePtr = ConvertType(BaseElementTy);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr = Builder.CreateBitCast(This, BasePtr);
+ EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
+ FinishFunction();
+ llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),
+ 0);
+ llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
+ return m;
+}
+
+
+void
+CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ llvm::Value *This,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) {
+ if (D->isCopyConstructor()) {
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D->getDeclContext());
+ if (ClassDecl->hasTrivialCopyConstructor()) {
+ assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
+ "EmitCXXConstructorCall - user declared copy constructor");
+ const Expr *E = (*ArgBeg);
+ QualType Ty = E->getType();
+ llvm::Value *Src = EmitLValue(E).getAddress();
+ EmitAggregateCopy(This, Src, Ty);
+ return;
+ }
+ } else if (D->isTrivial()) {
+ // FIXME: Track down why we're trying to generate calls to the trivial
+ // default constructor!
+ return;
+ }
+
+ llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type));
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
+
+ EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd);
+}
+
+void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
+ CXXDtorType Type,
+ llvm::Value *This) {
+ llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type));
+ llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
+
+ EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0);
+}
+
+llvm::Value *
+CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl) {
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8Ty(VMContext)->getPointerTo();
+
+ llvm::Value *VTablePtr = Builder.CreateBitCast(This,
+ Int8PtrTy->getPointerTo());
+ VTablePtr = Builder.CreateLoad(VTablePtr, "vtable");
+
+ int64_t VBaseOffsetIndex =
+ CGM.getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl);
+
+ llvm::Value *VBaseOffsetPtr =
+ Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr");
+ const llvm::Type *PtrDiffTy =
+ ConvertType(getContext().getPointerDiffType());
+
+ VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr,
+ PtrDiffTy->getPointerTo());
+
+ llvm::Value *VBaseOffset = Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset");
+
+ return VBaseOffset;
+}
+
+void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) {
+ if (!ClassDecl->isDynamicClass())
+ return;
+
+ llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl);
+ CGVtableInfo::AddrSubMap_t& AddressPoints =
+ *(*CGM.getVtableInfo().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());
+ uint64_t Offset = Layout.getVBaseClassOffset(BaseClassDecl);
+ InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
+ ThisPtr, Offset);
+ }
+
+ // Store address points for non-virtual bases and current class
+ InitializeVtablePtrsRecursive(ClassDecl, Vtable, AddressPoints, ThisPtr, 0);
+}
+
+void CodeGenFunction::InitializeVtablePtrsRecursive(
+ const CXXRecordDecl *ClassDecl,
+ llvm::Constant *Vtable,
+ CGVtableInfo::AddrSubMap_t& AddressPoints,
+ llvm::Value *ThisPtr,
+ uint64_t Offset) {
+ if (!ClassDecl->isDynamicClass())
+ return;
+
+ // 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;
+ if (Base.isVirtual())
+ continue;
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+ uint64_t NewOffset = Offset + Layout.getBaseClassOffset(BaseClassDecl);
+ InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
+ ThisPtr, NewOffset);
+ }
+
+ // 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);
+
+ // 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);
+
+ // Store address point
+ Builder.CreateStore(VtableAddressPoint, VtableField);
+}
+
+llvm::Value *CodeGenFunction::LoadCXXVTT() {
+ assert((isa<CXXConstructorDecl>(CurFuncDecl) ||
+ isa<CXXDestructorDecl>(CurFuncDecl)) &&
+ "Must be in a C++ ctor or dtor to load the vtt parameter");
+
+ return Builder.CreateLoad(LocalDeclMap[CXXVTTDecl], "vtt");
+}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 19695c8..ab8f663 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -65,6 +65,25 @@ llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl,
return CompileUnit;
}
+/// getFunctionName - Get function name for the given FunctionDecl. If the
+/// name is constructred on demand (e.g. C++ destructor) then the name
+/// is stored on the side.
+llvm::StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
+ assert (FD && "Invalid FunctionDecl!");
+ IdentifierInfo *FII = FD->getIdentifier();
+ if (FII)
+ return FII->getName();
+
+ // Otherwise construct human readable name for debug info.
+ std::string NS = FD->getNameAsString();
+
+ // Copy this name on the side and use its reference.
+ unsigned Length = NS.length() + 1;
+ char *StrPtr = FunctionNames.Allocate<char>(Length);
+ strncpy(StrPtr, NS.c_str(), Length);
+ return llvm::StringRef(StrPtr);
+}
+
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a new
/// one if necessary. This returns null for invalid source locations.
llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
@@ -972,18 +991,32 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
/// EmitFunctionStart - Constructs the debug code for entering a function -
/// "llvm.dbg.func.start.".
-void CGDebugInfo::EmitFunctionStart(llvm::StringRef Name, QualType FnType,
+void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
llvm::Function *Fn,
CGBuilderTy &Builder) {
- llvm::StringRef LinkageName(Name);
- // Skip the asm prefix if it exists.
- //
- // FIXME: This should probably be the unmangled name?
- if (Name[0] == '\01')
- Name = Name.substr(1);
+ llvm::StringRef Name;
+ llvm::StringRef LinkageName;
+
+ const Decl *D = GD.getDecl();
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ Name = getFunctionName(FD);
+ if (Name[0] == '\01')
+ Name = Name.substr(1);
+ // Use mangled name as linkage name for c/c++ functions.
+ LinkageName = CGM.getMangledName(GD);
+ } else {
+ // Use llvm function name as linkage name.
+ Name = Fn->getName();
+ // Skip the asm prefix if it exists.
+ if (Name[0] == '\01')
+ Name = Name.substr(1);
+ LinkageName = Name;
+ }
- // FIXME: Why is this using CurLoc???
+ // It is expected that CurLoc is set before using EmitFunctionStart.
+ // Usually, CurLoc points to the left bracket location of compound
+ // statement representing function body.
llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc);
SourceManager &SM = CGM.getContext().getSourceManager();
unsigned LineNo = SM.getPresumedLoc(CurLoc).getLine();
@@ -1379,7 +1412,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
else
Unit = llvm::DICompileUnit();
- uint64_t offset = CGF->BlockDecls[Decl];
+ CharUnits offset = CGF->BlockDecls[Decl];
llvm::SmallVector<llvm::Value *, 9> addr;
llvm::LLVMContext &VMContext = CGM.getLLVMContext();
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
@@ -1387,22 +1420,24 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
llvm::DIFactory::OpPlus));
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset));
+ offset.getQuantity()));
if (BDRE->isByRef()) {
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
llvm::DIFactory::OpDeref));
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
llvm::DIFactory::OpPlus));
- offset = CGF->LLVMPointerWidth/8; // offset of __forwarding field
+ // offset of __forwarding field
+ offset = CharUnits::fromQuantity(CGF->LLVMPointerWidth/8);
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset));
+ offset.getQuantity()));
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
llvm::DIFactory::OpDeref));
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
llvm::DIFactory::OpPlus));
- offset = XOffset/8; // offset of x field
+ // offset of x field
+ offset = CharUnits::fromQuantity(XOffset/8);
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset));
+ offset.getQuantity()));
}
// Create the descriptor for the variable.
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 7df2a62..8e88988 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -20,6 +20,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/Analysis/DebugInfo.h"
#include "llvm/Support/ValueHandle.h"
+#include "llvm/Support/Allocator.h"
#include <map>
#include "CGBuilder.h"
@@ -35,6 +36,7 @@ namespace clang {
namespace CodeGen {
class CodeGenModule;
class CodeGenFunction;
+ class GlobalDecl;
/// CGDebugInfo - This class gathers all debug information during compilation
/// and is responsible for emitting to llvm globals or pass directly to
@@ -58,6 +60,10 @@ class CGDebugInfo {
std::vector<llvm::TrackingVH<llvm::MDNode> > RegionStack;
+ /// FunctionNames - This is a storage for function names that are
+ /// constructed on demand. For example, C++ destructors, C++ operators etc..
+ llvm::BumpPtrAllocator FunctionNames;
+
/// Helper functions for getOrCreateType.
llvm::DIType CreateType(const BuiltinType *Ty, llvm::DICompileUnit U);
llvm::DIType CreateType(const ComplexType *Ty, llvm::DICompileUnit U);
@@ -93,7 +99,7 @@ public:
/// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate
/// start of a new function.
- void EmitFunctionStart(llvm::StringRef Name, QualType FnType,
+ void EmitFunctionStart(GlobalDecl GD, QualType FnType,
llvm::Function *Fn, CGBuilderTy &Builder);
/// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start
@@ -149,6 +155,11 @@ private:
/// CreateTypeNode - Create type metadata for a source language type.
llvm::DIType CreateTypeNode(QualType Ty, llvm::DICompileUnit Unit);
+
+ /// getFunctionName - Get function name for the given FunctionDecl. If the
+ /// name is constructred on demand (e.g. C++ destructor) then the name
+ /// is stored on the side.
+ llvm::StringRef getFunctionName(const FunctionDecl *FD);
};
} // namespace CodeGen
} // namespace clang
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 602cc9e..9606a71 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -473,7 +473,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
llvm::IntegerType::get(VMContext, LLVMPointerWidth);
llvm::Value *SizeVal =
llvm::ConstantInt::get(IntPtr,
- getContext().getTypeSizeInChars(Ty).getRaw());
+ getContext().getTypeSizeInChars(Ty).getQuantity());
const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext);
if (Loc->getType() != BP)
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 0b6ea5a..47773a0 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -120,6 +120,22 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
}
void
+CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D) {
+ const llvm::FunctionType *FTy
+ = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ false);
+
+ // Create a variable initialization function.
+ llvm::Function *Fn =
+ llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
+ "__cxx_global_var_init", &TheModule);
+
+ CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D);
+
+ CXXGlobalInits.push_back(Fn);
+}
+
+void
CodeGenModule::EmitCXXGlobalInitFunc() {
if (CXXGlobalInits.empty())
return;
@@ -140,18 +156,26 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
AddGlobalCtor(Fn);
}
+void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
+ const VarDecl *D) {
+ StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
+ SourceLocation());
+
+ llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
+ EmitCXXGlobalVarDeclInit(*D, DeclPtr);
+
+ FinishFunction();
+}
+
void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
- const VarDecl **Decls,
+ llvm::Constant **Decls,
unsigned NumDecls) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
SourceLocation());
- for (unsigned i = 0; i != NumDecls; ++i) {
- const VarDecl *D = Decls[i];
+ for (unsigned i = 0; i != NumDecls; ++i)
+ Builder.CreateCall(Decls[i]);
- llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
- EmitCXXGlobalVarDeclInit(*D, DeclPtr);
- }
FinishFunction();
}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index ab451cf..2358bb3 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -240,6 +240,132 @@ void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) {
EmitBlock(Cont);
}
+
+llvm::Value *CodeGenFunction::
+EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
+ bool isInc, bool isPre) {
+ QualType ValTy = E->getSubExpr()->getType();
+ llvm::Value *InVal = EmitLoadOfLValue(LV, ValTy).getScalarVal();
+
+ int AmountVal = isInc ? 1 : -1;
+
+ if (ValTy->isPointerType() &&
+ ValTy->getAs<PointerType>()->isVariableArrayType()) {
+ // The amount of the addition/subtraction needs to account for the VLA size
+ ErrorUnsupported(E, "VLA pointer inc/dec");
+ }
+
+ llvm::Value *NextVal;
+ if (const llvm::PointerType *PT =
+ dyn_cast<llvm::PointerType>(InVal->getType())) {
+ llvm::Constant *Inc =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), AmountVal);
+ if (!isa<llvm::FunctionType>(PT->getElementType())) {
+ QualType PTEE = ValTy->getPointeeType();
+ if (const ObjCInterfaceType *OIT =
+ dyn_cast<ObjCInterfaceType>(PTEE)) {
+ // Handle interface types, which are not represented with a concrete
+ // type.
+ int size = getContext().getTypeSize(OIT) / 8;
+ if (!isInc)
+ size = -size;
+ Inc = llvm::ConstantInt::get(Inc->getType(), size);
+ const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
+ InVal = Builder.CreateBitCast(InVal, i8Ty);
+ NextVal = Builder.CreateGEP(InVal, Inc, "add.ptr");
+ llvm::Value *lhs = LV.getAddress();
+ lhs = Builder.CreateBitCast(lhs, llvm::PointerType::getUnqual(i8Ty));
+ LV = LValue::MakeAddr(lhs, MakeQualifiers(ValTy));
+ } else
+ NextVal = Builder.CreateInBoundsGEP(InVal, Inc, "ptrincdec");
+ } else {
+ const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
+ NextVal = Builder.CreateBitCast(InVal, i8Ty, "tmp");
+ NextVal = Builder.CreateGEP(NextVal, Inc, "ptrincdec");
+ NextVal = Builder.CreateBitCast(NextVal, InVal->getType());
+ }
+ } else if (InVal->getType() == llvm::Type::getInt1Ty(VMContext) && isInc) {
+ // Bool++ is an interesting case, due to promotion rules, we get:
+ // Bool++ -> Bool = Bool+1 -> Bool = (int)Bool+1 ->
+ // Bool = ((int)Bool+1) != 0
+ // An interesting aspect of this is that increment is always true.
+ // Decrement does not have this property.
+ NextVal = llvm::ConstantInt::getTrue(VMContext);
+ } else if (isa<llvm::IntegerType>(InVal->getType())) {
+ NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal);
+
+ // Signed integer overflow is undefined behavior.
+ if (ValTy->isSignedIntegerType())
+ NextVal = Builder.CreateNSWAdd(InVal, NextVal, isInc ? "inc" : "dec");
+ else
+ NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec");
+ } else {
+ // Add the inc/dec to the real part.
+ if (InVal->getType()->isFloatTy())
+ NextVal =
+ llvm::ConstantFP::get(VMContext,
+ llvm::APFloat(static_cast<float>(AmountVal)));
+ else if (InVal->getType()->isDoubleTy())
+ NextVal =
+ llvm::ConstantFP::get(VMContext,
+ llvm::APFloat(static_cast<double>(AmountVal)));
+ else {
+ llvm::APFloat F(static_cast<float>(AmountVal));
+ bool ignored;
+ F.convert(Target.getLongDoubleFormat(), llvm::APFloat::rmTowardZero,
+ &ignored);
+ NextVal = llvm::ConstantFP::get(VMContext, F);
+ }
+ NextVal = Builder.CreateFAdd(InVal, NextVal, isInc ? "inc" : "dec");
+ }
+
+ // Store the updated result through the lvalue.
+ if (LV.isBitfield())
+ EmitStoreThroughBitfieldLValue(RValue::get(NextVal), LV, ValTy, &NextVal);
+ else
+ EmitStoreThroughLValue(RValue::get(NextVal), LV, ValTy);
+
+ // If this is a postinc, return the value read from memory, otherwise use the
+ // updated value.
+ return isPre ? NextVal : InVal;
+}
+
+
+CodeGenFunction::ComplexPairTy CodeGenFunction::
+EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
+ bool isInc, bool isPre) {
+ ComplexPairTy InVal = LoadComplexFromAddr(LV.getAddress(),
+ LV.isVolatileQualified());
+
+ llvm::Value *NextVal;
+ if (isa<llvm::IntegerType>(InVal.first->getType())) {
+ uint64_t AmountVal = isInc ? 1 : -1;
+ NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal, true);
+
+ // Add the inc/dec to the real part.
+ NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
+ } else {
+ QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType();
+ llvm::APFloat FVal(getContext().getFloatTypeSemantics(ElemTy), 1);
+ if (!isInc)
+ FVal.changeSign();
+ NextVal = llvm::ConstantFP::get(getLLVMContext(), FVal);
+
+ // Add the inc/dec to the real part.
+ NextVal = Builder.CreateFAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
+ }
+
+ ComplexPairTy IncVal(NextVal, InVal.second);
+
+ // Store the updated result through the lvalue.
+ StoreComplexToAddr(IncVal, LV.getAddress(), LV.isVolatileQualified());
+
+ // If this is a postinc, return the value read from memory, otherwise use the
+ // updated value.
+ return isPre ? IncVal : InVal;
+}
+
+
//===----------------------------------------------------------------------===//
// LValue Expression Emission
//===----------------------------------------------------------------------===//
@@ -994,8 +1120,16 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
MakeQualifiers(ExprTy));
}
case UnaryOperator::PreInc:
- case UnaryOperator::PreDec:
- return EmitUnsupportedLValue(E, "pre-inc/dec expression");
+ case UnaryOperator::PreDec: {
+ LValue LV = EmitLValue(E->getSubExpr());
+ bool isInc = E->getOpcode() == UnaryOperator::PreInc;
+
+ if (E->getType()->isAnyComplexType())
+ EmitComplexPrePostIncDec(E, LV, isInc, true/*isPre*/);
+ else
+ EmitScalarPrePostIncDec(E, LV, isInc, true/*isPre*/);
+ return LV;
+ }
}
}
@@ -1139,16 +1273,16 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
QualType BaseType = getContext().getBaseElementType(VAT);
- uint64_t BaseTypeSize = getContext().getTypeSize(BaseType) / 8;
+ CharUnits BaseTypeSize = getContext().getTypeSizeInChars(BaseType);
Idx = Builder.CreateUDiv(Idx,
llvm::ConstantInt::get(Idx->getType(),
- BaseTypeSize));
+ BaseTypeSize.getQuantity()));
Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx");
} else if (const ObjCInterfaceType *OIT =
dyn_cast<ObjCInterfaceType>(E->getType())) {
llvm::Value *InterfaceSize =
llvm::ConstantInt::get(Idx->getType(),
- getContext().getTypeSize(OIT) / 8);
+ getContext().getTypeSizeInChars(OIT).getQuantity());
Idx = Builder.CreateMul(Idx, InterfaceSize);
@@ -1211,8 +1345,8 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
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");
+ assert(E->getBase()->getType()->getAs<VectorType>() &&
+ "Result must be a vector");
llvm::Value *Vec = EmitScalarExpr(E->getBase());
// Store the vector to memory (because LValue wants an address).
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index b95fd79..c852d65 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -313,7 +313,8 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) {
"Unexpected member pointer type!");
const DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr());
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl());
+ const CXXMethodDecl *MD =
+ cast<CXXMethodDecl>(DRE->getDecl())->getCanonicalDecl();
const llvm::Type *PtrDiffTy =
CGF.ConvertType(CGF.getContext().getPointerDiffType());
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 7992322..e264109 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -15,6 +15,334 @@
using namespace clang;
using namespace CodeGen;
+RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
+ llvm::Value *Callee,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This,
+ llvm::Value *VTT,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) {
+ assert(MD->isInstance() &&
+ "Trying to emit a member call expr on a static method!");
+
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+
+ CallArgList Args;
+
+ // Push the this ptr.
+ Args.push_back(std::make_pair(RValue::get(This),
+ MD->getThisType(getContext())));
+
+ // If there is a VTT parameter, emit it.
+ if (VTT) {
+ QualType T = getContext().getPointerType(getContext().VoidPtrTy);
+ Args.push_back(std::make_pair(RValue::get(VTT), T));
+ }
+
+ // And the rest of the call args
+ EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
+
+ QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
+ return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
+ ReturnValue, Args, MD);
+}
+
+/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
+/// expr can be devirtualized.
+static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) {
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ // This is a record decl. We know the type and can devirtualize it.
+ return VD->getType()->isRecordType();
+ }
+
+ return false;
+ }
+
+ // We can always devirtualize calls on temporary object expressions.
+ if (isa<CXXTemporaryObjectExpr>(Base))
+ return true;
+
+ // And calls on bound temporaries.
+ if (isa<CXXBindTemporaryExpr>(Base))
+ return true;
+
+ // Check if this is a call expr that returns a record type.
+ if (const CallExpr *CE = dyn_cast<CallExpr>(Base))
+ return CE->getCallReturnType()->isRecordType();
+
+ // We can't devirtualize the call.
+ return false;
+}
+
+RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
+ ReturnValueSlot ReturnValue) {
+ if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens()))
+ return EmitCXXMemberPointerCallExpr(CE, ReturnValue);
+
+ const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens());
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
+
+ if (MD->isStatic()) {
+ // The method is static, emit it as we would a regular call.
+ llvm::Value *Callee = CGM.GetAddrOfFunction(MD);
+ return EmitCall(getContext().getPointerType(MD->getType()), Callee,
+ ReturnValue, CE->arg_begin(), CE->arg_end());
+ }
+
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+ llvm::Value *This;
+
+ if (ME->isArrow())
+ This = EmitScalarExpr(ME->getBase());
+ else {
+ LValue BaseLV = EmitLValue(ME->getBase());
+ This = BaseLV.getAddress();
+ }
+
+ if (MD->isCopyAssignment() && MD->isTrivial()) {
+ // We don't like to generate the trivial copy assignment operator when
+ // it isn't necessary; just produce the proper effect here.
+ llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress();
+ EmitAggregateCopy(This, RHS, CE->getType());
+ return RValue::get(This);
+ }
+
+ // C++ [class.virtual]p12:
+ // Explicit qualification with the scope operator (5.1) suppresses the
+ // virtual call mechanism.
+ //
+ // We also don't emit a virtual call if the base expression has a record type
+ // because then we know what the type is.
+ llvm::Value *Callee;
+ if (const CXXDestructorDecl *Destructor
+ = dyn_cast<CXXDestructorDecl>(MD)) {
+ if (Destructor->isTrivial())
+ return RValue::get(0);
+ if (MD->isVirtual() && !ME->hasQualifier() &&
+ !canDevirtualizeMemberFunctionCalls(ME->getBase())) {
+ Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty);
+ } else {
+ Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty);
+ }
+ } else if (MD->isVirtual() && !ME->hasQualifier() &&
+ !canDevirtualizeMemberFunctionCalls(ME->getBase())) {
+ Callee = BuildVirtualCall(MD, This, Ty);
+ } else {
+ Callee = CGM.GetAddrOfFunction(MD, Ty);
+ }
+
+ return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
+ CE->arg_begin(), CE->arg_end());
+}
+
+RValue
+CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
+ ReturnValueSlot ReturnValue) {
+ const BinaryOperator *BO =
+ cast<BinaryOperator>(E->getCallee()->IgnoreParens());
+ const Expr *BaseExpr = BO->getLHS();
+ const Expr *MemFnExpr = BO->getRHS();
+
+ const MemberPointerType *MPT =
+ MemFnExpr->getType()->getAs<MemberPointerType>();
+ const FunctionProtoType *FPT =
+ MPT->getPointeeType()->getAs<FunctionProtoType>();
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
+
+ const llvm::FunctionType *FTy =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
+ FPT->isVariadic());
+
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8Ty(VMContext)->getPointerTo();
+
+ // Get the member function pointer.
+ llvm::Value *MemFnPtr =
+ CreateTempAlloca(ConvertType(MemFnExpr->getType()), "mem.fn");
+ EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false);
+
+ // Emit the 'this' pointer.
+ llvm::Value *This;
+
+ if (BO->getOpcode() == BinaryOperator::PtrMemI)
+ This = EmitScalarExpr(BaseExpr);
+ else
+ This = EmitLValue(BaseExpr).getAddress();
+
+ // Adjust it.
+ llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1);
+ Adj = Builder.CreateLoad(Adj, "mem.fn.adj");
+
+ llvm::Value *Ptr = Builder.CreateBitCast(This, Int8PtrTy, "ptr");
+ Ptr = Builder.CreateGEP(Ptr, Adj, "adj");
+
+ This = Builder.CreateBitCast(Ptr, This->getType(), "this");
+
+ llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr");
+
+ const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
+
+ llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn");
+
+ // If the LSB in the function pointer is 1, the function pointer points to
+ // a virtual function.
+ llvm::Value *IsVirtual
+ = Builder.CreateAnd(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1),
+ "and");
+
+ IsVirtual = Builder.CreateTrunc(IsVirtual,
+ llvm::Type::getInt1Ty(VMContext));
+
+ llvm::BasicBlock *FnVirtual = createBasicBlock("fn.virtual");
+ llvm::BasicBlock *FnNonVirtual = createBasicBlock("fn.nonvirtual");
+ llvm::BasicBlock *FnEnd = createBasicBlock("fn.end");
+
+ Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual);
+ EmitBlock(FnVirtual);
+
+ const llvm::Type *VTableTy =
+ FTy->getPointerTo()->getPointerTo()->getPointerTo();
+
+ llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy);
+ VTable = Builder.CreateLoad(VTable);
+
+ VTable = Builder.CreateGEP(VTable, FnAsInt, "fn");
+
+ // Since the function pointer is 1 plus the virtual table offset, we
+ // subtract 1 by using a GEP.
+ VTable = Builder.CreateConstGEP1_64(VTable, (uint64_t)-1);
+
+ llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn");
+
+ EmitBranch(FnEnd);
+ EmitBlock(FnNonVirtual);
+
+ // If the function is not virtual, just load the pointer.
+ llvm::Value *NonVirtualFn = Builder.CreateLoad(FnPtr, "fn");
+ NonVirtualFn = Builder.CreateIntToPtr(NonVirtualFn, FTy->getPointerTo());
+
+ EmitBlock(FnEnd);
+
+ llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo());
+ Callee->reserveOperandSpace(2);
+ Callee->addIncoming(VirtualFn, FnVirtual);
+ Callee->addIncoming(NonVirtualFn, FnNonVirtual);
+
+ CallArgList Args;
+
+ QualType ThisType =
+ getContext().getPointerType(getContext().getTagDeclType(RD));
+
+ // Push the this ptr.
+ Args.push_back(std::make_pair(RValue::get(This), ThisType));
+
+ // 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,
+ ReturnValue, Args);
+}
+
+RValue
+CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
+ const CXXMethodDecl *MD,
+ ReturnValueSlot ReturnValue) {
+ assert(MD->isInstance() &&
+ "Trying to emit a member call expr on a static method!");
+
+ if (MD->isCopyAssignment()) {
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext());
+ if (ClassDecl->hasTrivialCopyAssignment()) {
+ assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
+ "EmitCXXOperatorMemberCallExpr - user declared copy assignment");
+ llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
+ llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
+ QualType Ty = E->getType();
+ EmitAggregateCopy(This, Src, Ty);
+ return RValue::get(This);
+ }
+ }
+
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+
+ llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
+
+ llvm::Value *Callee;
+ if (MD->isVirtual() && !canDevirtualizeMemberFunctionCalls(E->getArg(0)))
+ Callee = BuildVirtualCall(MD, This, Ty);
+ else
+ Callee = CGM.GetAddrOfFunction(MD, Ty);
+
+ return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
+ E->arg_begin() + 1, E->arg_end());
+}
+
+void
+CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
+ const CXXConstructExpr *E) {
+ assert(Dest && "Must have a destination!");
+ const CXXConstructorDecl *CD = E->getConstructor();
+ const ConstantArrayType *Array =
+ 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()) {
+ QualType InitType = E->getType();
+ if (Array)
+ InitType = getContext().getBaseElementType(Array);
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(InitType->getAs<RecordType>()->getDecl());
+ if (RD->hasTrivialConstructor())
+ 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))
+ Arg = BindExpr->getSubExpr();
+
+ EmitAggExpr(Arg, Dest, false);
+ return;
+ }
+ if (Array) {
+ QualType BaseElementTy = getContext().getBaseElementType(Array);
+ const llvm::Type *BasePtr = ConvertType(BaseElementTy);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ Builder.CreateBitCast(Dest, BasePtr);
+
+ EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
+ E->arg_begin(), E->arg_end());
+ }
+ else
+ // Call the constructor.
+ EmitCXXConstructorCall(CD, Ctor_Complete, Dest,
+ E->arg_begin(), E->arg_end());
+}
+
static uint64_t CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) {
const RecordType *RT = ElementType->getAs<RecordType>();
if (!RT)
@@ -405,7 +733,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
/*isVariadic=*/false);
llvm::Value *Callee = BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty);
- EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, 0, 0);
+ EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, /*VTT=*/0,
+ 0, 0);
// The dtor took care of deleting the object.
ShouldCallDelete = false;
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index be2239f..5ec336c 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -145,7 +145,10 @@ public:
// Operators.
ComplexPairTy VisitPrePostIncDec(const UnaryOperator *E,
- bool isInc, bool isPre);
+ bool isInc, bool isPre) {
+ LValue LV = CGF.EmitLValue(E->getSubExpr());
+ return CGF.EmitComplexPrePostIncDec(E, LV, isInc, isPre);
+ }
ComplexPairTy VisitUnaryPostDec(const UnaryOperator *E) {
return VisitPrePostIncDec(E, false, false);
}
@@ -355,40 +358,6 @@ ComplexPairTy ComplexExprEmitter::EmitCast(Expr *Op, QualType DestTy) {
return ComplexPairTy(Elt, llvm::Constant::getNullValue(Elt->getType()));
}
-ComplexPairTy ComplexExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
- bool isInc, bool isPre) {
- LValue LV = CGF.EmitLValue(E->getSubExpr());
- ComplexPairTy InVal = EmitLoadOfComplex(LV.getAddress(),
- LV.isVolatileQualified());
-
- llvm::Value *NextVal;
- if (isa<llvm::IntegerType>(InVal.first->getType())) {
- uint64_t AmountVal = isInc ? 1 : -1;
- NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal, true);
-
- // Add the inc/dec to the real part.
- NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
- } else {
- QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType();
- llvm::APFloat FVal(CGF.getContext().getFloatTypeSemantics(ElemTy), 1);
- if (!isInc)
- FVal.changeSign();
- NextVal = llvm::ConstantFP::get(CGF.getLLVMContext(), FVal);
-
- // Add the inc/dec to the real part.
- NextVal = Builder.CreateFAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
- }
-
- ComplexPairTy IncVal(NextVal, InVal.second);
-
- // Store the updated result through the lvalue.
- EmitStoreOfComplex(IncVal, LV.getAddress(), LV.isVolatileQualified());
-
- // If this is a postinc, return the value read from memory, otherwise use the
- // updated value.
- return isPre ? IncVal : InVal;
-}
-
ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
TestAndClearIgnoreReal();
TestAndClearIgnoreImag();
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index d428983..dec06e2 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -408,6 +408,8 @@ public:
llvm::Constant *EmitMemberFunctionPointer(CXXMethodDecl *MD) {
assert(MD->isInstance() && "Member function must not be static!");
+ MD = MD->getCanonicalDecl();
+
const llvm::Type *PtrDiffTy =
CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
@@ -633,32 +635,6 @@ public:
return ConstStructBuilder::BuildStruct(CGM, CGF, ILE);
}
- llvm::Constant *EmitVectorInitialization(InitListExpr *ILE) {
- const llvm::VectorType *VType =
- cast<llvm::VectorType>(ConvertType(ILE->getType()));
- const llvm::Type *ElemTy = VType->getElementType();
- std::vector<llvm::Constant*> Elts;
- unsigned NumElements = VType->getNumElements();
- unsigned NumInitElements = ILE->getNumInits();
-
- unsigned NumInitableElts = std::min(NumInitElements, NumElements);
-
- // Copy initializer elements.
- unsigned i = 0;
- for (; i < NumInitableElts; ++i) {
- Expr *Init = ILE->getInit(i);
- llvm::Constant *C = CGM.EmitConstantExpr(Init, Init->getType(), CGF);
- if (!C)
- return 0;
- Elts.push_back(C);
- }
-
- for (; i < NumElements; ++i)
- Elts.push_back(llvm::Constant::getNullValue(ElemTy));
-
- return llvm::ConstantVector::get(VType, Elts);
- }
-
llvm::Constant *VisitImplicitValueInitExpr(ImplicitValueInitExpr* E) {
return CGM.EmitNullConstant(E->getType());
}
@@ -682,8 +658,9 @@ public:
if (ILE->getType()->isUnionType())
return EmitUnionInitialization(ILE);
+ // If ILE was a constant vector, we would have handled it already.
if (ILE->getType()->isVectorType())
- return EmitVectorInitialization(ILE);
+ return 0;
assert(0 && "Unable to handle InitListExpr");
// Get rid of control reaches end of void function warning.
@@ -833,7 +810,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
const llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType);
llvm::Constant *Offset =
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- Result.Val.getLValueOffset());
+ Result.Val.getLValueOffset().getQuantity());
llvm::Constant *C;
if (const Expr *LVBase = Result.Val.getLValueBase()) {
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 93646d6..690a7dc 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -181,12 +181,6 @@ public:
Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
return EmitLoadOfLValue(E);
}
- Value *VisitStringLiteral(Expr *E) { return EmitLValue(E).getAddress(); }
- Value *VisitObjCEncodeExpr(const ObjCEncodeExpr *E) {
- return EmitLValue(E).getAddress();
- }
-
- Value *VisitPredefinedExpr(Expr *E) { return EmitLValue(E).getAddress(); }
Value *VisitInitListExpr(InitListExpr *E);
@@ -214,7 +208,10 @@ public:
Value *VisitBlockDeclRefExpr(const BlockDeclRefExpr *E);
// Unary Operators.
- Value *VisitPrePostIncDec(const UnaryOperator *E, bool isInc, bool isPre);
+ Value *VisitPrePostIncDec(const UnaryOperator *E, bool isInc, bool isPre) {
+ LValue LV = EmitLValue(E->getSubExpr());
+ return CGF.EmitScalarPrePostIncDec(E, LV, isInc, isPre);
+ }
Value *VisitUnaryPostDec(const UnaryOperator *E) {
return VisitPrePostIncDec(E, false, false);
}
@@ -1009,98 +1006,6 @@ Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
// Unary Operators
//===----------------------------------------------------------------------===//
-Value *ScalarExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
- bool isInc, bool isPre) {
- LValue LV = EmitLValue(E->getSubExpr());
- QualType ValTy = E->getSubExpr()->getType();
- Value *InVal = CGF.EmitLoadOfLValue(LV, ValTy).getScalarVal();
-
- llvm::LLVMContext &VMContext = CGF.getLLVMContext();
-
- int AmountVal = isInc ? 1 : -1;
-
- if (ValTy->isPointerType() &&
- ValTy->getAs<PointerType>()->isVariableArrayType()) {
- // The amount of the addition/subtraction needs to account for the VLA size
- CGF.ErrorUnsupported(E, "VLA pointer inc/dec");
- }
-
- Value *NextVal;
- if (const llvm::PointerType *PT =
- dyn_cast<llvm::PointerType>(InVal->getType())) {
- llvm::Constant *Inc =
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), AmountVal);
- if (!isa<llvm::FunctionType>(PT->getElementType())) {
- QualType PTEE = ValTy->getPointeeType();
- if (const ObjCInterfaceType *OIT =
- dyn_cast<ObjCInterfaceType>(PTEE)) {
- // Handle interface types, which are not represented with a concrete type.
- int size = CGF.getContext().getTypeSize(OIT) / 8;
- if (!isInc)
- size = -size;
- Inc = llvm::ConstantInt::get(Inc->getType(), size);
- const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
- InVal = Builder.CreateBitCast(InVal, i8Ty);
- NextVal = Builder.CreateGEP(InVal, Inc, "add.ptr");
- llvm::Value *lhs = LV.getAddress();
- lhs = Builder.CreateBitCast(lhs, llvm::PointerType::getUnqual(i8Ty));
- LV = LValue::MakeAddr(lhs, CGF.MakeQualifiers(ValTy));
- } else
- NextVal = Builder.CreateInBoundsGEP(InVal, Inc, "ptrincdec");
- } else {
- const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
- NextVal = Builder.CreateBitCast(InVal, i8Ty, "tmp");
- NextVal = Builder.CreateGEP(NextVal, Inc, "ptrincdec");
- NextVal = Builder.CreateBitCast(NextVal, InVal->getType());
- }
- } else if (InVal->getType() == llvm::Type::getInt1Ty(VMContext) && isInc) {
- // Bool++ is an interesting case, due to promotion rules, we get:
- // Bool++ -> Bool = Bool+1 -> Bool = (int)Bool+1 ->
- // Bool = ((int)Bool+1) != 0
- // An interesting aspect of this is that increment is always true.
- // Decrement does not have this property.
- NextVal = llvm::ConstantInt::getTrue(VMContext);
- } else if (isa<llvm::IntegerType>(InVal->getType())) {
- NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal);
-
- // Signed integer overflow is undefined behavior.
- if (ValTy->isSignedIntegerType())
- NextVal = Builder.CreateNSWAdd(InVal, NextVal, isInc ? "inc" : "dec");
- else
- NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec");
- } else {
- // Add the inc/dec to the real part.
- if (InVal->getType()->isFloatTy())
- NextVal =
- llvm::ConstantFP::get(VMContext,
- llvm::APFloat(static_cast<float>(AmountVal)));
- else if (InVal->getType()->isDoubleTy())
- NextVal =
- llvm::ConstantFP::get(VMContext,
- llvm::APFloat(static_cast<double>(AmountVal)));
- else {
- llvm::APFloat F(static_cast<float>(AmountVal));
- bool ignored;
- F.convert(CGF.Target.getLongDoubleFormat(), llvm::APFloat::rmTowardZero,
- &ignored);
- NextVal = llvm::ConstantFP::get(VMContext, F);
- }
- NextVal = Builder.CreateFAdd(InVal, NextVal, isInc ? "inc" : "dec");
- }
-
- // Store the updated result through the lvalue.
- if (LV.isBitfield())
- CGF.EmitStoreThroughBitfieldLValue(RValue::get(NextVal), LV, ValTy,
- &NextVal);
- else
- CGF.EmitStoreThroughLValue(RValue::get(NextVal), LV, ValTy);
-
- // If this is a postinc, return the value read from memory, otherwise use the
- // updated value.
- return isPre ? NextVal : InVal;
-}
-
-
Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
TestAndClearIgnoreResultAssign();
Value *Op = Visit(E->getSubExpr());
@@ -1405,7 +1310,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(ElementType)) {
llvm::Value *InterfaceSize =
llvm::ConstantInt::get(Idx->getType(),
- CGF.getContext().getTypeSize(OIT) / 8);
+ CGF.getContext().getTypeSizeInChars(OIT).getQuantity());
Idx = Builder.CreateMul(Idx, InterfaceSize);
const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
Value *Casted = Builder.CreateBitCast(Ptr, i8Ty);
@@ -1469,7 +1374,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
dyn_cast<ObjCInterfaceType>(LHSElementType)) {
llvm::Value *InterfaceSize =
llvm::ConstantInt::get(Idx->getType(),
- CGF.getContext().getTypeSize(OIT) / 8);
+ CGF.getContext().
+ getTypeSizeInChars(OIT).getQuantity());
Idx = Builder.CreateMul(Idx, InterfaceSize);
const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
Value *LHSCasted = Builder.CreateBitCast(Ops.LHS, i8Ty);
@@ -1493,14 +1399,14 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
Value *LHS = Ops.LHS;
Value *RHS = Ops.RHS;
- uint64_t ElementSize;
+ CharUnits ElementSize;
// Handle GCC extension for pointer arithmetic on void* and function pointer
// types.
if (LHSElementType->isVoidType() || LHSElementType->isFunctionType()) {
- ElementSize = 1;
+ ElementSize = CharUnits::One();
} else {
- ElementSize = CGF.getContext().getTypeSize(LHSElementType) / 8;
+ ElementSize = CGF.getContext().getTypeSizeInChars(LHSElementType);
}
const llvm::Type *ResultType = ConvertType(Ops.Ty);
@@ -1509,13 +1415,14 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub");
// Optimize out the shift for element size of 1.
- if (ElementSize == 1)
+ if (ElementSize.isOne())
return BytesBetween;
// Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since
// pointer difference in C is only defined in the case where both operands
// are pointing to elements of an array.
- Value *BytesPerElt = llvm::ConstantInt::get(ResultType, ElementSize);
+ Value *BytesPerElt =
+ llvm::ConstantInt::get(ResultType, ElementSize.getQuantity());
return Builder.CreateExactSDiv(BytesBetween, BytesPerElt, "sub.ptr.div");
}
}
@@ -1971,47 +1878,6 @@ Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src,
DstTy);
}
-Value *CodeGenFunction::EmitShuffleVector(Value* V1, Value *V2, ...) {
- assert(V1->getType() == V2->getType() &&
- "Vector operands must be of the same type");
- unsigned NumElements =
- cast<llvm::VectorType>(V1->getType())->getNumElements();
-
- va_list va;
- va_start(va, V2);
-
- llvm::SmallVector<llvm::Constant*, 16> Args;
- for (unsigned i = 0; i < NumElements; i++) {
- int n = va_arg(va, int);
- assert(n >= 0 && n < (int)NumElements * 2 &&
- "Vector shuffle index out of bounds!");
- Args.push_back(llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(VMContext), n));
- }
-
- const char *Name = va_arg(va, const char *);
- va_end(va);
-
- llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements);
-
- return Builder.CreateShuffleVector(V1, V2, Mask, Name);
-}
-
-llvm::Value *CodeGenFunction::EmitVector(llvm::Value * const *Vals,
- unsigned NumVals, bool isSplat) {
- llvm::Value *Vec
- = llvm::UndefValue::get(llvm::VectorType::get(Vals[0]->getType(), NumVals));
-
- for (unsigned i = 0, e = NumVals; i != e; ++i) {
- llvm::Value *Val = isSplat ? Vals[0] : Vals[i];
- llvm::Value *Idx = llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(VMContext), i);
- Vec = Builder.CreateInsertElement(Vec, Val, Idx, "tmp");
- }
-
- return Vec;
-}
-
LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
llvm::Value *V;
// object->isa or (*object).isa
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 95f67ae..e7a2093 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -114,9 +114,11 @@ private:
llvm::Constant *ExportUniqueString(const std::string &Str, const std::string
prefix);
llvm::Constant *MakeGlobal(const llvm::StructType *Ty,
- std::vector<llvm::Constant*> &V, const std::string &Name="");
+ std::vector<llvm::Constant*> &V, const std::string &Name="",
+ llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage);
llvm::Constant *MakeGlobal(const llvm::ArrayType *Ty,
- std::vector<llvm::Constant*> &V, const std::string &Name="");
+ std::vector<llvm::Constant*> &V, const std::string &Name="",
+ llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage);
llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar);
void EmitClassRef(const std::string &className);
@@ -215,8 +217,11 @@ static std::string SymbolNameForClass(const std::string &ClassName) {
static std::string SymbolNameForMethod(const std::string &ClassName, const
std::string &CategoryName, const std::string &MethodName, bool isClassMethod)
{
- return "_OBJC_METHOD_" + ClassName + "("+CategoryName+")"+
- (isClassMethod ? "+" : "-") + MethodName;
+ std::string MethodNameColonStripped = MethodName;
+ std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(),
+ ':', '_');
+ return std::string(isClassMethod ? "_c_" : "_i_") + ClassName + "_" +
+ CategoryName + "_" + MethodNameColonStripped;
}
CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
@@ -257,6 +262,10 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder,
const ObjCInterfaceDecl *OID) {
llvm::Value *ClassName = CGM.GetAddrOfConstantCString(OID->getNameAsString());
+ // With the incompatible ABI, this will need to be replaced with a direct
+ // reference to the class symbol. For the compatible nonfragile ABI we are
+ // still performing this lookup at run time but emitting the symbol for the
+ // class externally so that we can make the switch later.
EmitClassRef(OID->getNameAsString());
ClassName = Builder.CreateStructGEP(ClassName, 0);
@@ -323,14 +332,16 @@ llvm::Constant *CGObjCGNU::ExportUniqueString(const std::string &Str,
}
llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty,
- std::vector<llvm::Constant*> &V, const std::string &Name) {
+ std::vector<llvm::Constant*> &V, const std::string &Name,
+ llvm::GlobalValue::LinkageTypes linkage) {
llvm::Constant *C = llvm::ConstantStruct::get(Ty, V);
return new llvm::GlobalVariable(TheModule, Ty, false,
llvm::GlobalValue::InternalLinkage, C, Name);
}
llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty,
- std::vector<llvm::Constant*> &V, const std::string &Name) {
+ std::vector<llvm::Constant*> &V, const std::string &Name,
+ llvm::GlobalValue::LinkageTypes linkage) {
llvm::Constant *C = llvm::ConstantArray::get(Ty, V);
return new llvm::GlobalVariable(TheModule, Ty, false,
llvm::GlobalValue::InternalLinkage, C, Name);
@@ -703,7 +714,10 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
Elements.push_back(IvarOffsets);
Elements.push_back(Properties);
// Create an instance of the structure
- return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name));
+ // This is now an externally visible symbol, so that we can speed up class
+ // messages in the next ABI.
+ return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name),
+ llvm::GlobalValue::ExternalLinkage);
}
llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
@@ -1607,7 +1621,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), "objc_exception_throw");
+ Params, false), "_Unwind_Resume");
bool isTry = isa<ObjCAtTryStmt>(S);
llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try");
@@ -1923,7 +1937,7 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
if (!IvarOffsetPointer) {
uint64_t Offset = ComputeIvarBaseOffset(CGM, ID, Ivar);
llvm::ConstantInt *OffsetGuess =
- llvm::ConstantInt::get(LongTy, Offset, "ivar");
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Offset, "ivar");
// Don't emit the guess in non-PIC code because the linker will not be able
// to replace it with the real version for a library. In non-PIC code you
// must compile with the fragile ABI if you want to use ivars from a
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index db6c507..29552ce 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -360,28 +360,12 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(QualType Ty) {
// If we're in an anonymous namespace, then we always want internal linkage.
if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
return llvm::GlobalVariable::InternalLinkage;
-
+
+ // If this class does not have a vtable, we want weak linkage.
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;
- }
-
- // If the key function is defined, but inlined, then the RTTI descriptor is
- // emitted with weak_odr linkage.
- const FunctionDecl* KeyFunctionDefinition;
- KeyFunction->getBody(KeyFunctionDefinition);
-
- if (KeyFunctionDefinition->isInlined())
- return llvm::GlobalValue::WeakODRLinkage;
-
- // Otherwise, the RTTI descriptor is emitted with external linkage.
- return llvm::GlobalValue::ExternalLinkage;
+ return CodeGenModule::getVtableLinkage(RD);
}
case Type::Vector:
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index 7930f71..ae900d6 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -160,17 +160,19 @@ private:
// vtable for use in computing the initializers for the VTT.
llvm::DenseMap<CtorVtable_t, int64_t> &subAddressPoints;
+ /// AddressPoints - Address points for this vtable.
+ CGVtableInfo::AddressPointsMapTy& AddressPoints;
+
typedef CXXRecordDecl::method_iterator method_iter;
- const bool Extern;
const uint32_t LLVMPointerWidth;
Index_t extra;
typedef std::vector<std::pair<const CXXRecordDecl *, int64_t> > Path_t;
static llvm::DenseMap<CtorVtable_t, int64_t>&
AllocAddressPoint(CodeGenModule &cgm, const CXXRecordDecl *l,
const CXXRecordDecl *c) {
- CodeGenModule::AddrMap_t *&oref = cgm.AddressPoints[l];
+ CGVtableInfo::AddrMap_t *&oref = cgm.getVtableInfo().AddressPoints[l];
if (oref == 0)
- oref = new CodeGenModule::AddrMap_t;
+ oref = new CGVtableInfo::AddrMap_t;
llvm::DenseMap<CtorVtable_t, int64_t> *&ref = (*oref)[c];
if (ref == 0)
@@ -193,14 +195,15 @@ private:
public:
VtableBuilder(const CXXRecordDecl *MostDerivedClass,
const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm,
- bool build)
+ bool build, CGVtableInfo::AddressPointsMapTy& AddressPoints)
: BuildVtable(build), MostDerivedClass(MostDerivedClass), LayoutClass(l),
LayoutOffset(lo), BLayout(cgm.getContext().getASTRecordLayout(l)),
rtti(0), VMContext(cgm.getModule().getContext()),CGM(cgm),
PureVirtualFn(0),
subAddressPoints(AllocAddressPoint(cgm, l, MostDerivedClass)),
- Extern(!l->isInAnonymousNamespace()),
- LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) {
+ AddressPoints(AddressPoints),
+ LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0))
+ {
Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
if (BuildVtable) {
QualType ClassType = CGM.getContext().getTagDeclType(MostDerivedClass);
@@ -213,7 +216,7 @@ public:
return VtableComponents;
}
- llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex()
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getVBIndex()
{ return VBIndex; }
SavedAdjustmentsVectorTy &getSavedAdjustments()
@@ -463,6 +466,7 @@ public:
RD->getNameAsCString(), Class->getNameAsCString(),
LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
+ AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint;
// Now also add the address point for all our primary bases.
while (1) {
@@ -479,6 +483,7 @@ public:
RD->getNameAsCString(), Class->getNameAsCString(),
LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
+ AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint;
}
}
@@ -827,7 +832,6 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
MD->getNameAsString().c_str(), (int)-idx-3,
(int)VCalls[idx-1], Class->getNameAsCString()));
}
- VCall[GD] = idx;
int64_t NonVirtualAdjustment = NonVirtualOffset[GD];
int64_t VirtualAdjustment =
-((idx + extra + 2) * LLVMPointerWidth / 8);
@@ -844,6 +848,7 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
SavedAdjustments.push_back(
std::make_pair(GD, std::make_pair(OGD, ThisAdjustment)));
}
+ VCall[GD] = idx;
return true;
}
@@ -1090,7 +1095,8 @@ CGVtableInfo::getAdjustments(GlobalDecl GD) {
if (!SavedAdjustmentRecords.insert(RD).second)
return 0;
- VtableBuilder b(RD, RD, 0, CGM, false);
+ AddressPointsMapTy AddressPoints;
+ VtableBuilder b(RD, RD, 0, CGM, false, AddressPoints);
D1(printf("vtable %s\n", RD->getNameAsCString()));
b.GenerateVtableForBase(RD);
b.GenerateVtableForVBases(RD);
@@ -1118,7 +1124,8 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
// FIXME: This seems expensive. Can we do a partial job to get
// just this data.
- VtableBuilder b(RD, RD, 0, CGM, false);
+ AddressPointsMapTy AddressPoints;
+ VtableBuilder b(RD, RD, 0, CGM, false, AddressPoints);
D1(printf("vtable %s\n", RD->getNameAsCString()));
b.GenerateVtableForBase(RD);
b.GenerateVtableForVBases(RD);
@@ -1139,7 +1146,7 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
uint64_t CGVtableInfo::getVtableAddressPoint(const CXXRecordDecl *RD) {
uint64_t AddressPoint =
- (*(*(CGM.AddressPoints[RD]))[RD])[std::make_pair(RD, 0)];
+ (*(*(CGM.getVtableInfo().AddressPoints[RD]))[RD])[std::make_pair(RD, 0)];
return AddressPoint;
}
@@ -1148,7 +1155,8 @@ llvm::GlobalVariable *
CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
bool GenerateDefinition,
const CXXRecordDecl *LayoutClass,
- const CXXRecordDecl *RD, uint64_t Offset) {
+ const CXXRecordDecl *RD, uint64_t Offset,
+ AddressPointsMapTy& AddressPoints) {
llvm::SmallString<256> OutName;
if (LayoutClass != RD)
CGM.getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset / 8,
@@ -1158,8 +1166,10 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
llvm::StringRef Name = OutName.str();
llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
- if (GV == 0 || CGM.AddressPoints[LayoutClass] == 0 || GV->isDeclaration()) {
- VtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition);
+ if (GV == 0 || CGM.getVtableInfo().AddressPoints[LayoutClass] == 0 ||
+ GV->isDeclaration()) {
+ VtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition,
+ AddressPoints);
D1(printf("vtable %s\n", RD->getNameAsCString()));
// First comes the vtables for all the non-virtual bases...
@@ -1206,11 +1216,51 @@ class VTTBuilder {
/// BLayout - Layout for the most derived class that this vtable is being
/// built for.
const ASTRecordLayout &BLayout;
- CodeGenModule::AddrMap_t &AddressPoints;
+ CGVtableInfo::AddrMap_t &AddressPoints;
// vtbl - A pointer to the vtable for Class.
llvm::Constant *ClassVtbl;
llvm::LLVMContext &VMContext;
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies;
+
+ bool GenerateDefinition;
+
+ llvm::DenseMap<BaseSubobject, llvm::Constant *> CtorVtables;
+ llvm::DenseMap<std::pair<const CXXRecordDecl *, BaseSubobject>, uint64_t>
+ CtorVtableAddressPoints;
+
+ llvm::Constant *getCtorVtable(const BaseSubobject &Base) {
+ if (!GenerateDefinition)
+ return 0;
+
+ llvm::Constant *&CtorVtable = CtorVtables[Base];
+ if (!CtorVtable) {
+ // Build the vtable.
+ CGVtableInfo::CtorVtableInfo Info
+ = CGM.getVtableInfo().getCtorVtable(Class, Base);
+
+ CtorVtable = Info.Vtable;
+
+ // Add the address points for this base.
+ for (CGVtableInfo::AddressPointsMapTy::const_iterator I =
+ Info.AddressPoints.begin(), E = Info.AddressPoints.end();
+ I != E; ++I) {
+ uint64_t &AddressPoint =
+ CtorVtableAddressPoints[std::make_pair(Base.getBase(), I->first)];
+
+ // Check if we already have the address points for this base.
+ if (AddressPoint)
+ break;
+
+ // Otherwise, insert it.
+ AddressPoint = I->second;
+ }
+ }
+
+ return CtorVtable;
+ }
+
+
/// BuildVtablePtr - Build up a referene to the given secondary vtable
llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable,
const CXXRecordDecl *VtableClass,
@@ -1270,14 +1320,17 @@ class VTTBuilder {
// FIXME: Slightly too many of these for __ZTT8test8_B2
llvm::Constant *init;
if (BaseMorallyVirtual)
- init = BuildVtablePtr(vtbl, VtblClass, RD, Offset);
+ init = GenerateDefinition ?
+ BuildVtablePtr(vtbl, VtblClass, RD, Offset) : 0;
else {
- init = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseOffset);
+ init = GenerateDefinition ?
+ getCtorVtable(BaseSubobject(Base, BaseOffset)) : 0;
subvtbl = init;
subVtblClass = Base;
- init = BuildVtablePtr(init, Class, Base, BaseOffset);
+ init = GenerateDefinition ?
+ BuildVtablePtr(init, Class, Base, BaseOffset) : 0;
}
Inits.push_back(init);
}
@@ -1296,14 +1349,16 @@ class VTTBuilder {
// First comes the primary virtual table pointer...
if (MorallyVirtual) {
- Vtable = ClassVtbl;
+ Vtable = GenerateDefinition ? ClassVtbl : 0;
VtableClass = Class;
} else {
- Vtable = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset);
+ Vtable = GenerateDefinition ?
+ getCtorVtable(BaseSubobject(RD, Offset)) : 0;
VtableClass = RD;
}
- llvm::Constant *Init = BuildVtablePtr(Vtable, VtableClass, RD, Offset);
+ llvm::Constant *Init = GenerateDefinition ?
+ BuildVtablePtr(Vtable, VtableClass, RD, Offset) : 0;
Inits.push_back(Init);
// then the secondary VTTs....
@@ -1326,6 +1381,10 @@ class VTTBuilder {
continue;
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base);
+
+ // Remember the sub-VTT index.
+ SubVTTIndicies[Base] = Inits.size();
+
BuildVTT(Base, BaseOffset, MorallyVirtual);
}
}
@@ -1338,6 +1397,9 @@ class VTTBuilder {
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
if (i->isVirtual() && !SeenVBase.count(Base)) {
+ // Remember the sub-VTT index.
+ SubVTTIndicies[Base] = Inits.size();
+
SeenVBase.insert(Base);
uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
BuildVTT(Base, BaseOffset, true);
@@ -1348,15 +1410,18 @@ class VTTBuilder {
public:
VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c,
- CodeGenModule &cgm)
+ CodeGenModule &cgm, bool GenerateDefinition)
: Inits(inits), Class(c), CGM(cgm),
BLayout(cgm.getContext().getASTRecordLayout(c)),
- AddressPoints(*cgm.AddressPoints[c]),
- VMContext(cgm.getModule().getContext()) {
+ AddressPoints(*cgm.getVtableInfo().AddressPoints[c]),
+ VMContext(cgm.getModule().getContext()),
+ GenerateDefinition(GenerateDefinition) {
// First comes the primary virtual table pointer for the complete class...
ClassVtbl = CGM.getVtableInfo().getVtable(Class);
- Inits.push_back(BuildVtablePtr(ClassVtbl, Class, Class, 0));
+ llvm::Constant *Init = GenerateDefinition ?
+ BuildVtablePtr(ClassVtbl, Class, Class, 0) : 0;
+ Inits.push_back(Init);
// then the secondary VTTs...
SecondaryVTTs(Class);
@@ -1367,11 +1432,16 @@ public:
// and last, the virtual VTTs.
VirtualVTTs(Class);
}
+
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getSubVTTIndicies() {
+ return SubVTTIndicies;
+ }
};
}
llvm::GlobalVariable *
CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
+ bool GenerateDefinition,
const CXXRecordDecl *RD) {
// Only classes that have virtual bases need a VTT.
if (RD->getNumVBases() == 0)
@@ -1381,23 +1451,36 @@ CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
CGM.getMangleContext().mangleCXXVTT(RD, OutName);
llvm::StringRef Name = OutName.str();
-
D1(printf("vtt %s\n", RD->getNameAsCString()));
- std::vector<llvm::Constant *> inits;
- VTTBuilder b(inits, RD, CGM);
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
+ if (GV == 0 || GV->isDeclaration()) {
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size());
-
- llvm::Constant *Init = llvm::ConstantArray::get(Type, inits);
-
- llvm::GlobalVariable *VTT =
- new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true,
- Linkage, Init, Name);
- CGM.setGlobalVisibility(VTT, RD);
+ std::vector<llvm::Constant *> inits;
+ VTTBuilder b(inits, RD, CGM, GenerateDefinition);
+
+ const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size());
+ llvm::Constant *Init = 0;
+ if (GenerateDefinition)
+ Init = llvm::ConstantArray::get(Type, inits);
+
+ llvm::GlobalVariable *OldGV = GV;
+ GV = new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true,
+ Linkage, Init, Name);
+ CGM.setGlobalVisibility(GV, RD);
+
+ if (OldGV) {
+ GV->takeName(OldGV);
+ llvm::Constant *NewPtr =
+ llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
+ OldGV->replaceAllUsesWith(NewPtr);
+ OldGV->eraseFromParent();
+ }
+ }
- return VTT;
+ return GV;
}
void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
@@ -1408,28 +1491,44 @@ void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
return;
}
- Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0);
- GenerateVTT(Linkage, RD);
+ AddressPointsMapTy AddressPoints;
+ Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0,
+ AddressPoints);
+ GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD);
}
llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) {
llvm::GlobalVariable *Vtable = Vtables.lookup(RD);
- if (!Vtable)
+ if (!Vtable) {
+ AddressPointsMapTy AddressPoints;
Vtable = GenerateVtable(llvm::GlobalValue::ExternalLinkage,
- /*GenerateDefinition=*/false, RD, RD, 0);
+ /*GenerateDefinition=*/false, RD, RD, 0,
+ AddressPoints);
+ }
return Vtable;
}
-llvm::GlobalVariable *
-CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass,
- const CXXRecordDecl *RD, uint64_t Offset) {
- return GenerateVtable(llvm::GlobalValue::InternalLinkage,
- /*GenerateDefinition=*/true,
- LayoutClass, RD, Offset);
+CGVtableInfo::CtorVtableInfo
+CGVtableInfo::getCtorVtable(const CXXRecordDecl *RD,
+ const BaseSubobject &Base) {
+ CtorVtableInfo Info;
+
+ Info.Vtable = GenerateVtable(llvm::GlobalValue::InternalLinkage,
+ /*GenerateDefinition=*/true,
+ RD, Base.getBase(), Base.getBaseOffset(),
+ Info.AddressPoints);
+ return Info;
+}
+
+llvm::GlobalVariable *CGVtableInfo::getVTT(const CXXRecordDecl *RD) {
+ return GenerateVTT(llvm::GlobalValue::ExternalLinkage,
+ /*GenerateDefinition=*/false, RD);
+
}
+
void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
const CXXRecordDecl *RD = MD->getParent();
@@ -1445,28 +1544,10 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
// We don't have the right key function.
if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl())
return;
-
- // If the key function is a destructor, we only want to emit the vtable
- // once, so do it for the complete destructor.
- if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Complete)
- return;
- } else {
- // If there is no key function, we only want to emit the vtable if we are
- // emitting a constructor.
- if (!isa<CXXConstructorDecl>(MD) || GD.getCtorType() != Ctor_Complete)
- return;
}
- llvm::GlobalVariable::LinkageTypes Linkage;
- if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
- Linkage = llvm::GlobalVariable::InternalLinkage;
- else if (KeyFunction && !MD->isInlined())
- Linkage = llvm::GlobalVariable::ExternalLinkage;
- else
- Linkage = llvm::GlobalVariable::WeakODRLinkage;
-
// Emit the data.
- GenerateClassData(Linkage, RD);
+ GenerateClassData(CGM.getVtableLinkage(RD), RD);
for (CXXRecordDecl::method_iterator i = RD->method_begin(),
e = RD->method_end(); i != e; ++i) {
@@ -1481,3 +1562,47 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
}
}
+bool CGVtableInfo::needsVTTParameter(GlobalDecl GD) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ // We don't have any virtual bases, just return early.
+ if (!MD->getParent()->getNumVBases())
+ return false;
+
+ // Check if we have a base constructor.
+ if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base)
+ return true;
+
+ // Check if we have a base destructor.
+ if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
+ return true;
+
+ return false;
+}
+
+uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD,
+ const CXXRecordDecl *Base) {
+ ClassPairTy ClassPair(RD, Base);
+
+ SubVTTIndiciesTy::iterator I =
+ SubVTTIndicies.find(ClassPair);
+ if (I != SubVTTIndicies.end())
+ return I->second;
+
+ std::vector<llvm::Constant *> inits;
+ VTTBuilder Builder(inits, RD, CGM, /*GenerateDefinition=*/false);
+
+ for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
+ Builder.getSubVTTIndicies().begin(),
+ E = Builder.getSubVTTIndicies().end(); I != E; ++I) {
+ // Insert all indices.
+ ClassPairTy ClassPair(RD, I->first);
+
+ SubVTTIndicies.insert(std::make_pair(ClassPair, I->second));
+ }
+
+ I = SubVTTIndicies.find(ClassPair);
+ assert(I != SubVTTIndicies.end() && "Did not find index!");
+
+ return I->second;
+}
diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h
index eed5b64..471d638 100644
--- a/lib/CodeGen/CGVtable.h
+++ b/lib/CodeGen/CGVtable.h
@@ -61,11 +61,83 @@ public:
ThunkAdjustment ReturnAdjustment;
};
+// BaseSubobject - Uniquely identifies a direct or indirect base class.
+// Stores both the base class decl and the offset from the most derived class to
+// the base class.
+class BaseSubobject {
+ /// Base - The base class declaration.
+ const CXXRecordDecl *Base;
+
+ /// BaseOffset - The offset from the most derived class to the base class.
+ uint64_t BaseOffset;
+
+public:
+ BaseSubobject(const CXXRecordDecl *Base, uint64_t BaseOffset)
+ : Base(Base), BaseOffset(BaseOffset) { }
+
+ /// getBase - Returns the base class declaration.
+ const CXXRecordDecl *getBase() const { return Base; }
+
+ /// getBaseOffset - Returns the base class offset.
+ uint64_t getBaseOffset() const { return BaseOffset; }
+
+ friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) {
+ return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset;
+ }
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+namespace llvm {
+
+template<> struct DenseMapInfo<clang::CodeGen::BaseSubobject> {
+ static clang::CodeGen::BaseSubobject getEmptyKey() {
+ return clang::CodeGen::BaseSubobject(
+ DenseMapInfo<const clang::CXXRecordDecl *>::getEmptyKey(),
+ DenseMapInfo<uint64_t>::getEmptyKey());
+ }
+
+ static clang::CodeGen::BaseSubobject getTombstoneKey() {
+ return clang::CodeGen::BaseSubobject(
+ DenseMapInfo<const clang::CXXRecordDecl *>::getTombstoneKey(),
+ DenseMapInfo<uint64_t>::getTombstoneKey());
+ }
+
+ static unsigned getHashValue(const clang::CodeGen::BaseSubobject &Base) {
+ return
+ DenseMapInfo<const clang::CXXRecordDecl *>::getHashValue(Base.getBase()) ^
+ DenseMapInfo<uint64_t>::getHashValue(Base.getBaseOffset());
+ }
+
+ static bool isEqual(const clang::CodeGen::BaseSubobject &LHS,
+ const clang::CodeGen::BaseSubobject &RHS) {
+ return LHS == RHS;
+ }
+};
+
+// It's OK to treat BaseSubobject as a POD type.
+template <> struct isPodLike<clang::CodeGen::BaseSubobject> {
+ static const bool value = true;
+};
+
+}
+
+namespace clang {
+namespace CodeGen {
+
class CGVtableInfo {
public:
typedef std::vector<std::pair<GlobalDecl, ThunkAdjustment> >
AdjustmentVectorTy;
+ typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_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;
+
+ typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
+
private:
CodeGenModule &CGM;
@@ -93,6 +165,9 @@ private:
SavedAdjustmentsTy SavedAdjustments;
llvm::DenseSet<const CXXRecordDecl*> SavedAdjustmentRecords;
+ typedef llvm::DenseMap<ClassPairTy, uint64_t> SubVTTIndiciesTy;
+ SubVTTIndiciesTy SubVTTIndicies;
+
/// getNumVirtualFunctionPointers - Return the number of virtual function
/// pointers in the vtable for a given record decl.
uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
@@ -110,15 +185,26 @@ private:
llvm::GlobalVariable *
GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
bool GenerateDefinition, const CXXRecordDecl *LayoutClass,
- const CXXRecordDecl *RD, uint64_t Offset);
+ const CXXRecordDecl *RD, uint64_t Offset,
+ AddressPointsMapTy& AddressPoints);
llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
+ bool GenerateDefinition,
const CXXRecordDecl *RD);
public:
CGVtableInfo(CodeGenModule &CGM)
: CGM(CGM) { }
+ /// needsVTTParameter - Return whether the given global decl needs a VTT
+ /// parameter, which it does if it's a base constructor or destructor with
+ /// virtual bases.
+ static bool needsVTTParameter(GlobalDecl GD);
+
+ /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the
+ /// given record decl.
+ uint64_t getSubVTTIndex(const CXXRecordDecl *RD, const CXXRecordDecl *Base);
+
/// getMethodVtableIndex - Return the index (relative to the vtable address
/// point) where the function pointer for the given virtual function is
/// stored.
@@ -140,14 +226,26 @@ public:
uint64_t getVtableAddressPoint(const CXXRecordDecl *RD);
llvm::GlobalVariable *getVtable(const CXXRecordDecl *RD);
- llvm::GlobalVariable *getCtorVtable(const CXXRecordDecl *RD,
- const CXXRecordDecl *Class,
- uint64_t Offset);
+ /// CtorVtableInfo - Information about a constructor vtable.
+ struct CtorVtableInfo {
+ /// Vtable - The vtable itself.
+ llvm::GlobalVariable *Vtable;
+
+ /// AddressPoints - The address points in this constructor vtable.
+ AddressPointsMapTy AddressPoints;
+
+ CtorVtableInfo() : Vtable(0) { }
+ };
+
+ CtorVtableInfo getCtorVtable(const CXXRecordDecl *RD,
+ const BaseSubobject &Base);
+
+ llvm::GlobalVariable *getVTT(const CXXRecordDecl *RD);
void MaybeEmitVtable(GlobalDecl GD);
};
-}
-}
+} // end namespace CodeGen
+} // end namespace clang
#endif
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 3c26484..45469d3 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -29,5 +29,5 @@ add_clang_library(clangCodeGen
CodeGenTypes.cpp
Mangle.cpp
ModuleBuilder.cpp
- TargetABIInfo.cpp
+ TargetInfo.cpp
)
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index f904f04..f0a5c64 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -190,15 +190,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
QualType FnType = getContext().getFunctionType(RetTy, 0, 0, false, 0);
// Emit subprogram debug descriptor.
- // FIXME: The cast here is a huge hack.
if (CGDebugInfo *DI = getDebugInfo()) {
DI->setLocation(StartLoc);
- if (isa<FunctionDecl>(D)) {
- DI->EmitFunctionStart(CGM.getMangledName(GD), FnType, CurFn, Builder);
- } else {
- // Just use LLVM function name.
- DI->EmitFunctionStart(Fn->getName(), FnType, CurFn, Builder);
- }
+ DI->EmitFunctionStart(GD, FnType, CurFn, Builder);
}
// FIXME: Leaked.
@@ -230,26 +224,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
}
}
-static bool NeedsVTTParameter(GlobalDecl GD) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- // We don't have any virtual bases, just return early.
- if (!MD->getParent()->getNumVBases())
- return false;
-
- // Check if we have a base constructor.
- if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base)
- return true;
-
- // Check if we have a base destructor.
- if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
- return true;
-
- return false;
-}
-
-void CodeGenFunction::GenerateCode(GlobalDecl GD,
- llvm::Function *Fn) {
+void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
// Check if we should generate debug info for this function.
@@ -271,7 +246,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD,
Args.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType()));
// Check if we need a VTT parameter as well.
- if (NeedsVTTParameter(GD)) {
+ if (CGVtableInfo::needsVTTParameter(GD)) {
// FIXME: The comment about using a fake decl above applies here too.
QualType T = getContext().getPointerType(getContext().VoidPtrTy);
CXXVTTDecl =
@@ -597,7 +572,7 @@ llvm::Value *CodeGenFunction::EmitVLASize(QualType Ty) {
ElemSize = EmitVLASize(ElemTy);
else
ElemSize = llvm::ConstantInt::get(SizeTy,
- getContext().getTypeSize(ElemTy) / 8);
+ getContext().getTypeSizeInChars(ElemTy).getQuantity());
llvm::Value *NumElements = EmitScalarExpr(VAT->getSizeExpr());
NumElements = Builder.CreateIntCast(NumElements, SizeTy, false, "tmp");
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 273ddca..30ad663 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -17,6 +17,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/CharUnits.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
@@ -463,7 +464,7 @@ public:
llvm::Value *BuildBlockLiteralTmp(const BlockExpr *);
llvm::Constant *BuildDescriptorBlockDecl(bool BlockHasCopyDispose,
- uint64_t Size,
+ CharUnits Size,
const llvm::StructType *,
std::vector<HelperInfo> *);
@@ -471,14 +472,14 @@ public:
const BlockInfo& Info,
const Decl *OuterFuncDecl,
llvm::DenseMap<const Decl*, llvm::Value*> ldm,
- uint64_t &Size, uint64_t &Align,
+ CharUnits &Size, uint64_t &Align,
llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls,
bool &subBlockHasCopyDispose);
void BlockForwardSelf();
llvm::Value *LoadBlockStruct();
- uint64_t AllocateBlockDecl(const BlockDeclRefExpr *E);
+ CharUnits AllocateBlockDecl(const BlockDeclRefExpr *E);
llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E);
const llvm::Type *BuildByRefType(const ValueDecl *D);
@@ -517,7 +518,7 @@ public:
void InitializeVtablePtrsRecursive(const CXXRecordDecl *ClassDecl,
llvm::Constant *Vtable,
- CodeGenModule::AddrSubMap_t& AddressPoints,
+ CGVtableInfo::AddrSubMap_t& AddressPoints,
llvm::Value *ThisPtr,
uint64_t Offset);
@@ -728,6 +729,10 @@ public:
/// generating code for an C++ member function.
llvm::Value *LoadCXXThis();
+ /// LoadCXXVTT - Load the VTT parameter to base constructors/destructors have
+ /// virtual bases.
+ llvm::Value *LoadCXXVTT();
+
/// GetAddressOfBaseClass - This function will add the necessary delta to the
/// load of 'this' and returns address of the base class.
// FIXME. This currently only does a derived to non-virtual base conversion.
@@ -794,7 +799,7 @@ public:
llvm::Value *NumElements,
llvm::Value *This);
- llvm::Constant * GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
+ llvm::Constant *GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
const ArrayType *Array,
llvm::Value *This);
@@ -815,6 +820,10 @@ public:
void EmitCheck(llvm::Value *, unsigned Size);
+ llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
+ bool isInc, bool isPre);
+ ComplexPairTy EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
+ bool isInc, bool isPre);
//===--------------------------------------------------------------------===//
// Declaration Emission
//===--------------------------------------------------------------------===//
@@ -1057,6 +1066,7 @@ public:
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
llvm::Value *This,
+ llvm::Value *VTT,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E,
@@ -1081,10 +1091,6 @@ public:
llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
- llvm::Value *EmitShuffleVector(llvm::Value* V1, llvm::Value *V2, ...);
- llvm::Value *EmitVector(llvm::Value * const *Vals, unsigned NumVals,
- bool isSplat = false);
-
llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E);
llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E);
llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E);
@@ -1184,9 +1190,11 @@ public:
/// GenerateCXXGlobalInitFunc - Generates code for initializing global
/// variables.
void GenerateCXXGlobalInitFunc(llvm::Function *Fn,
- const VarDecl **Decls,
+ llvm::Constant **Decls,
unsigned NumDecls);
+ void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D);
+
void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E);
RValue EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index d497471..5ecc30e 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -17,6 +17,7 @@
#include "CGCall.h"
#include "CGObjCRuntime.h"
#include "Mangle.h"
+#include "TargetInfo.h"
#include "clang/CodeGen/CodeGenOptions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -42,8 +43,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
Diagnostic &diags)
: BlockModule(C, M, TD, Types, *this), Context(C),
Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M),
- TheTargetData(TD), Diags(diags), Types(C, M, TD), MangleCtx(C),
- VtableInfo(*this), Runtime(0),
+ TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags),
+ Types(C, M, TD, getTargetCodeGenInfo().getABIInfo()),
+ MangleCtx(C), VtableInfo(*this), Runtime(0),
MemCpyFn(0), MemMoveFn(0), MemSetFn(0), CFConstantStringClassRef(0),
VMContext(M.getContext()) {
@@ -66,10 +68,8 @@ CodeGenModule::~CodeGenModule() {
}
void CodeGenModule::Release() {
- // We need to call this first because it can add deferred declarations.
- EmitCXXGlobalInitFunc();
-
EmitDeferred();
+ EmitCXXGlobalInitFunc();
if (Runtime)
if (llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction())
AddGlobalCtor(ObjCInitFunction);
@@ -378,6 +378,8 @@ void CodeGenModule::SetCommonAttributes(const Decl *D,
if (const SectionAttr *SA = D->getAttr<SectionAttr>())
GV->setSection(SA->getName());
+
+ getTargetCodeGenInfo().SetTargetAttributes(D, GV, *this);
}
void CodeGenModule::SetInternalFunctionAttributes(const Decl *D,
@@ -537,7 +539,8 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
const CXXRecordDecl *RD = MD->getParent();
if (MD->isOutOfLine() && RD->isDynamicClass()) {
const CXXMethodDecl *KeyFunction = getContext().getKeyFunction(RD);
- if (KeyFunction == MD->getCanonicalDecl())
+ if (KeyFunction &&
+ KeyFunction->getCanonicalDecl() == MD->getCanonicalDecl())
return false;
}
}
@@ -876,6 +879,57 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
EmitGlobalVarDefinition(D);
}
+llvm::GlobalVariable::LinkageTypes
+CodeGenModule::getVtableLinkage(const CXXRecordDecl *RD) {
+ if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
+ return llvm::GlobalVariable::InternalLinkage;
+
+ if (const CXXMethodDecl *KeyFunction
+ = RD->getASTContext().getKeyFunction(RD)) {
+ // If this class has a key function, use that to determine the linkage of
+ // the vtable.
+ const FunctionDecl *Def = 0;
+ if (KeyFunction->getBody(Def))
+ KeyFunction = cast<CXXMethodDecl>(Def);
+
+ switch (KeyFunction->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ if (KeyFunction->isInlined())
+ return llvm::GlobalVariable::WeakODRLinkage;
+
+ return llvm::GlobalVariable::ExternalLinkage;
+
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDefinition:
+ return llvm::GlobalVariable::WeakODRLinkage;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ // FIXME: Use available_externally linkage. However, this currently
+ // breaks LLVM's build due to undefined symbols.
+ // return llvm::GlobalVariable::AvailableExternallyLinkage;
+ return llvm::GlobalVariable::WeakODRLinkage;
+ }
+ }
+
+ switch (RD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDefinition:
+ return llvm::GlobalVariable::WeakODRLinkage;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ // FIXME: Use available_externally linkage. However, this currently
+ // breaks LLVM's build due to undefined symbols.
+ // return llvm::GlobalVariable::AvailableExternallyLinkage;
+ return llvm::GlobalVariable::WeakODRLinkage;
+ }
+
+ // Silence GCC warning.
+ return llvm::GlobalVariable::WeakODRLinkage;
+}
+
static CodeGenModule::GVALinkage
GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
// Everything located semantically within an anonymous namespace is
@@ -909,6 +963,7 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
llvm::Constant *Init = 0;
QualType ASTTy = D->getType();
+ bool NonConstInit = false;
if (D->getInit() == 0) {
// This is a tentative definition; tentative definitions are
@@ -928,8 +983,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
if (!Init) {
QualType T = D->getInit()->getType();
if (getLangOptions().CPlusPlus) {
- CXXGlobalInits.push_back(D);
+ EmitCXXGlobalVarDeclInitFunc(D);
Init = EmitNullConstant(T);
+ NonConstInit = true;
} else {
ErrorUnsupported(D, "static initializer");
Init = llvm::UndefValue::get(getTypes().ConvertType(T));
@@ -990,7 +1046,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
// If it is safe to mark the global 'constant', do so now.
GV->setConstant(false);
- if (DeclIsConstantGlobal(Context, D))
+ if (!NonConstInit && DeclIsConstantGlobal(Context, D))
GV->setConstant(true);
GV->setAlignment(getContext().getDeclAlignInBytes(D));
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 939c66c..c7aa7a4 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -43,6 +43,7 @@ namespace llvm {
}
namespace clang {
+ class TargetCodeGenInfo;
class ASTContext;
class FunctionDecl;
class IdentifierInfo;
@@ -85,6 +86,7 @@ class CodeGenModule : public BlockModule {
const CodeGenOptions &CodeGenOpts;
llvm::Module &TheModule;
const llvm::TargetData &TheTargetData;
+ mutable const TargetCodeGenInfo *TheTargetCodeGenInfo;
Diagnostic &Diags;
CodeGenTypes Types;
MangleContext MangleCtx;
@@ -153,7 +155,7 @@ class CodeGenModule : public BlockModule {
/// CXXGlobalInits - Variables with global initializers that need to run
/// before main.
- std::vector<const VarDecl*> CXXGlobalInits;
+ std::vector<llvm::Constant*> CXXGlobalInits;
/// CFConstantStringClassRef - Cached reference to the class for constant
/// strings. This value has type int * but is actually an Obj-C class pointer.
@@ -191,6 +193,7 @@ public:
Diagnostic &getDiags() const { return Diags; }
const llvm::TargetData &getTargetData() const { return TheTargetData; }
llvm::LLVMContext &getLLVMContext() { return VMContext; }
+ const TargetCodeGenInfo &getTargetCodeGenInfo() const;
/// getDeclVisibilityMode - Compute the visibility of the decl \arg D.
LangOptions::VisibilityMode getDeclVisibilityMode(const Decl *D) const;
@@ -232,11 +235,6 @@ public:
BuildCovariantThunk(const GlobalDecl &GD, bool Extern,
const CovariantThunkAdjustment &Adjustment);
- typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_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
/// base class. Returns null if the offset is 0.
llvm::Constant *GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
@@ -412,6 +410,11 @@ public:
GVA_TemplateInstantiation
};
+ /// getVtableLinkage - Return the appropriate linkage for the vtable, VTT,
+ /// and type information of the given class.
+ static llvm::GlobalVariable::LinkageTypes
+ getVtableLinkage(const CXXRecordDecl *RD);
+
private:
/// UniqueMangledName - Unique a name by (if necessary) inserting it into the
/// MangledNames string map.
@@ -475,7 +478,9 @@ private:
/// EmitCXXGlobalInitFunc - Emit a function that initializes C++ globals.
void EmitCXXGlobalInitFunc();
-
+
+ void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D);
+
// FIXME: Hardcoding priority here is gross.
void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535);
void AddGlobalDtor(llvm::Function *Dtor, int Priority=65535);
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index cd34e0c..838f62a 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -28,9 +28,9 @@ using namespace clang;
using namespace CodeGen;
CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M,
- const llvm::TargetData &TD)
+ const llvm::TargetData &TD, const ABIInfo &Info)
: Context(Ctx), Target(Ctx.Target), TheModule(M), TheTargetData(TD),
- TheABIInfo(0) {
+ TheABIInfo(Info) {
}
CodeGenTypes::~CodeGenTypes() {
@@ -38,13 +38,10 @@ CodeGenTypes::~CodeGenTypes() {
I = CGRecordLayouts.begin(), E = CGRecordLayouts.end();
I != E; ++I)
delete I->second;
- {
- llvm::FoldingSet<CGFunctionInfo>::iterator
- I = FunctionInfos.begin(), E = FunctionInfos.end();
- while (I != E)
- delete &*I++;
- }
- delete TheABIInfo;
+
+ for (llvm::FoldingSet<CGFunctionInfo>::iterator
+ I = FunctionInfos.begin(), E = FunctionInfos.end(); I != E; )
+ delete &*I++;
}
/// ConvertType - Convert the specified type to its LLVM form.
@@ -56,9 +53,8 @@ const llvm::Type *CodeGenTypes::ConvertType(QualType T) {
// circular types. Loop through all these defered pointees, if any, and
// resolve them now.
while (!PointersToResolve.empty()) {
- std::pair<QualType, llvm::OpaqueType*> P =
- PointersToResolve.back();
- PointersToResolve.pop_back();
+ std::pair<QualType, llvm::OpaqueType*> P = PointersToResolve.pop_back_val();
+
// We can handle bare pointers here because we know that the only pointers
// to the Opaque type are P.second and from other types. Refining the
// opqaue type away will invalidate P.second, but we don't mind :).
@@ -88,9 +84,10 @@ const llvm::Type *CodeGenTypes::ConvertTypeRecursive(QualType T) {
const llvm::Type *CodeGenTypes::ConvertTypeForMemRecursive(QualType T) {
const llvm::Type *ResultType = ConvertTypeRecursive(T);
- if (ResultType == llvm::Type::getInt1Ty(getLLVMContext()))
+ if (ResultType->isInteger(1))
return llvm::IntegerType::get(getLLVMContext(),
(unsigned)Context.getTypeSize(T));
+ // FIXME: Should assert that the llvm type and AST type has the same size.
return ResultType;
}
@@ -102,7 +99,7 @@ const llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) {
const llvm::Type *R = ConvertType(T);
// If this is a non-bool type, don't map it.
- if (R != llvm::Type::getInt1Ty(getLLVMContext()))
+ if (!R->isInteger(1))
return R;
// Otherwise, return an integer of the target-specified size.
@@ -384,11 +381,10 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
QualType ETy = cast<MemberPointerType>(Ty).getPointeeType();
const llvm::Type *PtrDiffTy =
ConvertTypeRecursive(Context.getPointerDiffType());
- if (ETy->isFunctionType()) {
+ if (ETy->isFunctionType())
return llvm::StructType::get(TheModule.getContext(), PtrDiffTy, PtrDiffTy,
NULL);
- } else
- return PtrDiffTy;
+ return PtrDiffTy;
}
case Type::TemplateSpecialization:
@@ -436,10 +432,8 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
// Okay, this is a definition of a type. Compile the implementation now.
- if (TD->isEnum()) {
- // Don't bother storing enums in TagDeclTypes.
+ if (TD->isEnum()) // Don't bother storing enums in TagDeclTypes.
return ConvertTypeRecursive(cast<EnumDecl>(TD)->getIntegerType());
- }
// This decl could well be recursive. In this case, insert an opaque
// definition of this type, which the recursive uses will get. We will then
@@ -450,15 +444,13 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
llvm::PATypeHolder ResultHolder = llvm::OpaqueType::get(getLLVMContext());
TagDeclTypes.insert(std::make_pair(Key, ResultHolder));
- const llvm::Type *ResultType;
const RecordDecl *RD = cast<const RecordDecl>(TD);
// Layout fields.
- CGRecordLayout *Layout =
- CGRecordLayoutBuilder::ComputeLayout(*this, RD);
+ CGRecordLayout *Layout = CGRecordLayoutBuilder::ComputeLayout(*this, RD);
CGRecordLayouts[Key] = Layout;
- ResultType = Layout->getLLVMType();
+ const llvm::Type *ResultType = Layout->getLLVMType();
// Refine our Opaque type to ResultType. This can invalidate ResultType, so
// make sure to read the result out of the holder.
@@ -500,8 +492,7 @@ void CodeGenTypes::addBitFieldInfo(const FieldDecl *FD, unsigned FieldNo,
/// getCGRecordLayout - Return record layout info for the given llvm::Type.
const CGRecordLayout &
CodeGenTypes::getCGRecordLayout(const TagDecl *TD) const {
- const Type *Key =
- Context.getTagDeclType(TD).getTypePtr();
+ const Type *Key = Context.getTagDeclType(TD).getTypePtr();
llvm::DenseMap<const Type*, CGRecordLayout *>::const_iterator I
= CGRecordLayouts.find(Key);
assert (I != CGRecordLayouts.end()
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 2ff602f..7e34252 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -85,7 +85,7 @@ class CodeGenTypes {
const TargetInfo &Target;
llvm::Module& TheModule;
const llvm::TargetData& TheTargetData;
- mutable const ABIInfo* TheABIInfo;
+ const ABIInfo& TheABIInfo;
llvm::SmallVector<std::pair<QualType,
llvm::OpaqueType *>, 8> PointersToResolve;
@@ -140,13 +140,14 @@ private:
/// interface to convert type T into a llvm::Type.
const llvm::Type *ConvertNewType(QualType T);
public:
- CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD);
+ CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD,
+ const ABIInfo &Info);
~CodeGenTypes();
const llvm::TargetData &getTargetData() const { return TheTargetData; }
const TargetInfo &getTarget() const { return Target; }
ASTContext &getContext() const { return Context; }
- const ABIInfo &getABIInfo() const;
+ const ABIInfo &getABIInfo() const { return TheABIInfo; }
llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); }
/// ConvertType - Convert type T into a llvm::Type.
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index 10fd1f5..d873cfe 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -199,10 +199,13 @@ void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) {
return;
}
- // <mangled-name> ::= _Z <encoding>
+ // <mangled-name> ::= _Z [L] <encoding>
// ::= <data name>
// ::= <special-name>
Out << Prefix;
+ if (D->getLinkage() == NamedDecl::InternalLinkage) // match gcc behavior
+ Out << 'L';
+
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
mangleFunctionEncoding(FD);
else
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
new file mode 100644
index 0000000..e5fd47e
--- /dev/null
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -0,0 +1,1904 @@
+//===---- TargetInfo.cpp - Encapsulate target details -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes wrap the information about a call or function
+// definition used to handle ABI compliancy.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TargetInfo.h"
+#include "ABIInfo.h"
+#include "CodeGenFunction.h"
+#include "clang/AST/RecordLayout.h"
+#include "llvm/Type.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+using namespace CodeGen;
+
+ABIInfo::~ABIInfo() {}
+
+void ABIArgInfo::dump() const {
+ llvm::raw_ostream &OS = llvm::errs();
+ OS << "(ABIArgInfo Kind=";
+ switch (TheKind) {
+ case Direct:
+ OS << "Direct";
+ break;
+ case Extend:
+ OS << "Extend";
+ break;
+ case Ignore:
+ OS << "Ignore";
+ break;
+ case Coerce:
+ OS << "Coerce Type=";
+ getCoerceToType()->print(OS);
+ break;
+ case Indirect:
+ OS << "Indirect Align=" << getIndirectAlign();
+ break;
+ case Expand:
+ OS << "Expand";
+ break;
+ }
+ OS << ")\n";
+}
+
+TargetCodeGenInfo::~TargetCodeGenInfo() { delete Info; }
+
+static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);
+
+/// isEmptyField - Return true iff a the field is "empty", that is it
+/// is an unnamed bit-field or an (array of) empty record(s).
+static bool isEmptyField(ASTContext &Context, const FieldDecl *FD,
+ bool AllowArrays) {
+ if (FD->isUnnamedBitfield())
+ return true;
+
+ QualType FT = FD->getType();
+
+ // Constant arrays of empty records count as empty, strip them off.
+ if (AllowArrays)
+ while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT))
+ FT = AT->getElementType();
+
+ return isEmptyRecord(Context, FT, AllowArrays);
+}
+
+/// isEmptyRecord - Return true iff a structure contains only empty
+/// fields. Note that a structure with a flexible array member is not
+/// considered empty.
+static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) {
+ const RecordType *RT = T->getAs<RecordType>();
+ if (!RT)
+ return 0;
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->hasFlexibleArrayMember())
+ return false;
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i)
+ if (!isEmptyField(Context, *i, AllowArrays))
+ return false;
+ return true;
+}
+
+/// hasNonTrivialDestructorOrCopyConstructor - Determine if a type has either
+/// a non-trivial destructor or a non-trivial copy constructor.
+static bool hasNonTrivialDestructorOrCopyConstructor(const RecordType *RT) {
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD)
+ return false;
+
+ return !RD->hasTrivialDestructor() || !RD->hasTrivialCopyConstructor();
+}
+
+/// isRecordWithNonTrivialDestructorOrCopyConstructor - Determine if a type is
+/// a record type with either a non-trivial destructor or a non-trivial copy
+/// constructor.
+static bool isRecordWithNonTrivialDestructorOrCopyConstructor(QualType T) {
+ const RecordType *RT = T->getAs<RecordType>();
+ if (!RT)
+ return false;
+
+ return hasNonTrivialDestructorOrCopyConstructor(RT);
+}
+
+/// isSingleElementStruct - Determine if a structure is a "single
+/// element struct", i.e. it has exactly one non-empty field or
+/// exactly one field which is itself a single element
+/// struct. Structures with flexible array members are never
+/// considered single element structs.
+///
+/// \return The field declaration for the single non-empty field, if
+/// it exists.
+static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
+ const RecordType *RT = T->getAsStructureType();
+ if (!RT)
+ return 0;
+
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->hasFlexibleArrayMember())
+ return 0;
+
+ const Type *Found = 0;
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i) {
+ const FieldDecl *FD = *i;
+ QualType FT = FD->getType();
+
+ // Ignore empty fields.
+ if (isEmptyField(Context, FD, true))
+ continue;
+
+ // If we already found an element then this isn't a single-element
+ // struct.
+ if (Found)
+ return 0;
+
+ // Treat single element arrays as the element.
+ while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {
+ if (AT->getSize().getZExtValue() != 1)
+ break;
+ FT = AT->getElementType();
+ }
+
+ if (!CodeGenFunction::hasAggregateLLVMType(FT)) {
+ Found = FT.getTypePtr();
+ } else {
+ Found = isSingleElementStruct(FT, Context);
+ if (!Found)
+ return 0;
+ }
+ }
+
+ return Found;
+}
+
+static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) {
+ if (!Ty->getAs<BuiltinType>() && !Ty->isAnyPointerType() &&
+ !Ty->isAnyComplexType() && !Ty->isEnumeralType() &&
+ !Ty->isBlockPointerType())
+ return false;
+
+ uint64_t Size = Context.getTypeSize(Ty);
+ return Size == 32 || Size == 64;
+}
+
+/// canExpandIndirectArgument - Test whether an argument type which is to be
+/// passed indirectly (on the stack) would have the equivalent layout if it was
+/// expanded into separate arguments. If so, we prefer to do the latter to avoid
+/// inhibiting optimizations.
+///
+// FIXME: This predicate is missing many cases, currently it just follows
+// llvm-gcc (checks that all fields are 32-bit or 64-bit primitive types). We
+// should probably make this smarter, or better yet make the LLVM backend
+// capable of handling it.
+static bool canExpandIndirectArgument(QualType Ty, ASTContext &Context) {
+ // We can only expand structure types.
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (!RT)
+ return false;
+
+ // We can only expand (C) structures.
+ //
+ // FIXME: This needs to be generalized to handle classes as well.
+ const RecordDecl *RD = RT->getDecl();
+ if (!RD->isStruct() || isa<CXXRecordDecl>(RD))
+ return false;
+
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i) {
+ const FieldDecl *FD = *i;
+
+ if (!is32Or64BitBasicType(FD->getType(), Context))
+ return false;
+
+ // FIXME: Reject bit-fields wholesale; there are two problems, we don't know
+ // how to expand them yet, and the predicate for telling if a bitfield still
+ // counts as "basic" is more complicated than what we were doing previously.
+ if (FD->isBitField())
+ return false;
+ }
+
+ return true;
+}
+
+static bool typeContainsSSEVector(const RecordDecl *RD, ASTContext &Context) {
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i) {
+ const FieldDecl *FD = *i;
+
+ if (FD->getType()->isVectorType() &&
+ Context.getTypeSize(FD->getType()) >= 128)
+ return true;
+
+ if (const RecordType* RT = FD->getType()->getAs<RecordType>())
+ if (typeContainsSSEVector(RT->getDecl(), Context))
+ return true;
+ }
+
+ return false;
+}
+
+namespace {
+/// DefaultABIInfo - The default implementation for ABI specific
+/// details. This implementation provides information which results in
+/// self-consistent and sensible LLVM IR generation, but does not
+/// conform to any particular ABI.
+class DefaultABIInfo : public ABIInfo {
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ ABIArgInfo classifyArgumentType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
+ VMContext);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type, Context, VMContext);
+ }
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class DefaultTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ DefaultTargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {};
+};
+
+llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ return 0;
+}
+
+ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+}
+
+/// X86_32ABIInfo - The X86-32 ABI information.
+class X86_32ABIInfo : public ABIInfo {
+ ASTContext &Context;
+ bool IsDarwinVectorABI;
+ bool IsSmallStructInRegABI;
+
+ static bool isRegisterSize(unsigned Size) {
+ return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
+ }
+
+ static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context);
+
+ static unsigned getIndirectArgumentAlignment(QualType Ty,
+ ASTContext &Context);
+
+public:
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ ABIArgInfo classifyArgumentType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
+ VMContext);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type, Context, VMContext);
+ }
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+
+ X86_32ABIInfo(ASTContext &Context, bool d, bool p)
+ : ABIInfo(), Context(Context), IsDarwinVectorABI(d),
+ IsSmallStructInRegABI(p) {}
+};
+
+class X86_32TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ X86_32TargetCodeGenInfo(ASTContext &Context, bool d, bool p)
+ :TargetCodeGenInfo(new X86_32ABIInfo(Context, d, p)) {};
+};
+
+}
+
+/// shouldReturnTypeInRegister - Determine if the given type should be
+/// passed in a register (for the Darwin ABI).
+bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
+ ASTContext &Context) {
+ uint64_t Size = Context.getTypeSize(Ty);
+
+ // Type must be register sized.
+ if (!isRegisterSize(Size))
+ return false;
+
+ if (Ty->isVectorType()) {
+ // 64- and 128- bit vectors inside structures are not returned in
+ // registers.
+ if (Size == 64 || Size == 128)
+ return false;
+
+ return true;
+ }
+
+ // If this is a builtin, pointer, enum, or complex type, it is ok.
+ if (Ty->getAs<BuiltinType>() || Ty->isAnyPointerType() ||
+ Ty->isAnyComplexType() || Ty->isEnumeralType() ||
+ Ty->isBlockPointerType())
+ return true;
+
+ // Arrays are treated like records.
+ if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty))
+ return shouldReturnTypeInRegister(AT->getElementType(), Context);
+
+ // Otherwise, it must be a record type.
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (!RT) return false;
+
+ // Structure types are passed in register if all fields would be
+ // passed in a register.
+ for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(),
+ e = RT->getDecl()->field_end(); i != e; ++i) {
+ const FieldDecl *FD = *i;
+
+ // Empty fields are ignored.
+ if (isEmptyField(Context, FD, true))
+ continue;
+
+ // Check fields recursively.
+ if (!shouldReturnTypeInRegister(FD->getType(), Context))
+ return false;
+ }
+
+ return true;
+}
+
+ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (RetTy->isVoidType()) {
+ return ABIArgInfo::getIgnore();
+ } else if (const VectorType *VT = RetTy->getAs<VectorType>()) {
+ // On Darwin, some vectors are returned in registers.
+ if (IsDarwinVectorABI) {
+ uint64_t Size = Context.getTypeSize(RetTy);
+
+ // 128-bit vectors are a special case; they are returned in
+ // registers and we need to make sure to pick a type the LLVM
+ // backend will like.
+ if (Size == 128)
+ return ABIArgInfo::getCoerce(llvm::VectorType::get(
+ llvm::Type::getInt64Ty(VMContext), 2));
+
+ // Always return in register if it fits in a general purpose
+ // register, or if it is 64 bits and has a single element.
+ if ((Size == 8 || Size == 16 || Size == 32) ||
+ (Size == 64 && VT->getNumElements() == 1))
+ return ABIArgInfo::getCoerce(llvm::IntegerType::get(VMContext, Size));
+
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ return ABIArgInfo::getDirect();
+ } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ if (const RecordType *RT = RetTy->getAsStructureType()) {
+ // Structures with either a non-trivial destructor or a non-trivial
+ // copy constructor are always indirect.
+ if (hasNonTrivialDestructorOrCopyConstructor(RT))
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+
+ // Structures with flexible arrays are always indirect.
+ if (RT->getDecl()->hasFlexibleArrayMember())
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ // If specified, structs and unions are always indirect.
+ if (!IsSmallStructInRegABI && !RetTy->isAnyComplexType())
+ return ABIArgInfo::getIndirect(0);
+
+ // Classify "single element" structs as their element type.
+ if (const Type *SeltTy = isSingleElementStruct(RetTy, Context)) {
+ if (const BuiltinType *BT = SeltTy->getAs<BuiltinType>()) {
+ if (BT->isIntegerType()) {
+ // We need to use the size of the structure, padding
+ // bit-fields can adjust that to be larger than the single
+ // element type.
+ uint64_t Size = Context.getTypeSize(RetTy);
+ return ABIArgInfo::getCoerce(
+ llvm::IntegerType::get(VMContext, (unsigned) Size));
+ } else if (BT->getKind() == BuiltinType::Float) {
+ assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) &&
+ "Unexpect single element structure size!");
+ return ABIArgInfo::getCoerce(llvm::Type::getFloatTy(VMContext));
+ } else if (BT->getKind() == BuiltinType::Double) {
+ assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) &&
+ "Unexpect single element structure size!");
+ return ABIArgInfo::getCoerce(llvm::Type::getDoubleTy(VMContext));
+ }
+ } else if (SeltTy->isPointerType()) {
+ // FIXME: It would be really nice if this could come out as the proper
+ // pointer type.
+ const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ return ABIArgInfo::getCoerce(PtrTy);
+ } else if (SeltTy->isVectorType()) {
+ // 64- and 128-bit vectors are never returned in a
+ // register when inside a structure.
+ uint64_t Size = Context.getTypeSize(RetTy);
+ if (Size == 64 || Size == 128)
+ return ABIArgInfo::getIndirect(0);
+
+ return classifyReturnType(QualType(SeltTy, 0), Context, VMContext);
+ }
+ }
+
+ // Small structures which are register sized are generally returned
+ // in a register.
+ if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, Context)) {
+ uint64_t Size = Context.getTypeSize(RetTy);
+ return ABIArgInfo::getCoerce(llvm::IntegerType::get(VMContext, Size));
+ }
+
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return (RetTy->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+}
+
+unsigned X86_32ABIInfo::getIndirectArgumentAlignment(QualType Ty,
+ ASTContext &Context) {
+ unsigned Align = Context.getTypeAlign(Ty);
+ if (Align < 128) return 0;
+ if (const RecordType* RT = Ty->getAs<RecordType>())
+ if (typeContainsSSEVector(RT->getDecl(), Context))
+ return 16;
+ return 0;
+}
+
+ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ // FIXME: Set alignment on indirect arguments.
+ if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ // Structures with flexible arrays are always indirect.
+ if (const RecordType *RT = Ty->getAsStructureType())
+ if (RT->getDecl()->hasFlexibleArrayMember())
+ return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty,
+ Context));
+
+ // Ignore empty structs.
+ if (Ty->isStructureType() && Context.getTypeSize(Ty) == 0)
+ return ABIArgInfo::getIgnore();
+
+ // Expand small (<= 128-bit) record types when we know that the stack layout
+ // of those arguments will match the struct. This is important because the
+ // LLVM backend isn't smart enough to remove byval, which inhibits many
+ // optimizations.
+ if (Context.getTypeSize(Ty) <= 4*32 &&
+ canExpandIndirectArgument(Ty, Context))
+ return ABIArgInfo::getExpand();
+
+ return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context));
+ } else {
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+}
+
+llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ const llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
+
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP,
+ "ap");
+ llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
+ llvm::Type *PTy =
+ llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
+
+ uint64_t Offset =
+ llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4);
+ llvm::Value *NextAddr =
+ Builder.CreateGEP(Addr, llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(CGF.getLLVMContext()), Offset),
+ "ap.next");
+ Builder.CreateStore(NextAddr, VAListAddrAsBPP);
+
+ return AddrTyped;
+}
+
+namespace {
+/// X86_64ABIInfo - The X86_64 ABI information.
+class X86_64ABIInfo : public ABIInfo {
+ enum Class {
+ Integer = 0,
+ SSE,
+ SSEUp,
+ X87,
+ X87Up,
+ ComplexX87,
+ NoClass,
+ Memory
+ };
+
+ /// merge - Implement the X86_64 ABI merging algorithm.
+ ///
+ /// Merge an accumulating classification \arg Accum with a field
+ /// classification \arg Field.
+ ///
+ /// \param Accum - The accumulating classification. This should
+ /// always be either NoClass or the result of a previous merge
+ /// call. In addition, this should never be Memory (the caller
+ /// should just return Memory for the aggregate).
+ Class merge(Class Accum, Class Field) const;
+
+ /// classify - Determine the x86_64 register classes in which the
+ /// given type T should be passed.
+ ///
+ /// \param Lo - The classification for the parts of the type
+ /// residing in the low word of the containing object.
+ ///
+ /// \param Hi - The classification for the parts of the type
+ /// residing in the high word of the containing object.
+ ///
+ /// \param OffsetBase - The bit offset of this type in the
+ /// containing object. Some parameters are classified different
+ /// depending on whether they straddle an eightbyte boundary.
+ ///
+ /// If a word is unused its result will be NoClass; if a type should
+ /// be passed in Memory then at least the classification of \arg Lo
+ /// will be Memory.
+ ///
+ /// The \arg Lo class will be NoClass iff the argument is ignored.
+ ///
+ /// If the \arg Lo class is ComplexX87, then the \arg Hi class will
+ /// also be ComplexX87.
+ void classify(QualType T, ASTContext &Context, uint64_t OffsetBase,
+ Class &Lo, Class &Hi) const;
+
+ /// getCoerceResult - Given a source type \arg Ty and an LLVM type
+ /// to coerce to, chose the best way to pass Ty in the same place
+ /// that \arg CoerceTo would be passed, but while keeping the
+ /// emitted code as simple as possible.
+ ///
+ /// FIXME: Note, this should be cleaned up to just take an enumeration of all
+ /// the ways we might want to pass things, instead of constructing an LLVM
+ /// type. This makes this code more explicit, and it makes it clearer that we
+ /// are also doing this for correctness in the case of passing scalar types.
+ ABIArgInfo getCoerceResult(QualType Ty,
+ const llvm::Type *CoerceTo,
+ ASTContext &Context) const;
+
+ /// getIndirectResult - Give a source type \arg Ty, return a suitable result
+ /// such that the argument will be passed in memory.
+ ABIArgInfo getIndirectResult(QualType Ty,
+ ASTContext &Context) const;
+
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ ABIArgInfo classifyArgumentType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext,
+ unsigned &neededInt,
+ unsigned &neededSSE) const;
+
+public:
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class X86_64TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ X86_64TargetCodeGenInfo():TargetCodeGenInfo(new X86_64ABIInfo()) {};
+};
+
+}
+
+X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum,
+ Class Field) const {
+ // AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is
+ // classified recursively so that always two fields are
+ // considered. The resulting class is calculated according to
+ // the classes of the fields in the eightbyte:
+ //
+ // (a) If both classes are equal, this is the resulting class.
+ //
+ // (b) If one of the classes is NO_CLASS, the resulting class is
+ // the other class.
+ //
+ // (c) If one of the classes is MEMORY, the result is the MEMORY
+ // class.
+ //
+ // (d) If one of the classes is INTEGER, the result is the
+ // INTEGER.
+ //
+ // (e) If one of the classes is X87, X87UP, COMPLEX_X87 class,
+ // MEMORY is used as class.
+ //
+ // (f) Otherwise class SSE is used.
+
+ // Accum should never be memory (we should have returned) or
+ // ComplexX87 (because this cannot be passed in a structure).
+ assert((Accum != Memory && Accum != ComplexX87) &&
+ "Invalid accumulated classification during merge.");
+ if (Accum == Field || Field == NoClass)
+ return Accum;
+ else if (Field == Memory)
+ return Memory;
+ else if (Accum == NoClass)
+ return Field;
+ else if (Accum == Integer || Field == Integer)
+ return Integer;
+ else if (Field == X87 || Field == X87Up || Field == ComplexX87 ||
+ Accum == X87 || Accum == X87Up)
+ return Memory;
+ else
+ return SSE;
+}
+
+void X86_64ABIInfo::classify(QualType Ty,
+ ASTContext &Context,
+ uint64_t OffsetBase,
+ Class &Lo, Class &Hi) const {
+ // FIXME: This code can be simplified by introducing a simple value class for
+ // Class pairs with appropriate constructor methods for the various
+ // situations.
+
+ // FIXME: Some of the split computations are wrong; unaligned vectors
+ // shouldn't be passed in registers for example, so there is no chance they
+ // can straddle an eightbyte. Verify & simplify.
+
+ Lo = Hi = NoClass;
+
+ Class &Current = OffsetBase < 64 ? Lo : Hi;
+ Current = Memory;
+
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ BuiltinType::Kind k = BT->getKind();
+
+ if (k == BuiltinType::Void) {
+ Current = NoClass;
+ } else if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) {
+ Lo = Integer;
+ Hi = Integer;
+ } else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) {
+ Current = Integer;
+ } else if (k == BuiltinType::Float || k == BuiltinType::Double) {
+ Current = SSE;
+ } else if (k == BuiltinType::LongDouble) {
+ Lo = X87;
+ Hi = X87Up;
+ }
+ // FIXME: _Decimal32 and _Decimal64 are SSE.
+ // FIXME: _float128 and _Decimal128 are (SSE, SSEUp).
+ } else if (const EnumType *ET = Ty->getAs<EnumType>()) {
+ // Classify the underlying integer type.
+ classify(ET->getDecl()->getIntegerType(), Context, OffsetBase, Lo, Hi);
+ } else if (Ty->hasPointerRepresentation()) {
+ Current = Integer;
+ } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ uint64_t Size = Context.getTypeSize(VT);
+ if (Size == 32) {
+ // gcc passes all <4 x char>, <2 x short>, <1 x int>, <1 x
+ // float> as integer.
+ Current = Integer;
+
+ // If this type crosses an eightbyte boundary, it should be
+ // split.
+ uint64_t EB_Real = (OffsetBase) / 64;
+ uint64_t EB_Imag = (OffsetBase + Size - 1) / 64;
+ if (EB_Real != EB_Imag)
+ Hi = Lo;
+ } else if (Size == 64) {
+ // gcc passes <1 x double> in memory. :(
+ if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::Double))
+ return;
+
+ // gcc passes <1 x long long> as INTEGER.
+ if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::LongLong))
+ Current = Integer;
+ else
+ Current = SSE;
+
+ // If this type crosses an eightbyte boundary, it should be
+ // split.
+ if (OffsetBase && OffsetBase != 64)
+ Hi = Lo;
+ } else if (Size == 128) {
+ Lo = SSE;
+ Hi = SSEUp;
+ }
+ } else if (const ComplexType *CT = Ty->getAs<ComplexType>()) {
+ QualType ET = Context.getCanonicalType(CT->getElementType());
+
+ uint64_t Size = Context.getTypeSize(Ty);
+ if (ET->isIntegralType()) {
+ if (Size <= 64)
+ Current = Integer;
+ else if (Size <= 128)
+ Lo = Hi = Integer;
+ } else if (ET == Context.FloatTy)
+ Current = SSE;
+ else if (ET == Context.DoubleTy)
+ Lo = Hi = SSE;
+ else if (ET == Context.LongDoubleTy)
+ Current = ComplexX87;
+
+ // If this complex type crosses an eightbyte boundary then it
+ // should be split.
+ uint64_t EB_Real = (OffsetBase) / 64;
+ uint64_t EB_Imag = (OffsetBase + Context.getTypeSize(ET)) / 64;
+ if (Hi == NoClass && EB_Real != EB_Imag)
+ Hi = Lo;
+ } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) {
+ // Arrays are treated like structures.
+
+ uint64_t Size = Context.getTypeSize(Ty);
+
+ // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
+ // than two eightbytes, ..., it has class MEMORY.
+ if (Size > 128)
+ return;
+
+ // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned
+ // fields, it has class MEMORY.
+ //
+ // Only need to check alignment of array base.
+ if (OffsetBase % Context.getTypeAlign(AT->getElementType()))
+ return;
+
+ // Otherwise implement simplified merge. We could be smarter about
+ // this, but it isn't worth it and would be harder to verify.
+ Current = NoClass;
+ uint64_t EltSize = Context.getTypeSize(AT->getElementType());
+ uint64_t ArraySize = AT->getSize().getZExtValue();
+ for (uint64_t i=0, Offset=OffsetBase; i<ArraySize; ++i, Offset += EltSize) {
+ Class FieldLo, FieldHi;
+ classify(AT->getElementType(), Context, Offset, FieldLo, FieldHi);
+ Lo = merge(Lo, FieldLo);
+ Hi = merge(Hi, FieldHi);
+ if (Lo == Memory || Hi == Memory)
+ break;
+ }
+
+ // Do post merger cleanup (see below). Only case we worry about is Memory.
+ if (Hi == Memory)
+ Lo = Memory;
+ assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp array classification.");
+ } else if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ uint64_t Size = Context.getTypeSize(Ty);
+
+ // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
+ // than two eightbytes, ..., it has class MEMORY.
+ if (Size > 128)
+ return;
+
+ // AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial
+ // copy constructor or a non-trivial destructor, it is passed by invisible
+ // reference.
+ if (hasNonTrivialDestructorOrCopyConstructor(RT))
+ return;
+
+ const RecordDecl *RD = RT->getDecl();
+
+ // Assume variable sized types are passed in memory.
+ if (RD->hasFlexibleArrayMember())
+ return;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ // Reset Lo class, this will be recomputed.
+ Current = NoClass;
+
+ // If this is a C++ record, classify the bases first.
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(),
+ e = CXXRD->bases_end(); i != e; ++i) {
+ assert(!i->isVirtual() && !i->getType()->isDependentType() &&
+ "Unexpected base class!");
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+
+ // Classify this field.
+ //
+ // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate exceeds a
+ // single eightbyte, each is classified separately. Each eightbyte gets
+ // initialized to class NO_CLASS.
+ Class FieldLo, FieldHi;
+ uint64_t Offset = OffsetBase + Layout.getBaseClassOffset(Base);
+ classify(i->getType(), Context, Offset, FieldLo, FieldHi);
+ Lo = merge(Lo, FieldLo);
+ Hi = merge(Hi, FieldHi);
+ 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.
+ unsigned idx = 0;
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i, ++idx) {
+ uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx);
+ bool BitField = i->isBitField();
+
+ // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned
+ // fields, it has class MEMORY.
+ //
+ // Note, skip this test for bit-fields, see below.
+ if (!BitField && Offset % Context.getTypeAlign(i->getType())) {
+ Lo = Memory;
+ return;
+ }
+
+ // Classify this field.
+ //
+ // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate
+ // exceeds a single eightbyte, each is classified
+ // separately. Each eightbyte gets initialized to class
+ // NO_CLASS.
+ Class FieldLo, FieldHi;
+
+ // Bit-fields require special handling, they do not force the
+ // structure to be passed in memory even if unaligned, and
+ // therefore they can straddle an eightbyte.
+ if (BitField) {
+ // Ignore padding bit-fields.
+ if (i->isUnnamedBitfield())
+ continue;
+
+ uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx);
+ uint64_t Size = i->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
+
+ uint64_t EB_Lo = Offset / 64;
+ uint64_t EB_Hi = (Offset + Size - 1) / 64;
+ FieldLo = FieldHi = NoClass;
+ if (EB_Lo) {
+ assert(EB_Hi == EB_Lo && "Invalid classification, type > 16 bytes.");
+ FieldLo = NoClass;
+ FieldHi = Integer;
+ } else {
+ FieldLo = Integer;
+ FieldHi = EB_Hi ? Integer : NoClass;
+ }
+ } else
+ classify(i->getType(), Context, Offset, FieldLo, FieldHi);
+ Lo = merge(Lo, FieldLo);
+ Hi = merge(Hi, FieldHi);
+ if (Lo == Memory || Hi == Memory)
+ break;
+ }
+
+ // AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done:
+ //
+ // (a) If one of the classes is MEMORY, the whole argument is
+ // passed in memory.
+ //
+ // (b) If SSEUP is not preceeded by SSE, it is converted to SSE.
+
+ // The first of these conditions is guaranteed by how we implement
+ // the merge (just bail).
+ //
+ // The second condition occurs in the case of unions; for example
+ // union { _Complex double; unsigned; }.
+ if (Hi == Memory)
+ Lo = Memory;
+ if (Hi == SSEUp && Lo != SSE)
+ Hi = SSE;
+ }
+}
+
+ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty,
+ const llvm::Type *CoerceTo,
+ ASTContext &Context) const {
+ if (CoerceTo == llvm::Type::getInt64Ty(CoerceTo->getContext())) {
+ // Integer and pointer types will end up in a general purpose
+ // register.
+ if (Ty->isIntegralType() || Ty->hasPointerRepresentation())
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ } else if (CoerceTo == llvm::Type::getDoubleTy(CoerceTo->getContext())) {
+ // FIXME: It would probably be better to make CGFunctionInfo only map using
+ // canonical types than to canonize here.
+ QualType CTy = Context.getCanonicalType(Ty);
+
+ // Float and double end up in a single SSE reg.
+ if (CTy == Context.FloatTy || CTy == Context.DoubleTy)
+ return ABIArgInfo::getDirect();
+
+ }
+
+ return ABIArgInfo::getCoerce(CoerceTo);
+}
+
+ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
+ ASTContext &Context) const {
+ // If this is a scalar LLVM value then assume LLVM will pass it in the right
+ // place naturally.
+ if (!CodeGenFunction::hasAggregateLLVMType(Ty))
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+
+ bool ByVal = !isRecordWithNonTrivialDestructorOrCopyConstructor(Ty);
+
+ // FIXME: Set alignment correctly.
+ return ABIArgInfo::getIndirect(0, ByVal);
+}
+
+ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the
+ // classification algorithm.
+ X86_64ABIInfo::Class Lo, Hi;
+ classify(RetTy, Context, 0, Lo, Hi);
+
+ // Check some invariants.
+ assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
+ assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification.");
+ assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification.");
+
+ const llvm::Type *ResType = 0;
+ switch (Lo) {
+ case NoClass:
+ return ABIArgInfo::getIgnore();
+
+ case SSEUp:
+ case X87Up:
+ assert(0 && "Invalid classification for lo word.");
+
+ // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via
+ // hidden argument.
+ case Memory:
+ return getIndirectResult(RetTy, Context);
+
+ // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next
+ // available register of the sequence %rax, %rdx is used.
+ case Integer:
+ ResType = llvm::Type::getInt64Ty(VMContext); break;
+
+ // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next
+ // available SSE register of the sequence %xmm0, %xmm1 is used.
+ case SSE:
+ ResType = llvm::Type::getDoubleTy(VMContext); break;
+
+ // AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is
+ // returned on the X87 stack in %st0 as 80-bit x87 number.
+ case X87:
+ ResType = llvm::Type::getX86_FP80Ty(VMContext); break;
+
+ // AMD64-ABI 3.2.3p4: Rule 8. If the class is COMPLEX_X87, the real
+ // part of the value is returned in %st0 and the imaginary part in
+ // %st1.
+ case ComplexX87:
+ assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification.");
+ ResType = llvm::StructType::get(VMContext, llvm::Type::getX86_FP80Ty(VMContext),
+ llvm::Type::getX86_FP80Ty(VMContext),
+ NULL);
+ break;
+ }
+
+ switch (Hi) {
+ // Memory was handled previously and X87 should
+ // never occur as a hi class.
+ case Memory:
+ case X87:
+ assert(0 && "Invalid classification for hi word.");
+
+ case ComplexX87: // Previously handled.
+ case NoClass: break;
+
+ case Integer:
+ ResType = llvm::StructType::get(VMContext, ResType,
+ llvm::Type::getInt64Ty(VMContext), NULL);
+ break;
+ case SSE:
+ ResType = llvm::StructType::get(VMContext, ResType,
+ llvm::Type::getDoubleTy(VMContext), NULL);
+ break;
+
+ // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte
+ // is passed in the upper half of the last used SSE register.
+ //
+ // SSEUP should always be preceeded by SSE, just widen.
+ case SSEUp:
+ assert(Lo == SSE && "Unexpected SSEUp classification.");
+ ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2);
+ break;
+
+ // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is
+ // returned together with the previous X87 value in %st0.
+ case X87Up:
+ // If X87Up is preceeded by X87, we don't need to do
+ // anything. However, in some cases with unions it may not be
+ // preceeded by X87. In such situations we follow gcc and pass the
+ // extra bits in an SSE reg.
+ if (Lo != X87)
+ ResType = llvm::StructType::get(VMContext, ResType,
+ llvm::Type::getDoubleTy(VMContext), NULL);
+ break;
+ }
+
+ return getCoerceResult(RetTy, ResType, Context);
+}
+
+ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
+ llvm::LLVMContext &VMContext,
+ unsigned &neededInt,
+ unsigned &neededSSE) const {
+ X86_64ABIInfo::Class Lo, Hi;
+ classify(Ty, Context, 0, Lo, Hi);
+
+ // Check some invariants.
+ // FIXME: Enforce these by construction.
+ assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
+ assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification.");
+ assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification.");
+
+ neededInt = 0;
+ neededSSE = 0;
+ const llvm::Type *ResType = 0;
+ switch (Lo) {
+ case NoClass:
+ return ABIArgInfo::getIgnore();
+
+ // AMD64-ABI 3.2.3p3: Rule 1. If the class is MEMORY, pass the argument
+ // on the stack.
+ case Memory:
+
+ // AMD64-ABI 3.2.3p3: Rule 5. If the class is X87, X87UP or
+ // COMPLEX_X87, it is passed in memory.
+ case X87:
+ case ComplexX87:
+ return getIndirectResult(Ty, Context);
+
+ case SSEUp:
+ case X87Up:
+ assert(0 && "Invalid classification for lo word.");
+
+ // AMD64-ABI 3.2.3p3: Rule 2. If the class is INTEGER, the next
+ // available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8
+ // and %r9 is used.
+ case Integer:
+ ++neededInt;
+ ResType = llvm::Type::getInt64Ty(VMContext);
+ break;
+
+ // AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next
+ // available SSE register is used, the registers are taken in the
+ // order from %xmm0 to %xmm7.
+ case SSE:
+ ++neededSSE;
+ ResType = llvm::Type::getDoubleTy(VMContext);
+ break;
+ }
+
+ switch (Hi) {
+ // Memory was handled previously, ComplexX87 and X87 should
+ // never occur as hi classes, and X87Up must be preceed by X87,
+ // which is passed in memory.
+ case Memory:
+ case X87:
+ case ComplexX87:
+ assert(0 && "Invalid classification for hi word.");
+ break;
+
+ case NoClass: break;
+ case Integer:
+ ResType = llvm::StructType::get(VMContext, ResType,
+ llvm::Type::getInt64Ty(VMContext), NULL);
+ ++neededInt;
+ break;
+
+ // X87Up generally doesn't occur here (long double is passed in
+ // memory), except in situations involving unions.
+ case X87Up:
+ case SSE:
+ ResType = llvm::StructType::get(VMContext, ResType,
+ llvm::Type::getDoubleTy(VMContext), NULL);
+ ++neededSSE;
+ break;
+
+ // AMD64-ABI 3.2.3p3: Rule 4. If the class is SSEUP, the
+ // eightbyte is passed in the upper half of the last used SSE
+ // register.
+ case SSEUp:
+ assert(Lo == SSE && "Unexpected SSEUp classification.");
+ ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2);
+ break;
+ }
+
+ return getCoerceResult(Ty, ResType, Context);
+}
+
+void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
+ Context, VMContext);
+
+ // Keep track of the number of assigned registers.
+ unsigned freeIntRegs = 6, freeSSERegs = 8;
+
+ // If the return value is indirect, then the hidden argument is consuming one
+ // integer register.
+ if (FI.getReturnInfo().isIndirect())
+ --freeIntRegs;
+
+ // AMD64-ABI 3.2.3p3: Once arguments are classified, the registers
+ // get assigned (in left-to-right order) for passing as follows...
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it) {
+ unsigned neededInt, neededSSE;
+ it->info = classifyArgumentType(it->type, Context, VMContext,
+ neededInt, neededSSE);
+
+ // AMD64-ABI 3.2.3p3: If there are no registers available for any
+ // eightbyte of an argument, the whole argument is passed on the
+ // stack. If registers have already been assigned for some
+ // eightbytes of such an argument, the assignments get reverted.
+ if (freeIntRegs >= neededInt && freeSSERegs >= neededSSE) {
+ freeIntRegs -= neededInt;
+ freeSSERegs -= neededSSE;
+ } else {
+ it->info = getIndirectResult(it->type, Context);
+ }
+ }
+}
+
+static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr,
+ QualType Ty,
+ CodeGenFunction &CGF) {
+ llvm::Value *overflow_arg_area_p =
+ CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_p");
+ llvm::Value *overflow_arg_area =
+ CGF.Builder.CreateLoad(overflow_arg_area_p, "overflow_arg_area");
+
+ // AMD64-ABI 3.5.7p5: Step 7. Align l->overflow_arg_area upwards to a 16
+ // byte boundary if alignment needed by type exceeds 8 byte boundary.
+ uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8;
+ if (Align > 8) {
+ // Note that we follow the ABI & gcc here, even though the type
+ // could in theory have an alignment greater than 16. This case
+ // shouldn't ever matter in practice.
+
+ // overflow_arg_area = (overflow_arg_area + 15) & ~15;
+ llvm::Value *Offset =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), 15);
+ overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset);
+ llvm::Value *AsInt = CGF.Builder.CreatePtrToInt(overflow_arg_area,
+ llvm::Type::getInt64Ty(CGF.getLLVMContext()));
+ llvm::Value *Mask = llvm::ConstantInt::get(
+ llvm::Type::getInt64Ty(CGF.getLLVMContext()), ~15LL);
+ overflow_arg_area =
+ CGF.Builder.CreateIntToPtr(CGF.Builder.CreateAnd(AsInt, Mask),
+ overflow_arg_area->getType(),
+ "overflow_arg_area.align");
+ }
+
+ // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area.
+ const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty);
+ llvm::Value *Res =
+ CGF.Builder.CreateBitCast(overflow_arg_area,
+ llvm::PointerType::getUnqual(LTy));
+
+ // AMD64-ABI 3.5.7p5: Step 9. Set l->overflow_arg_area to:
+ // l->overflow_arg_area + sizeof(type).
+ // AMD64-ABI 3.5.7p5: Step 10. Align l->overflow_arg_area upwards to
+ // an 8 byte boundary.
+
+ uint64_t SizeInBytes = (CGF.getContext().getTypeSize(Ty) + 7) / 8;
+ llvm::Value *Offset =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()),
+ (SizeInBytes + 7) & ~7);
+ overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset,
+ "overflow_arg_area.next");
+ CGF.Builder.CreateStore(overflow_arg_area, overflow_arg_area_p);
+
+ // AMD64-ABI 3.5.7p5: Step 11. Return the fetched type.
+ return Res;
+}
+
+llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ llvm::LLVMContext &VMContext = CGF.getLLVMContext();
+ const llvm::Type *i32Ty = llvm::Type::getInt32Ty(VMContext);
+ const llvm::Type *DoubleTy = llvm::Type::getDoubleTy(VMContext);
+
+ // Assume that va_list type is correct; should be pointer to LLVM type:
+ // struct {
+ // i32 gp_offset;
+ // i32 fp_offset;
+ // i8* overflow_arg_area;
+ // i8* reg_save_area;
+ // };
+ unsigned neededInt, neededSSE;
+ ABIArgInfo AI = classifyArgumentType(Ty, CGF.getContext(), VMContext,
+ neededInt, neededSSE);
+
+ // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed
+ // in the registers. If not go to step 7.
+ if (!neededInt && !neededSSE)
+ return EmitVAArgFromMemory(VAListAddr, Ty, CGF);
+
+ // AMD64-ABI 3.5.7p5: Step 2. Compute num_gp to hold the number of
+ // general purpose registers needed to pass type and num_fp to hold
+ // the number of floating point registers needed.
+
+ // AMD64-ABI 3.5.7p5: Step 3. Verify whether arguments fit into
+ // registers. In the case: l->gp_offset > 48 - num_gp * 8 or
+ // l->fp_offset > 304 - num_fp * 16 go to step 7.
+ //
+ // NOTE: 304 is a typo, there are (6 * 8 + 8 * 16) = 176 bytes of
+ // register save space).
+
+ llvm::Value *InRegs = 0;
+ llvm::Value *gp_offset_p = 0, *gp_offset = 0;
+ llvm::Value *fp_offset_p = 0, *fp_offset = 0;
+ if (neededInt) {
+ gp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "gp_offset_p");
+ gp_offset = CGF.Builder.CreateLoad(gp_offset_p, "gp_offset");
+ InRegs =
+ CGF.Builder.CreateICmpULE(gp_offset,
+ llvm::ConstantInt::get(i32Ty,
+ 48 - neededInt * 8),
+ "fits_in_gp");
+ }
+
+ if (neededSSE) {
+ fp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 1, "fp_offset_p");
+ fp_offset = CGF.Builder.CreateLoad(fp_offset_p, "fp_offset");
+ llvm::Value *FitsInFP =
+ CGF.Builder.CreateICmpULE(fp_offset,
+ llvm::ConstantInt::get(i32Ty,
+ 176 - neededSSE * 16),
+ "fits_in_fp");
+ InRegs = InRegs ? CGF.Builder.CreateAnd(InRegs, FitsInFP) : FitsInFP;
+ }
+
+ llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg");
+ llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem");
+ llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end");
+ CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock);
+
+ // Emit code to load the value if it was passed in registers.
+
+ CGF.EmitBlock(InRegBlock);
+
+ // AMD64-ABI 3.5.7p5: Step 4. Fetch type from l->reg_save_area with
+ // an offset of l->gp_offset and/or l->fp_offset. This may require
+ // copying to a temporary location in case the parameter is passed
+ // in different register classes or requires an alignment greater
+ // than 8 for general purpose registers and 16 for XMM registers.
+ //
+ // FIXME: This really results in shameful code when we end up needing to
+ // collect arguments from different places; often what should result in a
+ // simple assembling of a structure from scattered addresses has many more
+ // loads than necessary. Can we clean this up?
+ const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty);
+ llvm::Value *RegAddr =
+ CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(VAListAddr, 3),
+ "reg_save_area");
+ if (neededInt && neededSSE) {
+ // FIXME: Cleanup.
+ assert(AI.isCoerce() && "Unexpected ABI info for mixed regs");
+ const llvm::StructType *ST = cast<llvm::StructType>(AI.getCoerceToType());
+ llvm::Value *Tmp = CGF.CreateTempAlloca(ST);
+ assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs");
+ const llvm::Type *TyLo = ST->getElementType(0);
+ const llvm::Type *TyHi = ST->getElementType(1);
+ assert((TyLo->isFloatingPoint() ^ TyHi->isFloatingPoint()) &&
+ "Unexpected ABI info for mixed regs");
+ const llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo);
+ const llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi);
+ llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset);
+ llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset);
+ llvm::Value *RegLoAddr = TyLo->isFloatingPoint() ? FPAddr : GPAddr;
+ llvm::Value *RegHiAddr = TyLo->isFloatingPoint() ? GPAddr : FPAddr;
+ llvm::Value *V =
+ CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegLoAddr, PTyLo));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
+ V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegHiAddr, PTyHi));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1));
+
+ RegAddr = CGF.Builder.CreateBitCast(Tmp,
+ llvm::PointerType::getUnqual(LTy));
+ } else if (neededInt) {
+ RegAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset);
+ RegAddr = CGF.Builder.CreateBitCast(RegAddr,
+ llvm::PointerType::getUnqual(LTy));
+ } else {
+ if (neededSSE == 1) {
+ RegAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset);
+ RegAddr = CGF.Builder.CreateBitCast(RegAddr,
+ llvm::PointerType::getUnqual(LTy));
+ } else {
+ assert(neededSSE == 2 && "Invalid number of needed registers!");
+ // SSE registers are spaced 16 bytes apart in the register save
+ // area, we need to collect the two eightbytes together.
+ llvm::Value *RegAddrLo = CGF.Builder.CreateGEP(RegAddr, fp_offset);
+ llvm::Value *RegAddrHi =
+ CGF.Builder.CreateGEP(RegAddrLo,
+ llvm::ConstantInt::get(i32Ty, 16));
+ const llvm::Type *DblPtrTy =
+ llvm::PointerType::getUnqual(DoubleTy);
+ const llvm::StructType *ST = llvm::StructType::get(VMContext, DoubleTy,
+ DoubleTy, NULL);
+ llvm::Value *V, *Tmp = CGF.CreateTempAlloca(ST);
+ V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo,
+ DblPtrTy));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
+ V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrHi,
+ DblPtrTy));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1));
+ RegAddr = CGF.Builder.CreateBitCast(Tmp,
+ llvm::PointerType::getUnqual(LTy));
+ }
+ }
+
+ // AMD64-ABI 3.5.7p5: Step 5. Set:
+ // l->gp_offset = l->gp_offset + num_gp * 8
+ // l->fp_offset = l->fp_offset + num_fp * 16.
+ if (neededInt) {
+ llvm::Value *Offset = llvm::ConstantInt::get(i32Ty, neededInt * 8);
+ CGF.Builder.CreateStore(CGF.Builder.CreateAdd(gp_offset, Offset),
+ gp_offset_p);
+ }
+ if (neededSSE) {
+ llvm::Value *Offset = llvm::ConstantInt::get(i32Ty, neededSSE * 16);
+ CGF.Builder.CreateStore(CGF.Builder.CreateAdd(fp_offset, Offset),
+ fp_offset_p);
+ }
+ CGF.EmitBranch(ContBlock);
+
+ // Emit code to load the value if it was passed in memory.
+
+ CGF.EmitBlock(InMemBlock);
+ llvm::Value *MemAddr = EmitVAArgFromMemory(VAListAddr, Ty, CGF);
+
+ // Return the appropriate result.
+
+ CGF.EmitBlock(ContBlock);
+ llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(RegAddr->getType(),
+ "vaarg.addr");
+ ResAddr->reserveOperandSpace(2);
+ ResAddr->addIncoming(RegAddr, InRegBlock);
+ ResAddr->addIncoming(MemAddr, InMemBlock);
+
+ return ResAddr;
+}
+
+// PIC16 ABI Implementation
+
+namespace {
+
+class PIC16ABIInfo : public ABIInfo {
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ ABIArgInfo classifyArgumentType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
+ VMContext);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type, Context, VMContext);
+ }
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class PIC16TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ PIC16TargetCodeGenInfo():TargetCodeGenInfo(new PIC16ABIInfo()) {};
+};
+
+}
+
+ABIArgInfo PIC16ABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (RetTy->isVoidType()) {
+ return ABIArgInfo::getIgnore();
+ } else {
+ return ABIArgInfo::getDirect();
+ }
+}
+
+ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ return ABIArgInfo::getDirect();
+}
+
+llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ return 0;
+}
+
+// ARM ABI Implementation
+
+namespace {
+
+class ARMABIInfo : public ABIInfo {
+public:
+ enum ABIKind {
+ APCS = 0,
+ AAPCS = 1,
+ AAPCS_VFP
+ };
+
+private:
+ ABIKind Kind;
+
+public:
+ ARMABIInfo(ABIKind _Kind) : Kind(_Kind) {}
+
+private:
+ ABIKind getABIKind() const { return Kind; }
+
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMCOntext) const;
+
+ ABIArgInfo classifyArgumentType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ ARMTargetCodeGenInfo(ARMABIInfo::ABIKind K)
+ :TargetCodeGenInfo(new ARMABIInfo(K)) {};
+};
+
+}
+
+void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
+ VMContext);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it) {
+ it->info = classifyArgumentType(it->type, Context, VMContext);
+ }
+
+ // ARM always overrides the calling convention.
+ switch (getABIKind()) {
+ case APCS:
+ FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_APCS);
+ break;
+
+ case AAPCS:
+ FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS);
+ break;
+
+ case AAPCS_VFP:
+ FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP);
+ break;
+ }
+}
+
+ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (!CodeGenFunction::hasAggregateLLVMType(Ty))
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+
+ // Ignore empty records.
+ if (isEmptyRecord(Context, Ty, true))
+ return ABIArgInfo::getIgnore();
+
+ // FIXME: This is kind of nasty... but there isn't much choice because the ARM
+ // backend doesn't support byval.
+ // FIXME: This doesn't handle alignment > 64 bits.
+ const llvm::Type* ElemTy;
+ unsigned SizeRegs;
+ if (Context.getTypeAlign(Ty) > 32) {
+ ElemTy = llvm::Type::getInt64Ty(VMContext);
+ SizeRegs = (Context.getTypeSize(Ty) + 63) / 64;
+ } else {
+ ElemTy = llvm::Type::getInt32Ty(VMContext);
+ SizeRegs = (Context.getTypeSize(Ty) + 31) / 32;
+ }
+ std::vector<const llvm::Type*> LLVMFields;
+ LLVMFields.push_back(llvm::ArrayType::get(ElemTy, SizeRegs));
+ const llvm::Type* STy = llvm::StructType::get(VMContext, LLVMFields, true);
+ return ABIArgInfo::getCoerce(STy);
+}
+
+static bool isIntegerLikeType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) {
+ // APCS, C Language Calling Conventions, Non-Simple Return Values: A structure
+ // is called integer-like if its size is less than or equal to one word, and
+ // the offset of each of its addressable sub-fields is zero.
+
+ uint64_t Size = Context.getTypeSize(Ty);
+
+ // Check that the type fits in a word.
+ if (Size > 32)
+ return false;
+
+ // FIXME: Handle vector types!
+ if (Ty->isVectorType())
+ return false;
+
+ // Float types are never treated as "integer like".
+ if (Ty->isRealFloatingType())
+ return false;
+
+ // If this is a builtin or pointer type then it is ok.
+ if (Ty->getAs<BuiltinType>() || Ty->isPointerType())
+ return true;
+
+ // Complex types "should" be ok by the definition above, but they are not.
+ if (Ty->isAnyComplexType())
+ return false;
+
+ // Single element and zero sized arrays should be allowed, by the definition
+ // above, but they are not.
+
+ // Otherwise, it must be a record type.
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (!RT) return false;
+
+ // Ignore records with flexible arrays.
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->hasFlexibleArrayMember())
+ return false;
+
+ // Check that all sub-fields are at offset 0, and are themselves "integer
+ // like".
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ bool HadField = false;
+ unsigned idx = 0;
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i, ++idx) {
+ const FieldDecl *FD = *i;
+
+ // Check if this field is at offset 0.
+ uint64_t Offset = Layout.getFieldOffset(idx);
+ if (Offset != 0) {
+ // Allow padding bit-fields, but only if they are all at the end of the
+ // structure (despite the wording above, this matches gcc).
+ if (FD->isBitField() &&
+ !FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
+ for (; i != e; ++i)
+ if (!i->isBitField() ||
+ i->getBitWidth()->EvaluateAsInt(Context).getZExtValue())
+ return false;
+
+ // All remaining fields are padding, allow this.
+ return true;
+ }
+
+ return false;
+ }
+
+ if (!isIntegerLikeType(FD->getType(), Context, VMContext))
+ return false;
+
+ // Only allow at most one field in a structure. Again this doesn't match the
+ // wording above, but follows gcc.
+ if (!RD->isUnion()) {
+ if (HadField)
+ return false;
+
+ HadField = true;
+ }
+ }
+
+ return true;
+}
+
+ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (RetTy->isVoidType())
+ return ABIArgInfo::getIgnore();
+
+ if (!CodeGenFunction::hasAggregateLLVMType(RetTy))
+ return (RetTy->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+
+ // Are we following APCS?
+ if (getABIKind() == APCS) {
+ if (isEmptyRecord(Context, RetTy, false))
+ return ABIArgInfo::getIgnore();
+
+ // Integer like structures are returned in r0.
+ if (isIntegerLikeType(RetTy, Context, VMContext)) {
+ // Return in the smallest viable integer type.
+ uint64_t Size = Context.getTypeSize(RetTy);
+ if (Size <= 8)
+ return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext));
+ if (Size <= 16)
+ return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext));
+ return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext));
+ }
+
+ // Otherwise return in memory.
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ // Otherwise this is an AAPCS variant.
+
+ if (isEmptyRecord(Context, RetTy, true))
+ return ABIArgInfo::getIgnore();
+
+ // Aggregates <= 4 bytes are returned in r0; other aggregates
+ // are returned indirectly.
+ uint64_t Size = Context.getTypeSize(RetTy);
+ if (Size <= 32) {
+ // Return in the smallest viable integer type.
+ if (Size <= 8)
+ return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext));
+ if (Size <= 16)
+ return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext));
+ return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext));
+ }
+
+ return ABIArgInfo::getIndirect(0);
+}
+
+llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ // FIXME: Need to handle alignment
+ const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ const llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
+
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP,
+ "ap");
+ llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
+ llvm::Type *PTy =
+ llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
+
+ uint64_t Offset =
+ llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4);
+ llvm::Value *NextAddr =
+ Builder.CreateGEP(Addr, llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(CGF.getLLVMContext()), Offset),
+ "ap.next");
+ Builder.CreateStore(NextAddr, VAListAddrAsBPP);
+
+ return AddrTyped;
+}
+
+ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (RetTy->isVoidType()) {
+ return ABIArgInfo::getIgnore();
+ } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return (RetTy->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+}
+
+// SystemZ ABI Implementation
+
+namespace {
+
+class SystemZABIInfo : public ABIInfo {
+ bool isPromotableIntegerType(QualType Ty) const;
+
+ ABIArgInfo classifyReturnType(QualType RetTy, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ ABIArgInfo classifyArgumentType(QualType RetTy, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
+ Context, VMContext);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type, Context, VMContext);
+ }
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ SystemZTargetCodeGenInfo():TargetCodeGenInfo(new SystemZABIInfo()) {};
+};
+
+}
+
+bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const {
+ // SystemZ ABI requires all 8, 16 and 32 bit quantities to be extended.
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
+ switch (BT->getKind()) {
+ case BuiltinType::Bool:
+ case BuiltinType::Char_S:
+ case BuiltinType::Char_U:
+ case BuiltinType::SChar:
+ case BuiltinType::UChar:
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
+llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ // FIXME: Implement
+ return 0;
+}
+
+
+ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (RetTy->isVoidType()) {
+ return ABIArgInfo::getIgnore();
+ } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return (isPromotableIntegerType(RetTy) ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+}
+
+ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return (isPromotableIntegerType(Ty) ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+}
+
+// MSP430 ABI Implementation
+
+namespace {
+
+class MSP430TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ MSP430TargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {};
+ void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const;
+};
+
+}
+
+void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
+ llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (const MSP430InterruptAttr *attr = FD->getAttr<MSP430InterruptAttr>()) {
+ // Handle 'interrupt' attribute:
+ llvm::Function *F = cast<llvm::Function>(GV);
+
+ // Step 1: Set ISR calling convention.
+ F->setCallingConv(llvm::CallingConv::MSP430_INTR);
+
+ // Step 2: Add attributes goodness.
+ F->addFnAttr(llvm::Attribute::NoInline);
+
+ // Step 3: Emit ISR vector alias.
+ unsigned Num = attr->getNumber() + 0xffe0;
+ new llvm::GlobalAlias(GV->getType(), llvm::Function::ExternalLinkage,
+ "vector_" +
+ llvm::LowercaseString(llvm::utohexstr(Num)),
+ GV, &M.getModule());
+ }
+ }
+}
+
+const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() const {
+ if (TheTargetCodeGenInfo)
+ return *TheTargetCodeGenInfo;
+
+ // For now we just cache the TargetCodeGenInfo in CodeGenModule and don't
+ // free it.
+
+ const llvm::Triple &Triple(getContext().Target.getTriple());
+ switch (Triple.getArch()) {
+ default:
+ return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo);
+
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ // FIXME: We want to know the float calling convention as well.
+ if (strcmp(getContext().Target.getABI(), "apcs-gnu") == 0)
+ return *(TheTargetCodeGenInfo =
+ new ARMTargetCodeGenInfo(ARMABIInfo::APCS));
+
+ return *(TheTargetCodeGenInfo =
+ new ARMTargetCodeGenInfo(ARMABIInfo::AAPCS));
+
+ case llvm::Triple::pic16:
+ return *(TheTargetCodeGenInfo = new PIC16TargetCodeGenInfo());
+
+ case llvm::Triple::systemz:
+ return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo());
+
+ case llvm::Triple::msp430:
+ return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo());
+
+ case llvm::Triple::x86:
+ switch (Triple.getOS()) {
+ case llvm::Triple::Darwin:
+ return *(TheTargetCodeGenInfo =
+ new X86_32TargetCodeGenInfo(Context, true, true));
+ case llvm::Triple::Cygwin:
+ case llvm::Triple::MinGW32:
+ case llvm::Triple::MinGW64:
+ case llvm::Triple::AuroraUX:
+ case llvm::Triple::DragonFly:
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::OpenBSD:
+ return *(TheTargetCodeGenInfo =
+ new X86_32TargetCodeGenInfo(Context, false, true));
+
+ default:
+ return *(TheTargetCodeGenInfo =
+ new X86_32TargetCodeGenInfo(Context, false, false));
+ }
+
+ case llvm::Triple::x86_64:
+ return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo());
+ }
+}
diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h
new file mode 100644
index 0000000..495b22f
--- /dev/null
+++ b/lib/CodeGen/TargetInfo.h
@@ -0,0 +1,50 @@
+//===---- TargetInfo.h - Encapsulate target details -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes wrap the information about a call or function
+// definition used to handle ABI compliancy.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_TARGETINFO_H
+#define CLANG_CODEGEN_TARGETINFO_H
+
+namespace llvm {
+ class GlobalValue;
+}
+
+namespace clang {
+ class ABIInfo;
+ class Decl;
+
+ namespace CodeGen {
+ class CodeGenModule;
+ }
+
+ /// TargetCodeGenInfo - This class organizes various target-specific
+ /// codegeneration issues, like target-specific attributes, builtins and so
+ /// on.
+ class TargetCodeGenInfo {
+ ABIInfo *Info;
+ public:
+ // WARNING: Acquires the ownership of ABIInfo.
+ TargetCodeGenInfo(ABIInfo *info = 0):Info(info) { };
+ virtual ~TargetCodeGenInfo();
+
+ /// getABIInfo() - Returns ABI info helper for the target.
+ const ABIInfo& getABIInfo() const { return *Info; }
+
+ /// SetTargetAttributes - Provides a convenient hook to handle extra
+ /// target-specific attributes for the given global.
+ virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const { };
+ };
+}
+
+#endif // CLANG_CODEGEN_TARGETINFO_H
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index cc3febf..42657d9 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -203,8 +203,8 @@ void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args,
CmdArgs.push_back("-lgcc_s.10.5");
}
} else if (Args.hasArg(options::OPT_shared_libgcc) ||
- // FIXME: -fexceptions -fno-exceptions means no exceptions
- Args.hasArg(options::OPT_fexceptions) ||
+ Args.hasFlag(options::OPT_fexceptions,
+ options::OPT_fno_exceptions) ||
Args.hasArg(options::OPT_fgnu_runtime)) {
// FIXME: This is probably broken on 10.3?
if (isMacosxVersionLT(MacosxVersionMin, 10, 5))
@@ -516,10 +516,6 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args,
return DAL;
}
-bool Darwin::IsMathErrnoDefault() const {
- return false;
-}
-
bool Darwin::IsUnwindTablesDefault() const {
// FIXME: Gross; we should probably have some separate target
// definition, possibly even reusing the one in clang.
@@ -599,10 +595,6 @@ Tool &Generic_GCC::SelectTool(const Compilation &C,
return *T;
}
-bool Generic_GCC::IsMathErrnoDefault() const {
- return true;
-}
-
bool Generic_GCC::IsUnwindTablesDefault() const {
// FIXME: Gross; we should probably have some separate target
// definition, possibly even reusing the one in clang.
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index be36344..374ad8c 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -38,7 +38,6 @@ public:
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
- virtual bool IsMathErrnoDefault() const;
virtual bool IsUnwindTablesDefault() const;
virtual const char *GetDefaultRelocationModel() const;
virtual const char *GetForcedPicModel() const;
@@ -136,7 +135,6 @@ public:
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
- virtual bool IsMathErrnoDefault() const;
virtual bool IsBlocksDefault() const {
// Blocks default to on for 10.6 (darwin10) and beyond.
return (DarwinVersion[0] > 9);
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 8f0af21..010953d 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -837,11 +837,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
break;
}
- // -fmath-errno is default.
- if (!Args.hasFlag(options::OPT_fmath_errno,
+ // -fno-math-errno is default.
+ if (Args.hasFlag(options::OPT_fmath_errno,
options::OPT_fno_math_errno,
- getToolChain().IsMathErrnoDefault()))
- CmdArgs.push_back("-fno-math-errno");
+ false))
+ CmdArgs.push_back("-fmath-errno");
Arg *Unsupported;
if ((Unsupported = Args.getLastArg(options::OPT_MG)) ||
@@ -935,6 +935,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
}
+ if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) {
+ CmdArgs.push_back("-ftabstop");
+ CmdArgs.push_back(A->getValue(Args));
+ }
+
// Pass -fmessage-length=.
CmdArgs.push_back("-fmessage-length");
if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
@@ -2069,13 +2074,7 @@ void darwin::Link::AddLinkArgs(const ArgList &Args,
Args.AddAllArgs(CmdArgs, options::OPT_umbrella);
Args.AddAllArgs(CmdArgs, options::OPT_undefined);
Args.AddAllArgs(CmdArgs, options::OPT_unexported__symbols__list);
-
Args.AddAllArgs(CmdArgs, options::OPT_weak__reference__mismatches);
- if (!Args.hasArg(options::OPT_weak__reference__mismatches)) {
- CmdArgs.push_back("-weak_reference_mismatches");
- CmdArgs.push_back("non-weak");
- }
-
Args.AddLastArg(CmdArgs, options::OPT_X_Flag);
Args.AddAllArgs(CmdArgs, options::OPT_y);
Args.AddLastArg(CmdArgs, options::OPT_w);
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 433af03..60d86a6 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -77,6 +77,7 @@ bool types::isAcceptedByClang(ID Id) {
case TY_Asm:
case TY_C: case TY_PP_C:
+ case TY_CL:
case TY_ObjC: case TY_PP_ObjC:
case TY_CXX: case TY_PP_CXX:
case TY_ObjCXX: case TY_PP_ObjCXX:
@@ -133,6 +134,7 @@ types::ID types::lookupTypeForExtension(const char *Ext) {
.Case("mm", TY_ObjCXX)
.Case("cc", TY_CXX)
.Case("CC", TY_CXX)
+ .Case("cl", TY_CL)
.Case("cp", TY_CXX)
.Case("hh", TY_CXXHeader)
.Case("hpp", TY_CXXHeader)
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index f1a6666..52b597e 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -408,6 +408,19 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "<function template> " << FTD->getNameAsString() << "\n";
break;
}
+ case Decl::FileScopeAsm: {
+ Out << "<file-scope asm>\n";
+ break;
+ }
+ case Decl::UsingDirective: {
+ Out << "<using directive>\n";
+ break;
+ }
+ case Decl::NamespaceAlias: {
+ NamespaceAliasDecl* NAD = cast<NamespaceAliasDecl>(*I);
+ Out << "<namespace alias> " << NAD->getNameAsString() << "\n";
+ break;
+ }
default:
Out << "DeclKind: " << DK << '"' << I->getDeclKindName() << "\"\n";
assert(0 && "decl unhandled");
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index 6824d8f..ad152d3 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -363,7 +363,7 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
if (!mgr.getLiveVariables(D))
return;
- GRExprEngine Eng(mgr);
+ GRExprEngine Eng(mgr, TF.take());
if (C.Opts.EnableExperimentalInternalChecks)
RegisterExperimentalInternalChecks(Eng);
@@ -373,8 +373,6 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
if (C.Opts.EnableExperimentalChecks)
RegisterExperimentalChecks(Eng);
- Eng.setTransferFunctionsAndCheckers(tf);
-
// Set the graph auditor.
llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
if (mgr.shouldVisualizeUbigraph()) {
@@ -494,7 +492,9 @@ static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr,
// Display progress.
C.DisplayFunction(D);
- GRExprEngine Eng(mgr);
+ // FIXME: Make a fake transfer function. The GRTransferFunc interface
+ // eventually will be removed.
+ GRExprEngine Eng(mgr, new GRTransferFuncs());
if (C.Opts.EnableExperimentalInternalChecks)
RegisterExperimentalInternalChecks(Eng);
@@ -503,10 +503,6 @@ static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr,
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);
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 2a6a8a8..19c740d 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -14,10 +14,12 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Version.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PTHManager.h"
#include "clang/Frontend/ChainedDiagnosticClient.h"
+#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/PCHReader.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
@@ -28,6 +30,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Timer.h"
+#include "llvm/System/Host.h"
#include "llvm/System/Path.h"
#include "llvm/System/Program.h"
using namespace clang;
@@ -155,7 +158,8 @@ void CompilerInstance::createPreprocessor() {
PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(),
getPreprocessorOpts(), getHeaderSearchOpts(),
getDependencyOutputOpts(), getTarget(),
- getSourceManager(), getFileManager()));
+ getFrontendOpts(), getSourceManager(),
+ getFileManager()));
}
Preprocessor *
@@ -165,6 +169,7 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
const HeaderSearchOptions &HSOpts,
const DependencyOutputOptions &DepOpts,
const TargetInfo &Target,
+ const FrontendOptions &FEOpts,
SourceManager &SourceMgr,
FileManager &FileMgr) {
// Create a PTH manager if we are using some form of a token cache.
@@ -186,7 +191,7 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
PP->setPTHManager(PTHMgr);
}
- InitializePreprocessor(*PP, PPOpts, HSOpts);
+ InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts);
// Handle generating dependencies, if requested.
if (!DepOpts.OutputFile.empty())
@@ -409,3 +414,87 @@ bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile,
return true;
}
+
+// High-Level Operations
+
+bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
+ assert(hasDiagnostics() && "Diagnostics engine is not initialized!");
+ assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!");
+ assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!");
+
+ // FIXME: Take this as an argument, once all the APIs we used have moved to
+ // taking it as an input instead of hard-coding llvm::errs.
+ llvm::raw_ostream &OS = llvm::errs();
+
+ // Create the target instance.
+ setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts()));
+ if (!hasTarget())
+ return false;
+
+ // Inform the target of the language options.
+ //
+ // FIXME: We shouldn't need to do this, the target should be immutable once
+ // created. This complexity should be lifted elsewhere.
+ getTarget().setForcedLangOptions(getLangOpts());
+
+ // Validate/process some options.
+ if (getHeaderSearchOpts().Verbose)
+ OS << "clang -cc1 version " CLANG_VERSION_STRING
+ << " based upon " << PACKAGE_STRING
+ << " hosted on " << llvm::sys::getHostTriple() << "\n";
+
+ if (getFrontendOpts().ShowTimers)
+ createFrontendTimer();
+
+ for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) {
+ const std::string &InFile = getFrontendOpts().Inputs[i].second;
+
+ // If we aren't using an AST file, setup the file and source managers and
+ // the preprocessor.
+ bool IsAST = getFrontendOpts().Inputs[i].first == FrontendOptions::IK_AST;
+ if (!IsAST) {
+ if (!i) {
+ // Create a file manager object to provide access to and cache the
+ // filesystem.
+ createFileManager();
+
+ // Create the source manager.
+ createSourceManager();
+ } else {
+ // Reset the ID tables if we are reusing the SourceManager.
+ getSourceManager().clearIDTables();
+ }
+
+ // Create the preprocessor.
+ createPreprocessor();
+ }
+
+ if (Act.BeginSourceFile(*this, InFile, IsAST)) {
+ Act.Execute();
+ Act.EndSourceFile();
+ }
+ }
+
+ if (getDiagnosticOpts().ShowCarets)
+ if (unsigned NumDiagnostics = getDiagnostics().getNumDiagnostics())
+ OS << NumDiagnostics << " diagnostic"
+ << (NumDiagnostics == 1 ? "" : "s")
+ << " generated.\n";
+
+ if (getFrontendOpts().ShowStats) {
+ getFileManager().PrintStats();
+ OS << "\n";
+ }
+
+ // Return the appropriate status when verifying diagnostics.
+ //
+ // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need
+ // this.
+ if (getDiagnosticOpts().VerifyDiagnostics)
+ return !static_cast<VerifyDiagnosticsClient&>(
+ getDiagnosticClient()).HadErrors();
+
+ return !getDiagnostics().getNumErrors();
+}
+
+
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 63f66fa..0bca475 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -222,6 +222,10 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
Res.push_back("-verify");
if (Opts.ShowOptionNames)
Res.push_back("-fdiagnostics-show-option");
+ if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) {
+ Res.push_back("-ftabstop");
+ Res.push_back(llvm::utostr(Opts.TabStop));
+ }
if (Opts.MessageLength) {
Res.push_back("-fmessage-length");
Res.push_back(llvm::utostr(Opts.MessageLength));
@@ -479,8 +483,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fblocks");
if (Opts.EmitAllDecls)
Res.push_back("-femit-all-decls");
- if (!Opts.MathErrno)
- Res.push_back("-fno-math-errno");
+ if (Opts.MathErrno)
+ Res.push_back("-fmath-errno");
if (Opts.OverflowChecking)
Res.push_back("-ftrapv");
if (Opts.HeinousExtensions)
@@ -804,6 +808,13 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option);
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
+ Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
+ DiagnosticOptions::DefaultTabStop, Diags);
+ if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
+ Diags.Report(diag::warn_ignoring_ftabstop_value)
+ << Opts.TabStop << DiagnosticOptions::DefaultTabStop;
+ Opts.TabStop = DiagnosticOptions::DefaultTabStop;
+ }
Opts.MessageLength = getLastArgIntValue(Args, OPT_fmessage_length, 0, Diags);
Opts.DumpBuildInformation = getLastArgValue(Args, OPT_dump_build_information);
Opts.Warnings = getAllArgValues(Args, OPT_W);
@@ -1147,7 +1158,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);
Opts.AccessControl = Args.hasArg(OPT_faccess_control);
Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);
- Opts.MathErrno = !Args.hasArg(OPT_fno_math_errno);
+ Opts.MathErrno = Args.hasArg(OPT_fmath_errno);
Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 99,
Diags);
Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime);
diff --git a/lib/Frontend/FixItRewriter.cpp b/lib/Frontend/FixItRewriter.cpp
index 4fa2b3c..0b04cf2 100644
--- a/lib/Frontend/FixItRewriter.cpp
+++ b/lib/Frontend/FixItRewriter.cpp
@@ -115,6 +115,9 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
if (!AcceptableLocation)
return;
+ } else if (DiagLevel == Diagnostic::Note) {
+ // Don't apply fix-it modifications in notes.
+ return;
}
// Make sure that we can perform all of the modifications we
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 4c647fda..0baba3f 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -280,7 +280,9 @@ void PrintParseAction::ExecuteAction() {
void PrintPreprocessedAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
- llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
+ // Output file needs to be set to 'Binary', to avoid converting Unix style
+ // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>).
+ llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
if (!OS) return;
DoPrintPreprocessedInput(CI.getPreprocessor(), OS,
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 9555125..6fceb98 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -477,6 +477,9 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0",
"i686-apple-darwin8", "", "", triple);
break;
+ case llvm::Triple::DragonFly:
+ AddPath("/usr/include/c++/4.1", System, true, false, false);
+ break;
case llvm::Triple::Linux:
// Exherbo (2009-10-26)
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
@@ -553,9 +556,6 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
"i686-pc-linux-gnu", "", "", triple);
break;
case llvm::Triple::FreeBSD:
- // DragonFly
- AddPath("/usr/include/c++/4.1", System, true, false, false);
- // FreeBSD
AddPath("/usr/include/c++/4.2", System, true, false, false);
break;
case llvm::Triple::Solaris:
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index c1fc92d..e4c380a 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -14,13 +14,12 @@
#include "clang/Frontend/Utils.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/PreprocessorOptions.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/APFloat.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/System/Path.h"
using namespace clang;
@@ -28,43 +27,22 @@ using namespace clang;
// Append a #define line to Buf for Macro. Macro should be of the form XXX,
// in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit
// "#define XXX Y z W". To get a #define with no value, use "XXX=".
-static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro,
- Diagnostic *Diags = 0) {
- const char *Command = "#define ";
- Buf.insert(Buf.end(), Command, Command+strlen(Command));
- if (const char *Equal = strchr(Macro, '=')) {
- // Turn the = into ' '.
- Buf.insert(Buf.end(), Macro, Equal);
- Buf.push_back(' ');
-
+static void DefineBuiltinMacro(MacroBuilder &Builder, llvm::StringRef Macro,
+ Diagnostic &Diags) {
+ std::pair<llvm::StringRef, llvm::StringRef> MacroPair = Macro.split('=');
+ llvm::StringRef MacroName = MacroPair.first;
+ llvm::StringRef MacroBody = MacroPair.second;
+ if (MacroName.size() != Macro.size()) {
// Per GCC -D semantics, the macro ends at \n if it exists.
- const char *End = strpbrk(Equal, "\n\r");
- if (End) {
- assert(Diags && "Unexpected macro with embedded newline!");
- Diags->Report(diag::warn_fe_macro_contains_embedded_newline)
- << std::string(Macro, Equal);
- } else {
- End = Equal+strlen(Equal);
- }
-
- Buf.insert(Buf.end(), Equal+1, End);
+ llvm::StringRef::size_type End = MacroBody.find_first_of("\n\r");
+ if (End != llvm::StringRef::npos)
+ Diags.Report(diag::warn_fe_macro_contains_embedded_newline)
+ << MacroName;
+ Builder.defineMacro(MacroName, MacroBody.substr(0, End));
} else {
// Push "macroname 1".
- Buf.insert(Buf.end(), Macro, Macro+strlen(Macro));
- Buf.push_back(' ');
- Buf.push_back('1');
+ Builder.defineMacro(Macro);
}
- Buf.push_back('\n');
-}
-
-// Append a #undef line to Buf for Macro. Macro should be of the form XXX
-// and we emit "#undef XXX".
-static void UndefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) {
- // Push "macroname".
- const char *Command = "#undef ";
- Buf.insert(Buf.end(), Command, Command+strlen(Command));
- Buf.insert(Buf.end(), Macro, Macro+strlen(Macro));
- Buf.push_back('\n');
}
std::string clang::NormalizeDashIncludePath(llvm::StringRef File) {
@@ -83,42 +61,25 @@ std::string clang::NormalizeDashIncludePath(llvm::StringRef File) {
return Lexer::Stringify(Path.str());
}
-/// Add the quoted name of an implicit include file.
-static void AddQuotedIncludePath(std::vector<char> &Buf,
- const std::string &File) {
-
- // Escape double quotes etc.
- Buf.push_back('"');
- std::string EscapedFile = NormalizeDashIncludePath(File);
- Buf.insert(Buf.end(), EscapedFile.begin(), EscapedFile.end());
- Buf.push_back('"');
-}
-
/// AddImplicitInclude - Add an implicit #include of the specified file to the
/// predefines buffer.
-static void AddImplicitInclude(std::vector<char> &Buf,
- const std::string &File) {
- const char *Inc = "#include ";
- Buf.insert(Buf.end(), Inc, Inc+strlen(Inc));
- AddQuotedIncludePath(Buf, File);
- Buf.push_back('\n');
+static void AddImplicitInclude(MacroBuilder &Builder, llvm::StringRef File) {
+ Builder.append("#include \"" +
+ llvm::Twine(NormalizeDashIncludePath(File)) + "\"");
}
-static void AddImplicitIncludeMacros(std::vector<char> &Buf,
- const std::string &File) {
- const char *Inc = "#__include_macros ";
- Buf.insert(Buf.end(), Inc, Inc+strlen(Inc));
- AddQuotedIncludePath(Buf, File);
- Buf.push_back('\n');
+static void AddImplicitIncludeMacros(MacroBuilder &Builder,
+ llvm::StringRef File) {
+ Builder.append("#__include_macros \"" +
+ llvm::Twine(NormalizeDashIncludePath(File)) + "\"");
// Marker token to stop the __include_macros fetch loop.
- const char *Marker = "##\n"; // ##?
- Buf.insert(Buf.end(), Marker, Marker+strlen(Marker));
+ Builder.append("##"); // ##?
}
/// AddImplicitIncludePTH - Add an implicit #include using the original file
/// used to generate a PTH cache.
-static void AddImplicitIncludePTH(std::vector<char> &Buf, Preprocessor &PP,
- const std::string& ImplicitIncludePTH) {
+static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP,
+ llvm::StringRef ImplicitIncludePTH) {
PTHManager *P = PP.getPTHManager();
assert(P && "No PTHManager.");
const char *OriginalFile = P->getOriginalSourceFile();
@@ -129,7 +90,7 @@ static void AddImplicitIncludePTH(std::vector<char> &Buf, Preprocessor &PP,
return;
}
- AddImplicitInclude(Buf, OriginalFile);
+ AddImplicitInclude(Builder, OriginalFile);
}
/// PickFP - This is used to pick a value based on the FP semantics of the
@@ -150,7 +111,7 @@ static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal,
return IEEEQuadVal;
}
-static void DefineFloatMacros(std::vector<char> &Buf, const char *Prefix,
+static void DefineFloatMacros(MacroBuilder &Builder, llvm::StringRef Prefix,
const llvm::fltSemantics *Sem) {
const char *DenormMin, *Epsilon, *Max, *Min;
DenormMin = PickFP(Sem, "1.40129846e-45F", "4.9406564584124654e-324",
@@ -162,7 +123,6 @@ static void DefineFloatMacros(std::vector<char> &Buf, const char *Prefix,
"1.08420217248550443401e-19L",
"4.94065645841246544176568792868221e-324L",
"1.92592994438723585305597794258492732e-34L");
- int HasInifinity = 1, HasQuietNaN = 1;
int MantissaDigits = PickFP(Sem, 24, 53, 64, 106, 113);
int Min10Exp = PickFP(Sem, -37, -307, -4931, -291, -4931);
int Max10Exp = PickFP(Sem, 38, 308, 4932, 308, 4932);
@@ -177,312 +137,281 @@ static void DefineFloatMacros(std::vector<char> &Buf, const char *Prefix,
"1.79769313486231580793728971405301e+308L",
"1.18973149535723176508575932662800702e+4932L");
- char MacroBuf[100];
- sprintf(MacroBuf, "__%s_DENORM_MIN__=%s", Prefix, DenormMin);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_DIG__=%d", Prefix, Digits);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_EPSILON__=%s", Prefix, Epsilon);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_HAS_INFINITY__=%d", Prefix, HasInifinity);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_HAS_QUIET_NAN__=%d", Prefix, HasQuietNaN);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_MANT_DIG__=%d", Prefix, MantissaDigits);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_MAX_10_EXP__=%d", Prefix, Max10Exp);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_MAX_EXP__=%d", Prefix, MaxExp);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_MAX__=%s", Prefix, Max);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_MIN_10_EXP__=(%d)", Prefix, Min10Exp);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_MIN_EXP__=(%d)", Prefix, MinExp);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_MIN__=%s", Prefix, Min);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_HAS_DENORM__=1", Prefix);
- DefineBuiltinMacro(Buf, MacroBuf);
+ llvm::Twine DefPrefix = "__" + Prefix + "_";
+
+ Builder.defineMacro(DefPrefix + "DENORM_MIN__", DenormMin);
+ Builder.defineMacro(DefPrefix + "HAS_DENORM__");
+ Builder.defineMacro(DefPrefix + "DIG__", llvm::Twine(Digits));
+ Builder.defineMacro(DefPrefix + "EPSILON__", llvm::Twine(Epsilon));
+ Builder.defineMacro(DefPrefix + "HAS_INFINITY__");
+ Builder.defineMacro(DefPrefix + "HAS_QUIET_NAN__");
+ Builder.defineMacro(DefPrefix + "MANT_DIG__", llvm::Twine(MantissaDigits));
+
+ Builder.defineMacro(DefPrefix + "MAX_10_EXP__", llvm::Twine(Max10Exp));
+ Builder.defineMacro(DefPrefix + "MAX_EXP__", llvm::Twine(MaxExp));
+ Builder.defineMacro(DefPrefix + "MAX__", llvm::Twine(Max));
+
+ Builder.defineMacro(DefPrefix + "MIN_10_EXP__","("+llvm::Twine(Min10Exp)+")");
+ Builder.defineMacro(DefPrefix + "MIN_EXP__", "("+llvm::Twine(MinExp)+")");
+ Builder.defineMacro(DefPrefix + "MIN__", llvm::Twine(Min));
}
/// DefineTypeSize - Emit a macro to the predefines buffer that declares a macro
/// named MacroName with the max value for a type with width 'TypeWidth' a
/// signedness of 'isSigned' and with a value suffix of 'ValSuffix' (e.g. LL).
-static void DefineTypeSize(const char *MacroName, unsigned TypeWidth,
- const char *ValSuffix, bool isSigned,
- std::vector<char> &Buf) {
- char MacroBuf[60];
+static void DefineTypeSize(llvm::StringRef MacroName, unsigned TypeWidth,
+ llvm::StringRef ValSuffix, bool isSigned,
+ MacroBuilder& Builder) {
long long MaxVal;
if (isSigned)
MaxVal = (1LL << (TypeWidth - 1)) - 1;
else
MaxVal = ~0LL >> (64-TypeWidth);
- // FIXME: Switch to using raw_ostream and avoid utostr().
- sprintf(MacroBuf, "%s=%s%s", MacroName, llvm::utostr(MaxVal).c_str(),
- ValSuffix);
- DefineBuiltinMacro(Buf, MacroBuf);
+ Builder.defineMacro(MacroName, llvm::Twine(MaxVal) + ValSuffix);
}
/// DefineTypeSize - An overloaded helper that uses TargetInfo to determine
/// the width, suffix, and signedness of the given type
-static void DefineTypeSize(const char *MacroName, TargetInfo::IntType Ty,
- const TargetInfo &TI, std::vector<char> &Buf) {
+static void DefineTypeSize(llvm::StringRef MacroName, TargetInfo::IntType Ty,
+ const TargetInfo &TI, MacroBuilder &Builder) {
DefineTypeSize(MacroName, TI.getTypeWidth(Ty), TI.getTypeConstantSuffix(Ty),
- TI.isTypeSigned(Ty), Buf);
+ TI.isTypeSigned(Ty), Builder);
}
-static void DefineType(const char *MacroName, TargetInfo::IntType Ty,
- std::vector<char> &Buf) {
- char MacroBuf[60];
- sprintf(MacroBuf, "%s=%s", MacroName, TargetInfo::getTypeName(Ty));
- DefineBuiltinMacro(Buf, MacroBuf);
+static void DefineType(const llvm::Twine &MacroName, TargetInfo::IntType Ty,
+ MacroBuilder &Builder) {
+ Builder.defineMacro(MacroName, TargetInfo::getTypeName(Ty));
}
-static void DefineTypeWidth(const char *MacroName, TargetInfo::IntType Ty,
- const TargetInfo &TI, std::vector<char> &Buf) {
- char MacroBuf[60];
- sprintf(MacroBuf, "%s=%d", MacroName, TI.getTypeWidth(Ty));
- DefineBuiltinMacro(Buf, MacroBuf);
+static void DefineTypeWidth(llvm::StringRef MacroName, TargetInfo::IntType Ty,
+ const TargetInfo &TI, MacroBuilder &Builder) {
+ Builder.defineMacro(MacroName, llvm::Twine(TI.getTypeWidth(Ty)));
}
static void DefineExactWidthIntType(TargetInfo::IntType Ty,
- const TargetInfo &TI, std::vector<char> &Buf) {
- char MacroBuf[60];
+ const TargetInfo &TI, MacroBuilder &Builder) {
int TypeWidth = TI.getTypeWidth(Ty);
- sprintf(MacroBuf, "__INT%d_TYPE__", TypeWidth);
- DefineType(MacroBuf, Ty, Buf);
+ DefineType("__INT" + llvm::Twine(TypeWidth) + "_TYPE__", Ty, Builder);
-
- const char *ConstSuffix = TargetInfo::getTypeConstantSuffix(Ty);
- if (strlen(ConstSuffix) > 0) {
- sprintf(MacroBuf, "__INT%d_C_SUFFIX__=%s", TypeWidth, ConstSuffix);
- DefineBuiltinMacro(Buf, MacroBuf);
- }
+ llvm::StringRef ConstSuffix(TargetInfo::getTypeConstantSuffix(Ty));
+ if (!ConstSuffix.empty())
+ Builder.defineMacro("__INT" + llvm::Twine(TypeWidth) + "_C_SUFFIX__",
+ ConstSuffix);
}
static void InitializePredefinedMacros(const TargetInfo &TI,
const LangOptions &LangOpts,
- std::vector<char> &Buf) {
- char MacroBuf[60];
+ const FrontendOptions &FEOpts,
+ MacroBuilder &Builder) {
// Compiler version introspection macros.
- DefineBuiltinMacro(Buf, "__llvm__=1"); // LLVM Backend
- DefineBuiltinMacro(Buf, "__clang__=1"); // Clang Frontend
+ Builder.defineMacro("__llvm__"); // LLVM Backend
+ Builder.defineMacro("__clang__"); // Clang Frontend
// Currently claim to be compatible with GCC 4.2.1-5621.
- DefineBuiltinMacro(Buf, "__GNUC_MINOR__=2");
- DefineBuiltinMacro(Buf, "__GNUC_PATCHLEVEL__=1");
- DefineBuiltinMacro(Buf, "__GNUC__=4");
- DefineBuiltinMacro(Buf, "__GXX_ABI_VERSION=1002");
- DefineBuiltinMacro(Buf, "__VERSION__=\"4.2.1 Compatible Clang Compiler\"");
-
+ Builder.defineMacro("__GNUC_MINOR__", "2");
+ Builder.defineMacro("__GNUC_PATCHLEVEL__", "1");
+ Builder.defineMacro("__GNUC__", "4");
+ Builder.defineMacro("__GXX_ABI_VERSION", "1002");
+ Builder.defineMacro("__VERSION__", "\"4.2.1 Compatible Clang Compiler\"");
// Initialize language-specific preprocessor defines.
// These should all be defined in the preprocessor according to the
// current language configuration.
if (!LangOpts.Microsoft)
- DefineBuiltinMacro(Buf, "__STDC__=1");
+ Builder.defineMacro("__STDC__");
if (LangOpts.AsmPreprocessor)
- DefineBuiltinMacro(Buf, "__ASSEMBLER__=1");
+ Builder.defineMacro("__ASSEMBLER__");
if (!LangOpts.CPlusPlus) {
if (LangOpts.C99)
- DefineBuiltinMacro(Buf, "__STDC_VERSION__=199901L");
+ Builder.defineMacro("__STDC_VERSION__", "199901L");
else if (!LangOpts.GNUMode && LangOpts.Digraphs)
- DefineBuiltinMacro(Buf, "__STDC_VERSION__=199409L");
+ Builder.defineMacro("__STDC_VERSION__", "199409L");
}
// Standard conforming mode?
if (!LangOpts.GNUMode)
- DefineBuiltinMacro(Buf, "__STRICT_ANSI__=1");
+ Builder.defineMacro("__STRICT_ANSI__");
if (LangOpts.CPlusPlus0x)
- DefineBuiltinMacro(Buf, "__GXX_EXPERIMENTAL_CXX0X__");
+ Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__");
if (LangOpts.Freestanding)
- DefineBuiltinMacro(Buf, "__STDC_HOSTED__=0");
+ Builder.defineMacro("__STDC_HOSTED__", "0");
else
- DefineBuiltinMacro(Buf, "__STDC_HOSTED__=1");
+ Builder.defineMacro("__STDC_HOSTED__");
if (LangOpts.ObjC1) {
- DefineBuiltinMacro(Buf, "__OBJC__=1");
+ Builder.defineMacro("__OBJC__");
if (LangOpts.ObjCNonFragileABI) {
- DefineBuiltinMacro(Buf, "__OBJC2__=1");
- DefineBuiltinMacro(Buf, "OBJC_ZEROCOST_EXCEPTIONS=1");
+ Builder.defineMacro("__OBJC2__");
+ Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS");
}
if (LangOpts.getGCMode() != LangOptions::NonGC)
- DefineBuiltinMacro(Buf, "__OBJC_GC__=1");
+ Builder.defineMacro("__OBJC_GC__");
if (LangOpts.NeXTRuntime)
- DefineBuiltinMacro(Buf, "__NEXT_RUNTIME__=1");
+ Builder.defineMacro("__NEXT_RUNTIME__");
}
// darwin_constant_cfstrings controls this. This is also dependent
// on other things like the runtime I believe. This is set even for C code.
- DefineBuiltinMacro(Buf, "__CONSTANT_CFSTRINGS__=1");
+ Builder.defineMacro("__CONSTANT_CFSTRINGS__");
if (LangOpts.ObjC2)
- DefineBuiltinMacro(Buf, "OBJC_NEW_PROPERTIES");
+ Builder.defineMacro("OBJC_NEW_PROPERTIES");
if (LangOpts.PascalStrings)
- DefineBuiltinMacro(Buf, "__PASCAL_STRINGS__");
+ Builder.defineMacro("__PASCAL_STRINGS__");
if (LangOpts.Blocks) {
- DefineBuiltinMacro(Buf, "__block=__attribute__((__blocks__(byref)))");
- DefineBuiltinMacro(Buf, "__BLOCKS__=1");
+ Builder.defineMacro("__block", "__attribute__((__blocks__(byref)))");
+ Builder.defineMacro("__BLOCKS__");
}
if (LangOpts.Exceptions)
- DefineBuiltinMacro(Buf, "__EXCEPTIONS=1");
+ Builder.defineMacro("__EXCEPTIONS");
if (LangOpts.CPlusPlus) {
- DefineBuiltinMacro(Buf, "__DEPRECATED=1");
- DefineBuiltinMacro(Buf, "__GNUG__=4");
- DefineBuiltinMacro(Buf, "__GXX_WEAK__=1");
+ Builder.defineMacro("__DEPRECATED");
+ Builder.defineMacro("__GNUG__", "4");
+ Builder.defineMacro("__GXX_WEAK__");
if (LangOpts.GNUMode)
- DefineBuiltinMacro(Buf, "__cplusplus=1");
+ Builder.defineMacro("__cplusplus");
else
// C++ [cpp.predefined]p1:
// The name_ _cplusplusis defined to the value199711Lwhen compiling a
// C++ translation unit.
- DefineBuiltinMacro(Buf, "__cplusplus=199711L");
- DefineBuiltinMacro(Buf, "__private_extern__=extern");
+ Builder.defineMacro("__cplusplus", "199711L");
+ Builder.defineMacro("__private_extern__", "extern");
// Ugly hack to work with GNU libstdc++.
- DefineBuiltinMacro(Buf, "_GNU_SOURCE=1");
+ Builder.defineMacro("_GNU_SOURCE");
}
if (LangOpts.Microsoft) {
// Filter out some microsoft extensions when trying to parse in ms-compat
// mode.
- DefineBuiltinMacro(Buf, "__int8=__INT8_TYPE__");
- DefineBuiltinMacro(Buf, "__int16=__INT16_TYPE__");
- DefineBuiltinMacro(Buf, "__int32=__INT32_TYPE__");
- DefineBuiltinMacro(Buf, "__int64=__INT64_TYPE__");
+ Builder.defineMacro("__int8", "__INT8_TYPE__");
+ Builder.defineMacro("__int16", "__INT16_TYPE__");
+ Builder.defineMacro("__int32", "__INT32_TYPE__");
+ Builder.defineMacro("__int64", "__INT64_TYPE__");
// Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however
// VC++ appears to only like __FUNCTION__.
- DefineBuiltinMacro(Buf, "__PRETTY_FUNCTION__=__FUNCTION__");
+ Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__");
// Work around some issues with Visual C++ headerws.
if (LangOpts.CPlusPlus) {
// Since we define wchar_t in C++ mode.
- DefineBuiltinMacro(Buf, "_WCHAR_T_DEFINED=1");
- DefineBuiltinMacro(Buf, "_NATIVE_WCHAR_T_DEFINED=1");
+ Builder.defineMacro("_WCHAR_T_DEFINED");
+ Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED");
// FIXME: This should be temporary until we have a __pragma
// solution, to avoid some errors flagged in VC++ headers.
- DefineBuiltinMacro(Buf, "_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES=0");
+ Builder.defineMacro("_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES", "0");
}
}
if (LangOpts.Optimize)
- DefineBuiltinMacro(Buf, "__OPTIMIZE__=1");
+ Builder.defineMacro("__OPTIMIZE__");
if (LangOpts.OptimizeSize)
- DefineBuiltinMacro(Buf, "__OPTIMIZE_SIZE__=1");
+ Builder.defineMacro("__OPTIMIZE_SIZE__");
// Initialize target-specific preprocessor defines.
// Define type sizing macros based on the target properties.
assert(TI.getCharWidth() == 8 && "Only support 8-bit char so far");
- DefineBuiltinMacro(Buf, "__CHAR_BIT__=8");
-
- DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Buf);
- DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Buf);
- DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Buf);
- DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Buf);
- DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Buf);
- DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Buf);
- DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Buf);
-
- DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Buf);
- DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Buf);
- DefineTypeWidth("__INTMAX_WIDTH__", TI.getIntMaxType(), TI, Buf);
- DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Buf);
- DefineTypeWidth("__PTRDIFF_WIDTH__", TI.getPtrDiffType(0), TI, Buf);
- DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Buf);
- DefineTypeWidth("__INTPTR_WIDTH__", TI.getIntPtrType(), TI, Buf);
- DefineType("__SIZE_TYPE__", TI.getSizeType(), Buf);
- DefineTypeWidth("__SIZE_WIDTH__", TI.getSizeType(), TI, Buf);
- DefineType("__WCHAR_TYPE__", TI.getWCharType(), Buf);
- DefineTypeWidth("__WCHAR_WIDTH__", TI.getWCharType(), TI, Buf);
- DefineType("__WINT_TYPE__", TI.getWIntType(), Buf);
- DefineTypeWidth("__WINT_WIDTH__", TI.getWIntType(), TI, Buf);
- DefineTypeWidth("__SIG_ATOMIC_WIDTH__", TI.getSigAtomicType(), TI, Buf);
-
- DefineFloatMacros(Buf, "FLT", &TI.getFloatFormat());
- DefineFloatMacros(Buf, "DBL", &TI.getDoubleFormat());
- DefineFloatMacros(Buf, "LDBL", &TI.getLongDoubleFormat());
+ Builder.defineMacro("__CHAR_BIT__", "8");
+
+ DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Builder);
+ DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Builder);
+ DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Builder);
+ DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Builder);
+ DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Builder);
+ DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Builder);
+ DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Builder);
+
+ DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Builder);
+ DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Builder);
+ DefineTypeWidth("__INTMAX_WIDTH__", TI.getIntMaxType(), TI, Builder);
+ DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Builder);
+ DefineTypeWidth("__PTRDIFF_WIDTH__", TI.getPtrDiffType(0), TI, Builder);
+ DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Builder);
+ DefineTypeWidth("__INTPTR_WIDTH__", TI.getIntPtrType(), TI, Builder);
+ DefineType("__SIZE_TYPE__", TI.getSizeType(), Builder);
+ DefineTypeWidth("__SIZE_WIDTH__", TI.getSizeType(), TI, Builder);
+ DefineType("__WCHAR_TYPE__", TI.getWCharType(), Builder);
+ DefineTypeWidth("__WCHAR_WIDTH__", TI.getWCharType(), TI, Builder);
+ DefineType("__WINT_TYPE__", TI.getWIntType(), Builder);
+ DefineTypeWidth("__WINT_WIDTH__", TI.getWIntType(), TI, Builder);
+ DefineTypeWidth("__SIG_ATOMIC_WIDTH__", TI.getSigAtomicType(), TI, Builder);
+
+ DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat());
+ DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat());
+ DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat());
// Define a __POINTER_WIDTH__ macro for stdint.h.
- sprintf(MacroBuf, "__POINTER_WIDTH__=%d", (int)TI.getPointerWidth(0));
- DefineBuiltinMacro(Buf, MacroBuf);
+ Builder.defineMacro("__POINTER_WIDTH__",
+ llvm::Twine((int)TI.getPointerWidth(0)));
if (!LangOpts.CharIsSigned)
- DefineBuiltinMacro(Buf, "__CHAR_UNSIGNED__");
+ Builder.defineMacro("__CHAR_UNSIGNED__");
// Define exact-width integer types for stdint.h
- sprintf(MacroBuf, "__INT%d_TYPE__=char", TI.getCharWidth());
- DefineBuiltinMacro(Buf, MacroBuf);
+ Builder.defineMacro("__INT" + llvm::Twine(TI.getCharWidth()) + "_TYPE__",
+ "char");
if (TI.getShortWidth() > TI.getCharWidth())
- DefineExactWidthIntType(TargetInfo::SignedShort, TI, Buf);
-
+ DefineExactWidthIntType(TargetInfo::SignedShort, TI, Builder);
+
if (TI.getIntWidth() > TI.getShortWidth())
- DefineExactWidthIntType(TargetInfo::SignedInt, TI, Buf);
-
+ DefineExactWidthIntType(TargetInfo::SignedInt, TI, Builder);
+
if (TI.getLongWidth() > TI.getIntWidth())
- DefineExactWidthIntType(TargetInfo::SignedLong, TI, Buf);
-
+ DefineExactWidthIntType(TargetInfo::SignedLong, TI, Builder);
+
if (TI.getLongLongWidth() > TI.getLongWidth())
- DefineExactWidthIntType(TargetInfo::SignedLongLong, TI, Buf);
-
+ DefineExactWidthIntType(TargetInfo::SignedLongLong, TI, Builder);
+
// Add __builtin_va_list typedef.
- {
- const char *VAList = TI.getVAListDeclaration();
- Buf.insert(Buf.end(), VAList, VAList+strlen(VAList));
- Buf.push_back('\n');
- }
+ Builder.append(TI.getVAListDeclaration());
- if (const char *Prefix = TI.getUserLabelPrefix()) {
- sprintf(MacroBuf, "__USER_LABEL_PREFIX__=%s", Prefix);
- DefineBuiltinMacro(Buf, MacroBuf);
- }
+ if (const char *Prefix = TI.getUserLabelPrefix())
+ Builder.defineMacro("__USER_LABEL_PREFIX__", Prefix);
// Build configuration options. FIXME: these should be controlled by
// command line options or something.
- DefineBuiltinMacro(Buf, "__FINITE_MATH_ONLY__=0");
+ Builder.defineMacro("__FINITE_MATH_ONLY__", "0");
if (LangOpts.GNUInline)
- DefineBuiltinMacro(Buf, "__GNUC_GNU_INLINE__=1");
+ Builder.defineMacro("__GNUC_GNU_INLINE__");
else
- DefineBuiltinMacro(Buf, "__GNUC_STDC_INLINE__=1");
+ Builder.defineMacro("__GNUC_STDC_INLINE__");
if (LangOpts.NoInline)
- DefineBuiltinMacro(Buf, "__NO_INLINE__=1");
+ Builder.defineMacro("__NO_INLINE__");
if (unsigned PICLevel = LangOpts.PICLevel) {
- sprintf(MacroBuf, "__PIC__=%d", PICLevel);
- DefineBuiltinMacro(Buf, MacroBuf);
-
- sprintf(MacroBuf, "__pic__=%d", PICLevel);
- DefineBuiltinMacro(Buf, MacroBuf);
+ Builder.defineMacro("__PIC__", llvm::Twine(PICLevel));
+ Builder.defineMacro("__pic__", llvm::Twine(PICLevel));
}
// Macros to control C99 numerics and <float.h>
- DefineBuiltinMacro(Buf, "__FLT_EVAL_METHOD__=0");
- DefineBuiltinMacro(Buf, "__FLT_RADIX__=2");
- sprintf(MacroBuf, "__DECIMAL_DIG__=%d",
- PickFP(&TI.getLongDoubleFormat(), -1/*FIXME*/, 17, 21, 33, 36));
- DefineBuiltinMacro(Buf, MacroBuf);
+ Builder.defineMacro("__FLT_EVAL_METHOD__", "0");
+ Builder.defineMacro("__FLT_RADIX__", "2");
+ int Dig = PickFP(&TI.getLongDoubleFormat(), -1/*FIXME*/, 17, 21, 33, 36);
+ Builder.defineMacro("__DECIMAL_DIG__", llvm::Twine(Dig));
if (LangOpts.getStackProtectorMode() == LangOptions::SSPOn)
- DefineBuiltinMacro(Buf, "__SSP__=1");
+ Builder.defineMacro("__SSP__");
else if (LangOpts.getStackProtectorMode() == LangOptions::SSPReq)
- DefineBuiltinMacro(Buf, "__SSP_ALL__=2");
+ Builder.defineMacro("__SSP_ALL__", "2");
+ if (FEOpts.ProgramAction == frontend::RewriteObjC)
+ Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
// Get other target #defines.
- TI.getTargetDefines(LangOpts, Buf);
+ TI.getTargetDefines(LangOpts, Builder);
}
// Initialize the remapping of files to alternative contents, e.g.,
@@ -536,58 +465,55 @@ static void InitializeFileRemapping(Diagnostic &Diags,
///
void clang::InitializePreprocessor(Preprocessor &PP,
const PreprocessorOptions &InitOpts,
- const HeaderSearchOptions &HSOpts) {
- std::vector<char> PredefineBuffer;
+ const HeaderSearchOptions &HSOpts,
+ const FrontendOptions &FEOpts) {
+ std::string PredefineBuffer;
+ PredefineBuffer.reserve(4080);
+ llvm::raw_string_ostream Predefines(PredefineBuffer);
+ MacroBuilder Builder(Predefines);
InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(),
PP.getFileManager(), InitOpts);
- const char *LineDirective = "# 1 \"<built-in>\" 3\n";
- PredefineBuffer.insert(PredefineBuffer.end(),
- LineDirective, LineDirective+strlen(LineDirective));
+ Builder.append("# 1 \"<built-in>\" 3");
// Install things like __POWERPC__, __GNUC__, etc into the macro table.
if (InitOpts.UsePredefines)
InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(),
- PredefineBuffer);
+ FEOpts, Builder);
// Add on the predefines from the driver. Wrap in a #line directive to report
// that they come from the command line.
- LineDirective = "# 1 \"<command line>\" 1\n";
- PredefineBuffer.insert(PredefineBuffer.end(),
- LineDirective, LineDirective+strlen(LineDirective));
+ Builder.append("# 1 \"<command line>\" 1");
// Process #define's and #undef's in the order they are given.
for (unsigned i = 0, e = InitOpts.Macros.size(); i != e; ++i) {
if (InitOpts.Macros[i].second) // isUndef
- UndefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str());
+ Builder.undefineMacro(InitOpts.Macros[i].first);
else
- DefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str(),
- &PP.getDiagnostics());
+ DefineBuiltinMacro(Builder, InitOpts.Macros[i].first,
+ PP.getDiagnostics());
}
// If -imacros are specified, include them now. These are processed before
// any -include directives.
for (unsigned i = 0, e = InitOpts.MacroIncludes.size(); i != e; ++i)
- AddImplicitIncludeMacros(PredefineBuffer, InitOpts.MacroIncludes[i]);
+ AddImplicitIncludeMacros(Builder, InitOpts.MacroIncludes[i]);
// Process -include directives.
for (unsigned i = 0, e = InitOpts.Includes.size(); i != e; ++i) {
const std::string &Path = InitOpts.Includes[i];
if (Path == InitOpts.ImplicitPTHInclude)
- AddImplicitIncludePTH(PredefineBuffer, PP, Path);
+ AddImplicitIncludePTH(Builder, PP, Path);
else
- AddImplicitInclude(PredefineBuffer, Path);
+ AddImplicitInclude(Builder, Path);
}
// Exit the command line and go back to <built-in> (2 is LC_LEAVE).
- LineDirective = "# 1 \"<built-in>\" 2\n";
- PredefineBuffer.insert(PredefineBuffer.end(),
- LineDirective, LineDirective+strlen(LineDirective));
+ Builder.append("# 1 \"<built-in>\" 2");
- // Null terminate PredefinedBuffer and add it.
- PredefineBuffer.push_back(0);
- PP.setPredefines(&PredefineBuffer[0]);
+ // Copy PredefinedBuffer into the Preprocessor.
+ PP.setPredefines(Predefines.str());
// Initialize the header search object.
ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), HSOpts,
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index d8fd791..07d5a78 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -1079,6 +1079,61 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
}
}
+void PCHReader::ReadDefinedMacros() {
+ // If there was no preprocessor block, do nothing.
+ if (!MacroCursor.getBitStreamReader())
+ return;
+
+ llvm::BitstreamCursor Cursor = MacroCursor;
+ if (Cursor.EnterSubBlock(pch::PREPROCESSOR_BLOCK_ID)) {
+ Error("malformed preprocessor block record in PCH file");
+ return;
+ }
+
+ RecordData Record;
+ while (true) {
+ unsigned Code = Cursor.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Cursor.ReadBlockEnd())
+ Error("error at end of preprocessor block in PCH file");
+ return;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Cursor.ReadSubBlockID();
+ if (Cursor.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Cursor.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ const char *BlobStart;
+ unsigned BlobLen;
+ Record.clear();
+ switch (Cursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case pch::PP_MACRO_OBJECT_LIKE:
+ case pch::PP_MACRO_FUNCTION_LIKE:
+ DecodeIdentifierInfo(Record[0]);
+ break;
+
+ case pch::PP_TOKEN:
+ // Ignore tokens.
+ break;
+ }
+ }
+}
+
/// \brief If we are loading a relocatable PCH file, and the filename is
/// not an absolute path, add the system root to the beginning of the file
/// name.
@@ -1140,6 +1195,10 @@ PCHReader::ReadPCHBlock() {
break;
case pch::PREPROCESSOR_BLOCK_ID:
+ MacroCursor = Stream;
+ if (PP)
+ PP->setExternalSource(this);
+
if (Stream.SkipBlock()) {
Error("malformed block record in PCH file");
return Failure;
@@ -1494,7 +1553,8 @@ void PCHReader::InitializeContext(ASTContext &Ctx) {
assert(PP && "Forgot to set Preprocessor ?");
PP->getIdentifierTable().setExternalIdentifierLookup(this);
PP->getHeaderSearchInfo().SetExternalLookup(this);
-
+ PP->setExternalSource(this);
+
// Load the translation unit declaration
ReadDeclRecord(DeclOffsets[0], 0);
@@ -2051,10 +2111,15 @@ void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
- TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setTypeofLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
- TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setTypeofLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(Record, Idx));
}
void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index 01e1a41..69343ed 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -208,7 +208,9 @@ void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
void PCHDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
VisitNamedDecl(CD);
- CD->setAtEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ SourceLocation A = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation B = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ CD->setAtEndRange(SourceRange(A, B));
}
void PCHDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
@@ -436,6 +438,9 @@ Attr *PCHReader::ReadAttributes() {
bool IsInherited = Record[Idx++];
switch (Kind) {
+ default:
+ assert(0 && "Unknown attribute!");
+ break;
STRING_ATTR(Alias);
UNSIGNED_ATTR(Aligned);
SIMPLE_ATTR(AlwaysInline);
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index ba82d26..138f1e1 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -304,6 +304,7 @@ unsigned PCHStmtReader::VisitAsmStmt(AsmStmt *S) {
S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
S->setVolatile(Record[Idx++]);
S->setSimple(Record[Idx++]);
+ S->setMSAsm(Record[Idx++]);
unsigned StackIdx
= StmtStack.size() - (NumOutputs*2 + NumInputs*2 + NumClobbers + 1);
@@ -615,7 +616,8 @@ unsigned PCHStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
}
}
}
- E->setDesignators(Designators.data(), Designators.size());
+ E->setDesignators(*Reader.getContext(),
+ Designators.data(), Designators.size());
return NumSubExprs;
}
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 2875f09..3f6841b 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -344,10 +344,15 @@ void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
- Writer.AddSourceLocation(TL.getNameLoc(), Record);
+ Writer.AddSourceLocation(TL.getTypeofLoc(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
}
void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
- Writer.AddSourceLocation(TL.getNameLoc(), Record);
+ Writer.AddSourceLocation(TL.getTypeofLoc(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
+ Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record);
}
void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
@@ -1148,7 +1153,6 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
// Loop over all the macro definitions that are live at the end of the file,
// emitting each to the PP section.
- // FIXME: Make sure that this sees macros defined in included PCH files.
for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
I != E; ++I) {
// FIXME: This emits macros in hash table order, we should do it in a stable
@@ -1160,7 +1164,6 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
if (MI->isBuiltinMacro())
continue;
- // FIXME: Remove this identifier reference?
AddIdentifierRef(I->first, Record);
MacroOffsets[I->first] = Stream.GetCurrentBitNo();
Record.push_back(MI->getDefinitionLoc().getRawEncoding());
@@ -1741,9 +1744,12 @@ void PCHWriter::WriteIdentifierTable(Preprocessor &PP) {
void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
RecordData Record;
for (; Attr; Attr = Attr->getNext()) {
- Record.push_back(Attr->getKind()); // FIXME: stable encoding
+ Record.push_back(Attr->getKind()); // FIXME: stable encoding, target attrs
Record.push_back(Attr->isInherited());
switch (Attr->getKind()) {
+ default:
+ assert(0 && "Does not support PCH writing for this attribute yet!");
+ break;
case Attr::Alias:
AddString(cast<AliasAttr>(Attr)->getAliasee(), Record);
break;
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index 049cdb0..2dbcc27 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -208,7 +208,9 @@ void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
void PCHDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
VisitNamedDecl(D);
- Writer.AddSourceLocation(D->getAtEndLoc(), Record);
+ SourceRange R = D->getAtEndRange();
+ Writer.AddSourceLocation(R.getBegin(), Record);
+ Writer.AddSourceLocation(R.getEnd(), Record);
// Abstract class (no need to define a stable pch::DECL code).
}
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index abf4eaa..4be9b81 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -277,6 +277,7 @@ void PCHStmtWriter::VisitAsmStmt(AsmStmt *S) {
Writer.AddSourceLocation(S->getRParenLoc(), Record);
Record.push_back(S->isVolatile());
Record.push_back(S->isSimple());
+ Record.push_back(S->isMSAsm());
Writer.WriteSubStmt(S->getAsmString());
// Outputs
diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp
index c5dc979..95afb90 100644
--- a/lib/Frontend/PrintParserCallbacks.cpp
+++ b/lib/Frontend/PrintParserCallbacks.cpp
@@ -394,7 +394,8 @@ namespace {
MultiExprArg Exprs,
ExprArg AsmString,
MultiExprArg Clobbers,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ bool MSAsm) {
Out << __FUNCTION__ << "\n";
return StmtEmpty();
}
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index c347472..fc9401d 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -25,6 +25,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/DenseSet.h"
using namespace clang;
using llvm::utostr;
@@ -75,7 +76,9 @@ namespace {
llvm::SmallVector<int, 8> ObjCBcLabelNo;
// Remember all the @protocol(<expr>) expressions.
llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ProtocolExprDecls;
-
+
+ llvm::DenseSet<uint64_t> CopyDestroyCache;
+
unsigned NumObjCStringLiterals;
FunctionDecl *MsgSendFunctionDecl;
@@ -111,6 +114,7 @@ namespace {
llvm::raw_ostream* OutFile;
bool SilenceRewriteMacroWarning;
+ bool objc_impl_method;
std::string Preamble;
@@ -122,6 +126,7 @@ namespace {
// Block related declarations.
llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls;
llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls;
+ llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo;
llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
@@ -138,6 +143,7 @@ namespace {
llvm::DenseMap<Stmt *, Stmt *> ReplacedNodes;
FunctionDecl *CurFunctionDef;
+ FunctionDecl *CurFunctionDeclToDeclareForBlock;
VarDecl *GlobalVarDecl;
bool DisableReplaceStmt;
@@ -247,12 +253,15 @@ namespace {
void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl);
void RewriteImplementationDecl(Decl *Dcl);
void RewriteObjCMethodDecl(ObjCMethodDecl *MDecl, std::string &ResultStr);
+ void RewriteByRefString(std::string &ResultStr, const std::string &Name,
+ ValueDecl *VD);
void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
void RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *Dcl);
void RewriteMethodDeclaration(ObjCMethodDecl *Method);
void RewriteProperty(ObjCPropertyDecl *prop);
void RewriteFunctionDecl(FunctionDecl *FD);
+ void RewriteBlockLiteralFunctionDecl(FunctionDecl *FD);
void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl);
void RewriteObjCQualifiedInterfaceTypes(Expr *E);
bool needToScanForQualifiers(QualType T);
@@ -347,7 +356,8 @@ namespace {
void RewriteBlockCall(CallExpr *Exp);
void RewriteBlockPointerDecl(NamedDecl *VD);
void RewriteByRefVar(VarDecl *VD);
- Stmt *RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD);
+ std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag);
+ Stmt *RewriteBlockDeclRefExpr(Expr *VD);
void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
@@ -362,7 +372,7 @@ namespace {
unsigned hasCopy);
Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp);
void SynthesizeBlockLiterals(SourceLocation FunLocStart,
- const char *FunName);
+ const char *FunName);
void RewriteRecordBody(RecordDecl *RD);
void CollectBlockDeclRefInfo(BlockExpr *Exp);
@@ -483,6 +493,7 @@ void RewriteObjC::Initialize(ASTContext &context) {
NSStringRecord = 0;
CurMethodDef = 0;
CurFunctionDef = 0;
+ CurFunctionDeclToDeclareForBlock = 0;
GlobalVarDecl = 0;
SuperStructDecl = 0;
ProtocolTypeDecl = 0;
@@ -493,6 +504,7 @@ void RewriteObjC::Initialize(ASTContext &context) {
PropParentMap = 0;
CurrentBody = 0;
DisableReplaceStmt = false;
+ objc_impl_method = false;
// Get the ID and start/end of the main file.
MainFileID = SM->getMainFileID();
@@ -588,8 +600,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 \"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 _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 void *_NSConcreteGlobalBlock[32];\n";
Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n";
Preamble += "#endif\n";
@@ -599,8 +611,10 @@ void RewriteObjC::Initialize(ASTContext &context) {
Preamble += "#undef __OBJC_RW_STATICIMPORT\n";
Preamble += "#define __attribute__(X)\n";
}
- else
+ else {
Preamble += "#define __block\n";
+ Preamble += "#define __weak\n";
+ }
}
@@ -779,9 +793,17 @@ void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) {
// as the class. As a convenience, we include the original declaration
// as a comment.
std::string typedefString;
- typedefString += "// ";
- typedefString.append(startBuf, semiPtr-startBuf+1);
- typedefString += "\n";
+ typedefString += "// @class ";
+ for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end();
+ I != E; ++I) {
+ ObjCInterfaceDecl *ForwardDecl = I->getInterface();
+ typedefString += ForwardDecl->getNameAsString();
+ if (I+1 != E)
+ typedefString += ", ";
+ else
+ typedefString += ";\n";
+ }
+
for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end();
I != E; ++I) {
ObjCInterfaceDecl *ForwardDecl = I->getInterface();
@@ -838,7 +860,7 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
RewriteMethodDeclaration(*I);
// Lastly, comment out the @end.
- ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3);
+ ReplaceText(CatDecl->getAtEndRange().getBegin(), 0, "// ", 3);
}
void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
@@ -859,7 +881,7 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
RewriteMethodDeclaration(*I);
// Lastly, comment out the @end.
- SourceLocation LocEnd = PDecl->getAtEndLoc();
+ SourceLocation LocEnd = PDecl->getAtEndRange().getBegin();
ReplaceText(LocEnd, 0, "// ", 3);
// Must comment out @optional/@required
@@ -1096,7 +1118,7 @@ void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
RewriteMethodDeclaration(*I);
// Lastly, comment out the @end.
- ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3);
+ ReplaceText(ClassDecl->getAtEndRange().getBegin(), 0, "// ", 3);
}
Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
@@ -1177,10 +1199,12 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) {
Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
SourceLocation OrigStart) {
ObjCIvarDecl *D = IV->getDecl();
+ const Expr *BaseExpr = IV->getBase();
if (CurMethodDef) {
- if (const PointerType *pType = IV->getBase()->getType()->getAs<PointerType>()) {
+ if (BaseExpr->getType()->isObjCObjectPointerType() &&
+ isa<DeclRefExpr>(BaseExpr)) {
ObjCInterfaceType *iFaceDecl =
- dyn_cast<ObjCInterfaceType>(pType->getPointeeType());
+ dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
// lookup which class implements the instance variable.
ObjCInterfaceDecl *clsDeclared = 0;
iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
@@ -1226,8 +1250,9 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
// Explicit ivar refs need to have a cast inserted.
// FIXME: consider sharing some of this code with the code above.
- if (const PointerType *pType = IV->getBase()->getType()->getAs<PointerType>()) {
- ObjCInterfaceType *iFaceDecl = dyn_cast<ObjCInterfaceType>(pType->getPointeeType());
+ if (BaseExpr->getType()->isObjCObjectPointerType()) {
+ ObjCInterfaceType *iFaceDecl =
+ dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
// lookup which class implements the instance variable.
ObjCInterfaceDecl *clsDeclared = 0;
iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
@@ -1474,14 +1499,18 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
SynthCountByEnumWithState(buf);
buf += ");\n\t";
buf += elementName;
- buf += " = ((id)0);\n\t";
+ buf += " = ((";
+ buf += elementTypeAsString;
+ buf += ")0);\n\t";
buf += "__break_label_";
buf += utostr(ObjCBcLabelNo.back());
buf += ": ;\n\t";
buf += "}\n\t";
buf += "else\n\t\t";
buf += elementName;
- buf += " = ((id)0);\n";
+ buf += " = ((";
+ buf += elementTypeAsString;
+ buf += ")0);\n\t";
buf += "}\n";
// Insert all these *after* the statement body.
@@ -1735,10 +1764,10 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
buf += "1) { ";
ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size());
sawIdTypedCatch = true;
- } else if (const PointerType *pType = t->getAs<PointerType>()) {
- ObjCInterfaceType *cls; // Should be a pointer to a class.
-
- cls = dyn_cast<ObjCInterfaceType>(pType->getPointeeType().getTypePtr());
+ } else if (t->isObjCObjectPointerType()) {
+ QualType InterfaceTy = t->getPointeeType();
+ const ObjCInterfaceType *cls = // Should be a pointer to a class.
+ InterfaceTy->getAs<ObjCInterfaceType>();
if (cls) {
buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";
buf += cls->getDecl()->getNameAsString();
@@ -2092,6 +2121,30 @@ void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) {
RewriteObjCQualifiedInterfaceTypes(FD);
}
+void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) {
+ SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
+ const FunctionType *funcType = FD->getType()->getAs<FunctionType>();
+ const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(funcType);
+ if (!proto)
+ return;
+ QualType Type = proto->getResultType();
+ std::string FdStr = Type.getAsString();
+ FdStr += " ";
+ FdStr += FD->getNameAsCString();
+ FdStr += "(";
+ unsigned numArgs = proto->getNumArgs();
+ for (unsigned i = 0; i < numArgs; i++) {
+ QualType ArgType = proto->getArgType(i);
+ FdStr += ArgType.getAsString();
+
+ if (i+1 < numArgs)
+ FdStr += ", ";
+ }
+ FdStr += ");\n";
+ InsertText(FunLocStart, FdStr.c_str(), FdStr.size());
+ CurFunctionDeclToDeclareForBlock = 0;
+}
+
// SynthSuperContructorFunctionDecl - id objc_super(id obj, id super);
void RewriteObjC::SynthSuperContructorFunctionDecl() {
if (SuperContructorFunctionDecl)
@@ -2946,7 +2999,6 @@ void RewriteObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
std::string &Result) {
if (MethodBegin == MethodEnd) return;
- static bool objc_impl_method = false;
if (!objc_impl_method) {
/* struct _objc_method {
SEL _cmd;
@@ -3617,7 +3669,7 @@ void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) {
int CatDefCount = CategoryImplementation.size();
// This is needed for determining instance variable offsets.
- Result += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)\n";
+ Result += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long) &((TYPE *)0)->MEMBER)\n";
// For each implemented class, write out all its meta data.
for (int i = 0; i < ClsDefCount; i++)
RewriteObjCClassMetaData(ClassImplementation[i], Result);
@@ -3711,6 +3763,15 @@ void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) {
}
}
+void RewriteObjC::RewriteByRefString(std::string &ResultStr,
+ const std::string &Name,
+ ValueDecl *VD) {
+ assert(BlockByRefDeclNo.count(VD) &&
+ "RewriteByRefString: ByRef decl missing");
+ ResultStr += "struct __Block_byref_" + Name +
+ "_" + utostr(BlockByRefDeclNo[VD]) ;
+}
+
std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
const char *funcName,
std::string Tag) {
@@ -3756,7 +3817,9 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
E = BlockByRefDecls.end(); I != E; ++I) {
S += " ";
std::string Name = (*I)->getNameAsString();
- std::string TypeString = "struct __Block_byref_" + Name + " *";
+ std::string TypeString;
+ RewriteByRefString(TypeString, Name, (*I));
+ TypeString += " *";
Name = TypeString + Name;
S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
}
@@ -3891,7 +3954,8 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
S += "struct __block_impl *";
Constructor += ", void *" + ArgName;
} else {
- std::string TypeString = "struct __Block_byref_" + FieldName;
+ std::string TypeString;
+ RewriteByRefString(TypeString, FieldName, (*I));
TypeString += " *";
FieldName = TypeString + FieldName;
ArgName = TypeString + ArgName;
@@ -3977,7 +4041,10 @@ std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag,
}
void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
- const char *FunName) {
+ const char *FunName) {
+ // Insert declaration for the function in which block literal is used.
+ if (CurFunctionDeclToDeclareForBlock)
+ RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock);
// Insert closures that were part of the function.
for (unsigned i = 0; i < Blocks.size(); i++) {
@@ -4192,29 +4259,40 @@ void RewriteObjC::RewriteBlockCall(CallExpr *Exp) {
// i = 77;
// };
//}
-Stmt *RewriteObjC::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) {
+Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
// Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR
- // for each BDRE where BYREFVAR is name of the variable.
+ // for each DeclRefExp where BYREFVAR is name of the variable.
+ ValueDecl *VD;
+ bool isArrow = true;
+ if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(DeclRefExp))
+ VD = BDRE->getDecl();
+ else {
+ VD = cast<DeclRefExpr>(DeclRefExp)->getDecl();
+ isArrow = false;
+ }
+
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(),
+ MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
+ FD, SourceLocation(),
FD->getType());
- const char *Name = BDRE->getDecl()->getNameAsCString();
+
+ const char *Name = VD->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());
+ DeclRefExp->getType());
// Need parens to enforce precedence.
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
ME);
- ReplaceStmt(BDRE, PE);
+ ReplaceStmt(DeclRefExp, PE);
return PE;
}
@@ -4369,6 +4447,64 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
return;
}
+
+/// SynthesizeByrefCopyDestroyHelper - This routine synthesizes:
+/// void __Block_byref_id_object_copy(struct Block_byref_id_object *dst,
+/// struct Block_byref_id_object *src) {
+/// _Block_object_assign (&_dest->object, _src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT
+/// [|BLOCK_FIELD_IS_WEAK]) // object
+/// _Block_object_assign(&_dest->object, _src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK
+/// [|BLOCK_FIELD_IS_WEAK]) // block
+/// }
+/// And:
+/// void __Block_byref_id_object_dispose(struct Block_byref_id_object *_src) {
+/// _Block_object_dispose(_src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT
+/// [|BLOCK_FIELD_IS_WEAK]) // object
+/// _Block_object_dispose(_src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK
+/// [|BLOCK_FIELD_IS_WEAK]) // block
+/// }
+
+std::string RewriteObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD,
+ int flag) {
+ std::string S;
+ if (CopyDestroyCache.count(flag))
+ return S;
+ CopyDestroyCache.insert(flag);
+ S = "static void __Block_byref_id_object_copy_";
+ S += utostr(flag);
+ S += "(void *dst, void *src) {\n";
+
+ // offset into the object pointer is computed as:
+ // void * + void* + int + int + void* + void *
+ unsigned IntSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
+ unsigned VoidPtrSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->VoidPtrTy));
+
+ unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/8;
+ S += " _Block_object_assign((char*)dst + ";
+ S += utostr(offset);
+ S += ", *(void * *) ((char*)src + ";
+ S += utostr(offset);
+ S += "), ";
+ S += utostr(flag);
+ S += ");\n}\n";
+
+ S += "static void __Block_byref_id_object_dispose_";
+ S += utostr(flag);
+ S += "(void *src) {\n";
+ S += " _Block_object_dispose(*(void * *) ((char*)src + ";
+ S += utostr(offset);
+ S += "), ";
+ S += utostr(flag);
+ S += ");\n}\n";
+ return S;
+}
+
/// RewriteByRefVar - For each __block typex ND variable this routine transforms
/// the declaration into:
/// struct __Block_byref_ND {
@@ -4376,8 +4512,8 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
/// 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
+/// void *__Block_byref_id_object_copy; // If variable is __block ObjC object
+/// void *__Block_byref_id_object_dispose; // If variable is __block ObjC object
/// typex ND;
/// };
///
@@ -4388,54 +4524,110 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
///
///
void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
+ // Insert declaration for the function in which block literal is
+ // used.
+ if (CurFunctionDeclToDeclareForBlock)
+ RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock);
+ int flag = 0;
+ int isa = 0;
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;
+ std::string ByrefType;
+ RewriteByRefString(ByrefType, Name, ND);
ByrefType += " {\n";
ByrefType += " void *__isa;\n";
- ByrefType += " struct __Block_byref_" + Name + " *__forwarding;\n";
+ RewriteByRefString(ByrefType, Name, ND);
+ ByrefType += " *__forwarding;\n";
ByrefType += " int __flags;\n";
ByrefType += " int __size;\n";
- // FIXME. Add void *__ByrefKeepFuncPtr; void *__ByrefDestroyFuncPtr;
- // if needed.
- ND->getType().getAsStringInternal(Name, Context->PrintingPolicy);
+ // Add void *__Block_byref_id_object_copy;
+ // void *__Block_byref_id_object_dispose; if needed.
+ QualType Ty = ND->getType();
+ bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty);
+ if (HasCopyAndDispose) {
+ ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n";
+ ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n";
+ }
+
+ Ty.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());
+ if (Ty.isObjCGCWeak()) {
+ flag |= BLOCK_FIELD_IS_WEAK;
+ isa = 1;
+ }
+
+ if (HasCopyAndDispose) {
+ flag = BLOCK_BYREF_CALLER;
+ QualType Ty = ND->getType();
+ // FIXME. Handle __weak variable (BLOCK_FIELD_IS_WEAK) as well.
+ if (Ty->isBlockPointerType())
+ flag |= BLOCK_FIELD_IS_BLOCK;
+ else
+ flag |= BLOCK_FIELD_IS_OBJECT;
+ std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag);
+ if (!HF.empty())
+ InsertText(FunLocStart, HF.c_str(), HF.size());
+ }
// struct __Block_byref_ND ND =
// {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND),
// initializer-if-any};
bool hasInit = (ND->getInit() != 0);
+ unsigned flags = 0;
+ if (HasCopyAndDispose)
+ flags |= BLOCK_HAS_COPY_DISPOSE;
Name = ND->getNameAsString();
- ByrefType = "struct __Block_byref_" + Name;
+ ByrefType.clear();
+ RewriteByRefString(ByrefType, Name, ND);
if (!hasInit) {
- ByrefType += " " + Name + " = ";
- ByrefType += "{0, &" + Name + ", ";
- // FIXME. Compute the flag.
- ByrefType += "0, ";
- ByrefType += "sizeof(struct __Block_byref_" + Name + ")";
+ ByrefType += " " + Name + " = {(void*)";
+ ByrefType += utostr(isa);
+ ByrefType += ", &" + Name + ", ";
+ ByrefType += utostr(flags);
+ ByrefType += ", ";
+ ByrefType += "sizeof(";
+ RewriteByRefString(ByrefType, Name, ND);
+ ByrefType += ")";
+ if (HasCopyAndDispose) {
+ ByrefType += ", __Block_byref_id_object_copy_";
+ ByrefType += utostr(flag);
+ ByrefType += ", __Block_byref_id_object_dispose_";
+ ByrefType += utostr(flag);
+ }
ByrefType += "};\n";
ReplaceText(DeclLoc, endBuf-startBuf+Name.size(),
ByrefType.c_str(), ByrefType.size());
}
else {
SourceLocation startLoc = ND->getInit()->getLocStart();
+ startLoc = SM->getInstantiationLoc(startLoc);
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 + "), ";
+ ByrefType = " = {(void*)";
+ ByrefType += utostr(isa);
+ ByrefType += ", &" + Name + ", ";
+ ByrefType += utostr(flags);
+ ByrefType += ", ";
+ ByrefType += "sizeof(";
+ RewriteByRefString(ByrefType, Name, ND);
+ ByrefType += "), ";
+ if (HasCopyAndDispose) {
+ ByrefType += "__Block_byref_id_object_copy_";
+ ByrefType += utostr(flag);
+ ByrefType += ", __Block_byref_id_object_dispose_";
+ ByrefType += utostr(flag);
+ ByrefType += ", ";
+ }
InsertText(startLoc, ByrefType.c_str(), ByrefType.size());
// Complete the newly synthesized compound expression by inserting a right
@@ -4638,8 +4830,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
Stmts.push_back(S);
else if (isa<ObjCForCollectionStmt>(S)) {
Stmts.push_back(S);
- ++BcLabelCount;
- ObjCBcLabelNo.push_back(BcLabelCount);
+ ObjCBcLabelNo.push_back(++BcLabelCount);
}
SourceRange OrigStmtRange = S->getSourceRange();
@@ -4658,7 +4849,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
RewriteFunctionBodyOrGlobalInitializer(BE->getBody());
// Now we snarf the rewritten text and stash it away for later use.
- std::string Str = Rewrite.getRewritenText(BE->getSourceRange());
+ std::string Str = Rewrite.getRewrittenText(BE->getSourceRange());
RewrittenBlockExprs[BE] = Str;
Stmt *blockTranscribed = SynthBlockInitExpr(BE);
@@ -4801,8 +4992,13 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
else if (ND->getType()->isFunctionPointerType())
CheckFunctionPointerDecl(ND->getType(), ND);
if (VarDecl *VD = dyn_cast<VarDecl>(SD))
- if (VD->hasAttr<BlocksAttr>())
+ if (VD->hasAttr<BlocksAttr>()) {
+ static unsigned uniqueByrefDeclCount = 0;
+ assert(!BlockByRefDeclNo.count(ND) &&
+ "RewriteFunctionBodyOrGlobalInitializer: Duplicate byref decl");
+ BlockByRefDeclNo[ND] = uniqueByrefDeclCount++;
RewriteByRefVar(VD);
+ }
}
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
@@ -4829,6 +5025,12 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
if (BDRE->isByRef())
return RewriteBlockDeclRefExpr(BDRE);
}
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
+ ValueDecl *VD = DRE->getDecl();
+ if (VD->hasAttr<BlocksAttr>())
+ return RewriteBlockDeclRefExpr(DRE);
+ }
+
if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
if (CE->getCallee()->getType()->isBlockPointerType()) {
Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee());
@@ -4885,6 +5087,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
// FIXME: If this should support Obj-C++, support CXXTryStmt
if (CompoundStmt *Body = FD->getCompoundBody()) {
CurFunctionDef = FD;
+ CurFunctionDeclToDeclareForBlock = FD;
CollectPropertySetters(Body);
CurrentBody = Body;
Body =
@@ -4899,6 +5102,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
// and any copy/dispose helper functions.
InsertBlockLiteralsWithinFunction(FD);
CurFunctionDef = 0;
+ CurFunctionDeclToDeclareForBlock = 0;
}
return;
}
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 61f8a70..fcefd4e 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -371,7 +371,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
CaretLine.push_back('^');
// Scan the source line, looking for tabs. If we find any, manually expand
- // them to 8 characters and update the CaretLine to match.
+ // them to spaces and update the CaretLine to match.
for (unsigned i = 0; i != SourceLine.size(); ++i) {
if (SourceLine[i] != '\t') continue;
@@ -379,8 +379,11 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
SourceLine[i] = ' ';
// Compute the number of spaces we need to insert.
- unsigned NumSpaces = ((i+8)&~7) - (i+1);
- assert(NumSpaces < 8 && "Invalid computation of space amt");
+ unsigned TabStop = DiagOpts->TabStop;
+ assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop &&
+ "Invalid -ftabstop value");
+ unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1);
+ assert(NumSpaces < TabStop && "Invalid computation of space amt");
// Insert spaces into the SourceLine.
SourceLine.insert(i+1, NumSpaces, ' ');
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index 5d2bcbb..e270602 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -172,7 +172,7 @@ static inline __m128 __attribute__((__always_inline__, __nodebug__))
_mm_xor_ps(__m128 a, __m128 b)
{
typedef int __v4si __attribute__((__vector_size__(16)));
- return (__m128)((__v4si)a ^ ~(__v4si)b);
+ return (__m128)((__v4si)a ^ (__v4si)b);
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
index df71276..4010d61 100644
--- a/lib/Lex/HeaderMap.cpp
+++ b/lib/Lex/HeaderMap.cpp
@@ -56,8 +56,9 @@ struct HMapHeader {
/// HashHMapKey - This is the 'well known' hash function required by the file
/// format, used to look up keys in the hash table. The hash table uses simple
/// linear probing based on this function.
-static inline unsigned HashHMapKey(const char *S, const char *End) {
+static inline unsigned HashHMapKey(llvm::StringRef Str) {
unsigned Result = 0;
+ const char *S = Str.begin(), *End = Str.end();
for (; S != End; S++)
Result += tolower(*S) * 13;
@@ -172,17 +173,6 @@ const char *HeaderMap::getString(unsigned StrTabIdx) const {
return FileBuffer->getBufferStart()+StrTabIdx;
}
-/// StringsEqualWithoutCase - Compare the specified two strings for case-
-/// insensitive equality, returning true if they are equal. Both strings are
-/// known to have the same length.
-static bool StringsEqualWithoutCase(const char *S1, const char *S2,
- unsigned Len) {
- for (; Len; ++S1, ++S2, --Len)
- if (tolower(*S1) != tolower(*S2))
- return false;
- return true;
-}
-
//===----------------------------------------------------------------------===//
// The Main Drivers
//===----------------------------------------------------------------------===//
@@ -209,8 +199,7 @@ void HeaderMap::dump() const {
/// LookupFile - Check to see if the specified relative filename is located in
/// this HeaderMap. If so, open it and return its FileEntry.
-const FileEntry *HeaderMap::LookupFile(const char *FilenameStart,
- const char *FilenameEnd,
+const FileEntry *HeaderMap::LookupFile(llvm::StringRef Filename,
FileManager &FM) const {
const HMapHeader &Hdr = getHeader();
unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);
@@ -221,18 +210,12 @@ const FileEntry *HeaderMap::LookupFile(const char *FilenameStart,
return 0;
// Linearly probe the hash table.
- for (unsigned Bucket = HashHMapKey(FilenameStart, FilenameEnd);; ++Bucket) {
+ for (unsigned Bucket = HashHMapKey(Filename);; ++Bucket) {
HMapBucket B = getBucket(Bucket & (NumBuckets-1));
if (B.Key == HMAP_EmptyBucketKey) return 0; // Hash miss.
// See if the key matches. If not, probe on.
- const char *Key = getString(B.Key);
- unsigned BucketKeyLen = strlen(Key);
- if (BucketKeyLen != unsigned(FilenameEnd-FilenameStart))
- continue;
-
- // See if the actual strings equal.
- if (!StringsEqualWithoutCase(FilenameStart, Key, BucketKeyLen))
+ if (!Filename.equals_lower(getString(B.Key)))
continue;
// If so, we have a match in the hash table. Construct the destination
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 2b9b7c9..4554aba 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -109,8 +109,7 @@ const char *DirectoryLookup::getName() const {
/// LookupFile - Lookup the specified file in this search path, returning it
/// if it exists or returning null if not.
-const FileEntry *DirectoryLookup::LookupFile(const char *FilenameStart,
- const char *FilenameEnd,
+const FileEntry *DirectoryLookup::LookupFile(llvm::StringRef Filename,
HeaderSearch &HS) const {
llvm::SmallString<1024> TmpDir;
if (isNormalDir()) {
@@ -118,33 +117,32 @@ const FileEntry *DirectoryLookup::LookupFile(const char *FilenameStart,
// FIXME: Portability. Filename concatenation should be in sys::Path.
TmpDir += getDir()->getName();
TmpDir.push_back('/');
- TmpDir.append(FilenameStart, FilenameEnd);
+ TmpDir.append(Filename.begin(), Filename.end());
return HS.getFileMgr().getFile(TmpDir.begin(), TmpDir.end());
}
if (isFramework())
- return DoFrameworkLookup(FilenameStart, FilenameEnd, HS);
+ return DoFrameworkLookup(Filename, HS);
assert(isHeaderMap() && "Unknown directory lookup");
- return getHeaderMap()->LookupFile(FilenameStart, FilenameEnd,HS.getFileMgr());
+ return getHeaderMap()->LookupFile(Filename, HS.getFileMgr());
}
/// DoFrameworkLookup - Do a lookup of the specified file in the current
/// DirectoryLookup, which is a framework directory.
-const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart,
- const char *FilenameEnd,
+const FileEntry *DirectoryLookup::DoFrameworkLookup(llvm::StringRef Filename,
HeaderSearch &HS) const {
FileManager &FileMgr = HS.getFileMgr();
// Framework names must have a '/' in the filename.
- const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/');
- if (SlashPos == FilenameEnd) return 0;
+ size_t SlashPos = Filename.find('/');
+ if (SlashPos == llvm::StringRef::npos) return 0;
// Find out if this is the home for the specified framework, by checking
// HeaderSearch. Possible answer are yes/no and unknown.
const DirectoryEntry *&FrameworkDirCache =
- HS.LookupFrameworkCache(FilenameStart, SlashPos);
+ HS.LookupFrameworkCache(Filename.substr(0, SlashPos));
// If it is known and in some other directory, fail.
if (FrameworkDirCache && FrameworkDirCache != getFrameworkDir())
@@ -159,7 +157,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart,
FrameworkName.push_back('/');
// FrameworkName = "/System/Library/Frameworks/Cocoa"
- FrameworkName.append(FilenameStart, SlashPos);
+ FrameworkName.append(Filename.begin(), Filename.begin()+SlashPos);
// FrameworkName = "/System/Library/Frameworks/Cocoa.framework/"
FrameworkName += ".framework/";
@@ -184,7 +182,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart,
unsigned OrigSize = FrameworkName.size();
FrameworkName += "Headers/";
- FrameworkName.append(SlashPos+1, FilenameEnd);
+ FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
if (const FileEntry *FE = FileMgr.getFile(FrameworkName.begin(),
FrameworkName.end())) {
return FE;
@@ -208,21 +206,20 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart,
/// for system #include's or not (i.e. using <> instead of ""). CurFileEnt, if
/// non-null, indicates where the #including file is, in case a relative search
/// is needed.
-const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart,
- const char *FilenameEnd,
+const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename,
bool isAngled,
const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir,
const FileEntry *CurFileEnt) {
// If 'Filename' is absolute, check to see if it exists and no searching.
- if (llvm::sys::Path::isAbsolute(FilenameStart, FilenameEnd-FilenameStart)) {
+ if (llvm::sys::Path::isAbsolute(Filename.begin(), Filename.size())) {
CurDir = 0;
// If this was an #include_next "/absolute/file", fail.
if (FromDir) return 0;
// Otherwise, just return the file.
- return FileMgr.getFile(FilenameStart, FilenameEnd);
+ return FileMgr.getFile(Filename);
}
// Step #0, unless disabled, check to see if the file is in the #includer's
@@ -236,8 +233,8 @@ const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart,
// FIXME: Portability. Filename concatenation should be in sys::Path.
TmpDir += CurFileEnt->getDir()->getName();
TmpDir.push_back('/');
- TmpDir.append(FilenameStart, FilenameEnd);
- if (const FileEntry *FE = FileMgr.getFile(TmpDir.begin(), TmpDir.end())) {
+ TmpDir.append(Filename.begin(), Filename.end());
+ if (const FileEntry *FE = FileMgr.getFile(TmpDir.str())) {
// Leave CurDir unset.
// This file is a system header or C++ unfriendly if the old file is.
//
@@ -265,7 +262,7 @@ const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart,
// being relex/pp'd, but they would still have to search through a
// (potentially huge) series of SearchDirs to find it.
std::pair<unsigned, unsigned> &CacheLookup =
- LookupFileCache.GetOrCreateValue(FilenameStart, FilenameEnd).getValue();
+ LookupFileCache.GetOrCreateValue(Filename).getValue();
// If the entry has been previously looked up, the first value will be
// non-zero. If the value is equal to i (the start point of our search), then
@@ -283,7 +280,7 @@ const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart,
// Check each directory in sequence to see if it contains this file.
for (; i != SearchDirs.size(); ++i) {
const FileEntry *FE =
- SearchDirs[i].LookupFile(FilenameStart, FilenameEnd, *this);
+ SearchDirs[i].LookupFile(Filename, *this);
if (!FE) continue;
CurDir = &SearchDirs[i];
@@ -307,14 +304,13 @@ const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart,
/// is a subframework within Carbon.framework. If so, return the FileEntry
/// for the designated file, otherwise return null.
const FileEntry *HeaderSearch::
-LookupSubframeworkHeader(const char *FilenameStart,
- const char *FilenameEnd,
+LookupSubframeworkHeader(llvm::StringRef Filename,
const FileEntry *ContextFileEnt) {
assert(ContextFileEnt && "No context file?");
// Framework names must have a '/' in the filename. Find it.
- const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/');
- if (SlashPos == FilenameEnd) return 0;
+ size_t SlashPos = Filename.find('/');
+ if (SlashPos == llvm::StringRef::npos) return 0;
// Look up the base framework name of the ContextFileEnt.
const char *ContextName = ContextFileEnt->getName();
@@ -329,11 +325,11 @@ LookupSubframeworkHeader(const char *FilenameStart,
// Append Frameworks/HIToolbox.framework/
FrameworkName += "Frameworks/";
- FrameworkName.append(FilenameStart, SlashPos);
+ FrameworkName.append(Filename.begin(), Filename.begin()+SlashPos);
FrameworkName += ".framework/";
llvm::StringMapEntry<const DirectoryEntry *> &CacheLookup =
- FrameworkMap.GetOrCreateValue(FilenameStart, SlashPos);
+ FrameworkMap.GetOrCreateValue(Filename.begin(), Filename.begin()+SlashPos);
// Some other location?
if (CacheLookup.getValue() &&
@@ -361,14 +357,14 @@ LookupSubframeworkHeader(const char *FilenameStart,
// Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h"
llvm::SmallString<1024> HeadersFilename(FrameworkName);
HeadersFilename += "Headers/";
- HeadersFilename.append(SlashPos+1, FilenameEnd);
+ HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
if (!(FE = FileMgr.getFile(HeadersFilename.begin(),
HeadersFilename.end()))) {
// Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
HeadersFilename = FrameworkName;
HeadersFilename += "PrivateHeaders/";
- HeadersFilename.append(SlashPos+1, FilenameEnd);
+ HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
if (!(FE = FileMgr.getFile(HeadersFilename.begin(), HeadersFilename.end())))
return 0;
}
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index d5a4643..0a74b26 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -643,14 +643,17 @@ void Lexer::LexIdentifier(Token &Result, const char *CurPtr) {
// Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$]
unsigned Size;
unsigned char C = *CurPtr++;
- while (isIdentifierBody(C)) {
+ while (isIdentifierBody(C))
C = *CurPtr++;
- }
+
--CurPtr; // Back up over the skipped character.
// Fast path, no $,\,? in identifier found. '\' might be an escaped newline
// or UCN, and ? might be a trigraph for '\', an escaped newline or UCN.
// FIXME: UCNs.
+ //
+ // TODO: Could merge these checks into a CharInfo flag to make the comparison
+ // cheaper
if (C != '\\' && C != '?' && (C != '$' || !Features.DollarIdents)) {
FinishIdentifier:
const char *IdStart = BufferPtr;
@@ -724,7 +727,8 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
// If we have a hex FP constant, continue.
- if ((C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p'))
+ if ((C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p') &&
+ (!PP || !PP->getLangOptions().CPlusPlus0x))
return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
// Update the location of token as well as BufferPtr.
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 9aaa82d..5cd5497 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -458,7 +458,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
}
// A binary exponent can appear with or with a '.'. If dotted, the
// binary exponent is required.
- if (*s == 'p' || *s == 'P') {
+ if ((*s == 'p' || *s == 'P') && !PP.getLangOptions().CPlusPlus0x) {
const char *Exponent = s;
s++;
saw_exponent = true;
@@ -472,7 +472,12 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
}
s = first_non_digit;
- if (!PP.getLangOptions().HexFloats)
+ // In C++0x, we cannot support hexadecmial floating literals because
+ // they conflict with user-defined literals, so we warn in previous
+ // versions of C++ by default.
+ if (PP.getLangOptions().CPlusPlus)
+ PP.Diag(TokLoc, diag::ext_hexconstant_cplusplus);
+ else if (!PP.getLangOptions().HexFloats)
PP.Diag(TokLoc, diag::ext_hexconstant_invalid);
} else if (saw_period) {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 9e3d283..aa807f8 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -404,8 +404,8 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() {
/// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
/// return null on failure. isAngled indicates whether the file reference is
/// for system #include's or not (i.e. using <> instead of "").
-const FileEntry *Preprocessor::LookupFile(const char *FilenameStart,
- const char *FilenameEnd,
+const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename,
+ SourceLocation FilenameTokLoc,
bool isAngled,
const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir) {
@@ -431,17 +431,24 @@ const FileEntry *Preprocessor::LookupFile(const char *FilenameStart,
// Do a standard file entry lookup.
CurDir = CurDirLookup;
const FileEntry *FE =
- HeaderInfo.LookupFile(FilenameStart, FilenameEnd,
- isAngled, FromDir, CurDir, CurFileEnt);
- if (FE) return FE;
+ HeaderInfo.LookupFile(Filename, isAngled, FromDir, CurDir, CurFileEnt);
+ if (FE) {
+ // Warn about normal quoted #include from framework headers. Since
+ // framework headers are published (both public and private ones) they
+ // should not do relative searches, they should do an include with the
+ // framework path included.
+ if (!isAngled && CurDir && FilenameTokLoc.isValid() &&
+ CurDir->isFramework() && CurDir == CurDirLookup)
+ Diag(FilenameTokLoc, diag::warn_pp_relative_include_from_framework);
+ return FE;
+ }
// Otherwise, see if this is a subframework header. If so, this is relative
// to one of the headers on the #include stack. Walk the list of the current
// headers on the #include stack and pass them to HeaderInfo.
if (IsFileLexer()) {
if ((CurFileEnt = SourceMgr.getFileEntryForID(CurPPLexer->getFileID())))
- if ((FE = HeaderInfo.LookupSubframeworkHeader(FilenameStart, FilenameEnd,
- CurFileEnt)))
+ if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt)))
return FE;
}
@@ -450,8 +457,7 @@ const FileEntry *Preprocessor::LookupFile(const char *FilenameStart,
if (IsFileLexer(ISEntry)) {
if ((CurFileEnt =
SourceMgr.getFileEntryForID(ISEntry.ThePPLexer->getFileID())))
- if ((FE = HeaderInfo.LookupSubframeworkHeader(FilenameStart,
- FilenameEnd, CurFileEnt)))
+ if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt)))
return FE;
}
}
@@ -922,43 +928,41 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) {
/// spelling of the filename, but is also expected to handle the case when
/// this method decides to use a different buffer.
bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc,
- const char *&BufStart,
- const char *&BufEnd) {
+ llvm::StringRef &Buffer) {
// Get the text form of the filename.
- assert(BufStart != BufEnd && "Can't have tokens with empty spellings!");
+ assert(!Buffer.empty() && "Can't have tokens with empty spellings!");
// Make sure the filename is <x> or "x".
bool isAngled;
- if (BufStart[0] == '<') {
- if (BufEnd[-1] != '>') {
+ if (Buffer[0] == '<') {
+ if (Buffer.back() != '>') {
Diag(Loc, diag::err_pp_expects_filename);
- BufStart = 0;
+ Buffer = llvm::StringRef();
return true;
}
isAngled = true;
- } else if (BufStart[0] == '"') {
- if (BufEnd[-1] != '"') {
+ } else if (Buffer[0] == '"') {
+ if (Buffer.back() != '"') {
Diag(Loc, diag::err_pp_expects_filename);
- BufStart = 0;
+ Buffer = llvm::StringRef();
return true;
}
isAngled = false;
} else {
Diag(Loc, diag::err_pp_expects_filename);
- BufStart = 0;
+ Buffer = llvm::StringRef();
return true;
}
// Diagnose #include "" as invalid.
- if (BufEnd-BufStart <= 2) {
+ if (Buffer.size() <= 2) {
Diag(Loc, diag::err_pp_empty_filename);
- BufStart = 0;
- return "";
+ Buffer = llvm::StringRef();
+ return true;
}
// Skip the brackets.
- ++BufStart;
- --BufEnd;
+ Buffer = Buffer.substr(1, Buffer.size()-2);
return isAngled;
}
@@ -1024,8 +1028,8 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
CurPPLexer->LexIncludeFilename(FilenameTok);
// Reserve a buffer to get the spelling.
- llvm::SmallVector<char, 128> FilenameBuffer;
- const char *FilenameStart, *FilenameEnd;
+ llvm::SmallString<128> FilenameBuffer;
+ llvm::StringRef Filename;
switch (FilenameTok.getKind()) {
case tok::eom:
@@ -1035,9 +1039,9 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
case tok::angle_string_literal:
case tok::string_literal: {
FilenameBuffer.resize(FilenameTok.getLength());
- FilenameStart = &FilenameBuffer[0];
+ const char *FilenameStart = &FilenameBuffer[0];
unsigned Len = getSpelling(FilenameTok, FilenameStart);
- FilenameEnd = FilenameStart+Len;
+ Filename = llvm::StringRef(FilenameStart, Len);
break;
}
@@ -1047,8 +1051,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
FilenameBuffer.push_back('<');
if (ConcatenateIncludeName(FilenameBuffer))
return; // Found <eom> but no ">"? Diagnostic already emitted.
- FilenameStart = FilenameBuffer.data();
- FilenameEnd = FilenameStart + FilenameBuffer.size();
+ Filename = FilenameBuffer.str();
break;
default:
Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
@@ -1056,11 +1059,11 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
return;
}
- bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(),
- FilenameStart, FilenameEnd);
+ bool isAngled =
+ GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
// error.
- if (FilenameStart == 0) {
+ if (Filename.empty()) {
DiscardUntilEndOfDirective();
return;
}
@@ -1079,14 +1082,13 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
// Search include directories.
const DirectoryLookup *CurDir;
- const FileEntry *File = LookupFile(FilenameStart, FilenameEnd,
+ const FileEntry *File = LookupFile(Filename, FilenameTok.getLocation(),
isAngled, LookupFrom, CurDir);
if (File == 0) {
- Diag(FilenameTok, diag::err_pp_file_not_found)
- << std::string(FilenameStart, FilenameEnd);
+ Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
}
-
+
// Ask HeaderInfo if we should enter this #include file. If not, #including
// this file will have no effect.
if (!HeaderInfo.ShouldEnterIncludeFile(File, isImport))
@@ -1103,8 +1105,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
FileID FID = SourceMgr.createFileID(File, FilenameTok.getLocation(),
FileCharacter);
if (FID.isInvalid()) {
- Diag(FilenameTok, diag::err_pp_file_not_found)
- << std::string(FilenameStart, FilenameEnd);
+ Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
}
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index ce1b19c..0b26ccb 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -249,7 +249,8 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
// diagnostic is enabled, look for macros that have not been used.
if (getDiagnostics().getDiagnosticLevel(diag::pp_macro_not_used) !=
Diagnostic::Ignored) {
- for (macro_iterator I = macro_begin(), E = macro_end(); I != E; ++I)
+ for (macro_iterator I = macro_begin(false), E = macro_end(false);
+ I != E; ++I)
if (!I->second->isUsed())
Diag(I->second->getDefinitionLoc(), diag::pp_macro_not_used);
}
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index dfb14ff..3792782 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -18,6 +18,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "llvm/ADT/StringSwitch.h"
#include <cstdio>
#include <ctime>
using namespace clang;
@@ -481,34 +482,27 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
const LangOptions &LangOpts = PP.getLangOptions();
- switch (II->getLength()) {
- default: return false;
- case 6:
- if (II->isStr("blocks")) return LangOpts.Blocks;
- return false;
- case 8:
- if (II->isStr("cxx_rtti")) return LangOpts.RTTI;
- return false;
- case 14:
- if (II->isStr("cxx_exceptions")) return LangOpts.Exceptions;
- return false;
- case 19:
- if (II->isStr("objc_nonfragile_abi")) return LangOpts.ObjCNonFragileABI;
- return false;
- case 22:
- if (II->isStr("attribute_overloadable")) return true;
- return false;
- case 25:
- if (II->isStr("attribute_ext_vector_type")) return true;
- return false;
- case 27:
- if (II->isStr("attribute_analyzer_noreturn")) return true;
- return false;
- case 29:
- if (II->isStr("attribute_ns_returns_retained")) return true;
- if (II->isStr("attribute_cf_returns_retained")) return true;
- return false;
- }
+ return llvm::StringSwitch<bool>(II->getName())
+ .Case("blocks", LangOpts.Blocks)
+ .Case("cxx_rtti", LangOpts.RTTI)
+ //.Case("cxx_lambdas", false)
+ //.Case("cxx_nullptr", false)
+ //.Case("cxx_concepts", false)
+ .Case("cxx_decltype", LangOpts.CPlusPlus0x)
+ .Case("cxx_auto_type", LangOpts.CPlusPlus0x)
+ .Case("cxx_exceptions", LangOpts.Exceptions)
+ .Case("cxx_attributes", LangOpts.CPlusPlus0x)
+ .Case("cxx_static_assert", LangOpts.CPlusPlus0x)
+ .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
+ .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x)
+ //.Case("cxx_rvalue_references", false)
+ .Case("attribute_overloadable", true)
+ //.Case("cxx_variadic_templates", false)
+ .Case("attribute_ext_vector_type", true)
+ .Case("attribute_analyzer_noreturn", true)
+ .Case("attribute_ns_returns_retained", true)
+ .Case("attribute_cf_returns_retained", true)
+ .Default(false);
}
/// EvaluateHasIncludeCommon - Process a '__has_include("path")'
@@ -535,8 +529,8 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok,
PP.getCurrentLexer()->LexIncludeFilename(Tok);
// Reserve a buffer to get the spelling.
- llvm::SmallVector<char, 128> FilenameBuffer;
- const char *FilenameStart, *FilenameEnd;
+ llvm::SmallString<128> FilenameBuffer;
+ llvm::StringRef Filename;
switch (Tok.getKind()) {
case tok::eom:
@@ -546,9 +540,9 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok,
case tok::angle_string_literal:
case tok::string_literal: {
FilenameBuffer.resize(Tok.getLength());
- FilenameStart = &FilenameBuffer[0];
+ const char *FilenameStart = &FilenameBuffer[0];
unsigned Len = PP.getSpelling(Tok, FilenameStart);
- FilenameEnd = FilenameStart+Len;
+ Filename = llvm::StringRef(FilenameStart, Len);
break;
}
@@ -558,26 +552,24 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok,
FilenameBuffer.push_back('<');
if (PP.ConcatenateIncludeName(FilenameBuffer))
return false; // Found <eom> but no ">"? Diagnostic already emitted.
- FilenameStart = FilenameBuffer.data();
- FilenameEnd = FilenameStart + FilenameBuffer.size();
+ Filename = FilenameBuffer.str();
break;
default:
PP.Diag(Tok.getLocation(), diag::err_pp_expects_filename);
return false;
}
- bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(),
- FilenameStart, FilenameEnd);
+ bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename);
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
// error.
- if (FilenameStart == 0) {
+ if (Filename.empty())
return false;
- }
// Search include directories.
const DirectoryLookup *CurDir;
- const FileEntry *File = PP.LookupFile(FilenameStart, FilenameEnd,
- isAngled, LookupFrom, CurDir);
+ const FileEntry *File = PP.LookupFile(Filename,
+ SourceLocation(),// produce no warnings.
+ isAngled, LookupFrom, CurDir);
// Get the result value. Result = true means the file exists.
Result = File != 0;
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 8b46f71..856b3bd 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -286,26 +286,25 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
return;
// Reserve a buffer to get the spelling.
- llvm::SmallVector<char, 128> FilenameBuffer;
+ llvm::SmallString<128> FilenameBuffer;
FilenameBuffer.resize(FilenameTok.getLength());
const char *FilenameStart = &FilenameBuffer[0];
unsigned Len = getSpelling(FilenameTok, FilenameStart);
- const char *FilenameEnd = FilenameStart+Len;
- bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(),
- FilenameStart, FilenameEnd);
+ llvm::StringRef Filename(FilenameStart, Len);
+ bool isAngled =
+ GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
// error.
- if (FilenameStart == 0)
+ if (Filename.empty())
return;
// Search include directories for this file.
const DirectoryLookup *CurDir;
- const FileEntry *File = LookupFile(FilenameStart, FilenameEnd,
+ const FileEntry *File = LookupFile(Filename, FilenameTok.getLocation(),
isAngled, 0, CurDir);
if (File == 0) {
- Diag(FilenameTok, diag::err_pp_file_not_found)
- << std::string(FilenameStart, FilenameEnd);
+ Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 81966cb..26bb3a9 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -27,6 +27,7 @@
#include "clang/Lex/Preprocessor.h"
#include "MacroArgs.h"
+#include "clang/Lex/ExternalPreprocessorSource.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Pragma.h"
@@ -43,6 +44,7 @@
using namespace clang;
//===----------------------------------------------------------------------===//
+ExternalPreprocessorSource::~ExternalPreprocessorSource() { }
Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
const TargetInfo &target, SourceManager &SM,
@@ -50,9 +52,9 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
IdentifierInfoLookup* IILookup,
bool OwnsHeaders)
: Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()),
- SourceMgr(SM), HeaderInfo(Headers), Identifiers(opts, IILookup),
- BuiltinInfo(Target), CodeCompletionFile(0), CurPPLexer(0), CurDirLookup(0),
- Callbacks(0), MacroArgCache(0) {
+ SourceMgr(SM), HeaderInfo(Headers), ExternalSource(0),
+ Identifiers(opts, IILookup), BuiltinInfo(Target), CodeCompletionFile(0),
+ CurPPLexer(0), CurDirLookup(0), Callbacks(0), MacroArgCache(0) {
ScratchBuf = new ScratchBuffer(SourceMgr);
CounterValue = 0; // __COUNTER__ starts at 0.
OwnsHeaderSearch = OwnsHeaders;
@@ -77,6 +79,9 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
CachedLexPos = 0;
+ // We haven't read anything from the external source.
+ ReadMacrosFromExternalSource = false;
+
// "Poison" __VA_ARGS__, which can only appear in the expansion of a macro.
// This gets unpoisoned where it is allowed.
(Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned();
@@ -194,6 +199,28 @@ void Preprocessor::PrintStats() {
<< NumFastTokenPaste << " on the fast path.\n";
}
+Preprocessor::macro_iterator
+Preprocessor::macro_begin(bool IncludeExternalMacros) const {
+ if (IncludeExternalMacros && ExternalSource &&
+ !ReadMacrosFromExternalSource) {
+ ReadMacrosFromExternalSource = true;
+ ExternalSource->ReadDefinedMacros();
+ }
+
+ return Macros.begin();
+}
+
+Preprocessor::macro_iterator
+Preprocessor::macro_end(bool IncludeExternalMacros) const {
+ if (IncludeExternalMacros && ExternalSource &&
+ !ReadMacrosFromExternalSource) {
+ ReadMacrosFromExternalSource = true;
+ ExternalSource->ReadDefinedMacros();
+ }
+
+ return Macros.end();
+}
+
bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
unsigned TruncateAtLine,
unsigned TruncateAtColumn) {
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index 4cd8fe8..f52d8b9 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -36,6 +36,14 @@ void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) {
EndLocation = TemplateId->RAngleLoc;
}
+void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) {
+ assert(TemplateId && "NULL template-id annotation?");
+ Kind = IK_ConstructorTemplateId;
+ this->TemplateId = TemplateId;
+ StartLocation = TemplateId->TemplateNameLoc;
+ EndLocation = TemplateId->RAngleLoc;
+}
+
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
/// "TheDeclarator" is the declarator that this will be added to.
DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index f429ac9..b5ba8ac 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -356,7 +356,8 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
ParsingDeclSpec DS(*this);
if (Attr)
DS.AddAttributes(Attr);
- ParseDeclarationSpecifiers(DS);
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
+ getDeclSpecContextFromDeclaratorContext(Context));
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
@@ -786,6 +787,20 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
return false;
}
+/// \brief Determine the declaration specifier context from the declarator
+/// context.
+///
+/// \param Context the declarator context, which is one of the
+/// Declarator::TheContext enumerator values.
+Parser::DeclSpecContext
+Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
+ if (Context == Declarator::MemberContext)
+ return DSC_class;
+ if (Context == Declarator::FileContext)
+ return DSC_top_level;
+ return DSC_normal;
+}
+
/// ParseDeclarationSpecifiers
/// declaration-specifiers: [C99 6.7]
/// storage-class-specifier declaration-specifiers[opt]
@@ -814,7 +829,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
AccessSpecifier AS,
DeclSpecContext DSContext) {
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteOrdinaryName(CurScope);
+ Action::CodeCompletionContext CCC = Action::CCC_Namespace;
+ if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate)
+ CCC = DSContext == DSC_class? Action::CCC_MemberTemplate
+ : Action::CCC_Template;
+ else if (DSContext == DSC_class)
+ CCC = Action::CCC_Class;
+ else if (ObjCImpDecl)
+ CCC = Action::CCC_ObjCImplementation;
+
+ Actions.CodeCompleteOrdinaryName(CurScope, CCC);
ConsumeToken();
}
@@ -854,6 +878,47 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
->Kind == TNK_Type_template) {
// We have a qualified template-id, e.g., N::A<int>
+
+ // C++ [class.qual]p2:
+ // In a lookup in which the constructor is an acceptable lookup
+ // result and the nested-name-specifier nominates a class C:
+ //
+ // - if the name specified after the
+ // nested-name-specifier, when looked up in C, is the
+ // injected-class-name of C (Clause 9), or
+ //
+ // - if the name specified after the nested-name-specifier
+ // is the same as the identifier or the
+ // simple-template-id's template-name in the last
+ // component of the nested-name-specifier,
+ //
+ // the name is instead considered to name the constructor of
+ // class C.
+ //
+ // Thus, if the template-name is actually the constructor
+ // name, then the code is ill-formed; this interpretation is
+ // reinforced by the NAD status of core issue 635.
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue());
+ if (DSContext == DSC_top_level && TemplateId->Name &&
+ Actions.isCurrentClassName(*TemplateId->Name, CurScope, &SS)) {
+ if (isConstructorDeclarator()) {
+ // The user meant this to be an out-of-line constructor
+ // definition, but template arguments are not allowed
+ // there. Just allow this as a constructor; we'll
+ // complain about it later.
+ goto DoneWithDeclSpec;
+ }
+
+ // The user meant this to name a type, but it actually names
+ // a constructor with some extraneous template
+ // arguments. Complain, then parse it as a type as the user
+ // intended.
+ Diag(TemplateId->TemplateNameLoc,
+ diag::err_out_of_line_template_id_names_constructor)
+ << TemplateId->Name;
+ }
+
DS.getTypeSpecScope() = SS;
ConsumeToken(); // The C++ scope.
assert(Tok.is(tok::annot_template_id) &&
@@ -878,13 +943,23 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (Next.isNot(tok::identifier))
goto DoneWithDeclSpec;
- // If the next token is the name of the class type that the C++ scope
- // denotes, followed by a '(', then this is a constructor declaration.
- // We're done with the decl-specifiers.
- if (Actions.isCurrentClassName(*Next.getIdentifierInfo(),
- CurScope, &SS) &&
- GetLookAheadToken(2).is(tok::l_paren))
- goto DoneWithDeclSpec;
+ // If we're in a context where the identifier could be a class name,
+ // check whether this is a constructor declaration.
+ if (DSContext == DSC_top_level &&
+ Actions.isCurrentClassName(*Next.getIdentifierInfo(), CurScope,
+ &SS)) {
+ if (isConstructorDeclarator())
+ goto DoneWithDeclSpec;
+
+ // As noted in C++ [class.qual]p2 (cited above), when the name
+ // of the class is qualified in a context where it could name
+ // a constructor, its a constructor name. However, we've
+ // looked at the declarator, and the user probably meant this
+ // to be a type. Complain that it isn't supposed to be treated
+ // as a type, then proceed to parse it as a type.
+ Diag(Next.getLocation(), diag::err_out_of_line_type_names_constructor)
+ << Next.getIdentifierInfo();
+ }
TypeTy *TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(),
Next.getLocation(), CurScope, &SS);
@@ -965,16 +1040,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
goto DoneWithDeclSpec;
}
- // C++: If the identifier is actually the name of the class type
- // being defined and the next token is a '(', then this is a
- // constructor declaration. We're done with the decl-specifiers
- // and will treat this token as an identifier.
- if (getLang().CPlusPlus &&
- (CurScope->isClassScope() ||
- (CurScope->isTemplateParamScope() &&
- CurScope->getParent()->isClassScope())) &&
+ // If we're in a context where the identifier could be a class name,
+ // check whether this is a constructor declaration.
+ if (getLang().CPlusPlus && DSContext == DSC_class &&
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) &&
- NextToken().getKind() == tok::l_paren)
+ isConstructorDeclarator())
goto DoneWithDeclSpec;
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
@@ -1017,6 +1087,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
goto DoneWithDeclSpec;
}
+ // If we're in a context where the template-id could be a
+ // constructor name or specialization, check whether this is a
+ // constructor declaration.
+ if (getLang().CPlusPlus && DSContext == DSC_class &&
+ Actions.isCurrentClassName(*TemplateId->Name, CurScope) &&
+ isConstructorDeclarator())
+ goto DoneWithDeclSpec;
+
// Turn the template-id annotation token into a type annotation
// token, then try again to parse it as a type-specifier.
AnnotateTemplateIdTokenAsType();
@@ -2082,6 +2160,48 @@ bool Parser::isDeclarationSpecifier() {
}
}
+bool Parser::isConstructorDeclarator() {
+ TentativeParsingAction TPA(*this);
+
+ // Parse the C++ scope specifier.
+ CXXScopeSpec SS;
+ ParseOptionalCXXScopeSpecifier(SS, 0, true);
+
+ // Parse the constructor name.
+ if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) {
+ // We already know that we have a constructor name; just consume
+ // the token.
+ ConsumeToken();
+ } else {
+ TPA.Revert();
+ return false;
+ }
+
+ // Current class name must be followed by a left parentheses.
+ if (Tok.isNot(tok::l_paren)) {
+ TPA.Revert();
+ return false;
+ }
+ ConsumeParen();
+
+ // A right parentheses or ellipsis signals that we have a constructor.
+ if (Tok.is(tok::r_paren) || Tok.is(tok::ellipsis)) {
+ TPA.Revert();
+ return true;
+ }
+
+ // If we need to, enter the specified scope.
+ DeclaratorScopeObj DeclScopeObj(*this, SS);
+ if (SS.isSet() && Actions.ShouldEnterDeclaratorScope(CurScope, SS))
+ DeclScopeObj.EnterDeclaratorScope();
+
+ // Check whether the next token(s) are part of a declaration
+ // specifier, in which case we have the start of a parameter and,
+ // therefore, we know that this is a constructor.
+ bool IsConstructor = isDeclarationSpecifier();
+ TPA.Revert();
+ return IsConstructor;
+}
/// ParseTypeQualifierListOpt
/// type-qualifier-list: [C99 6.7.5]
@@ -2366,10 +2486,16 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) {
// We found something that indicates the start of an unqualified-id.
// Parse that unqualified-id.
+ bool AllowConstructorName
+ = ((D.getCXXScopeSpec().isSet() &&
+ D.getContext() == Declarator::FileContext) ||
+ (!D.getCXXScopeSpec().isSet() &&
+ D.getContext() == Declarator::MemberContext)) &&
+ !D.getDeclSpec().hasTypeSpecifier();
if (ParseUnqualifiedId(D.getCXXScopeSpec(),
/*EnteringContext=*/true,
/*AllowDestructorName=*/true,
- /*AllowConstructorName=*/!D.getDeclSpec().hasTypeSpecifier(),
+ AllowConstructorName,
/*ObjectType=*/0,
D.getName())) {
D.SetIdentifier(0, Tok.getLocation());
@@ -2396,6 +2522,16 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// direct-declarator: '(' attributes declarator ')'
// Example: 'char (*X)' or 'int (*XX)(void)'
ParseParenDeclarator(D);
+
+ // If the declarator was parenthesized, we entered the declarator
+ // scope when parsing the parenthesized declarator, then exited
+ // the scope already. Re-enter the scope, if we need to.
+ if (D.getCXXScopeSpec().isSet()) {
+ if (Actions.ShouldEnterDeclaratorScope(CurScope, D.getCXXScopeSpec()))
+ // Change the declaration context for name lookup, until this function
+ // is exited (and the declarator has been parsed).
+ DeclScopeObj.EnterDeclaratorScope();
+ }
} else if (D.mayOmitIdentifier()) {
// This could be something simple like "int" (in which case the declarator
// portion is empty), if an abstract-declarator is allowed.
@@ -3020,6 +3156,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
Token OpTok = Tok;
SourceLocation StartLoc = ConsumeToken();
+ const bool hasParens = Tok.is(tok::l_paren);
+
bool isCastExpr;
TypeTy *CastTy;
SourceRange CastRange;
@@ -3027,6 +3165,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
isCastExpr,
CastTy,
CastRange);
+ if (hasParens)
+ DS.setTypeofParensRange(CastRange);
if (CastRange.getEnd().isInvalid())
// FIXME: Not accurate, the range gets one token more than it should.
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 265d0f3..90040c5 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -468,7 +468,8 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
- if (TemplateId->Kind == TNK_Type_template) {
+ if (TemplateId->Kind == TNK_Type_template ||
+ TemplateId->Kind == TNK_Dependent_template_name) {
AnnotateTemplateIdTokenAsType(SS);
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
@@ -489,18 +490,57 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
return true;
}
+ IdentifierInfo *Id = Tok.getIdentifierInfo();
+ SourceLocation IdLoc = ConsumeToken();
+
+ if (Tok.is(tok::less)) {
+ // It looks the user intended to write a template-id here, but the
+ // template-name was wrong. Try to fix that.
+ TemplateNameKind TNK = TNK_Type_template;
+ TemplateTy Template;
+ if (!Actions.DiagnoseUnknownTemplateName(*Id, IdLoc, CurScope,
+ SS, Template, TNK)) {
+ Diag(IdLoc, diag::err_unknown_template_name)
+ << Id;
+ }
+
+ if (!Template)
+ return true;
+
+ // Form the template name
+ UnqualifiedId TemplateName;
+ TemplateName.setIdentifier(Id, IdLoc);
+
+ // Parse the full template-id, then turn it into a type.
+ if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName,
+ SourceLocation(), true))
+ return true;
+ if (TNK == TNK_Dependent_template_name)
+ AnnotateTemplateIdTokenAsType(SS);
+
+ // If we didn't end up with a typename token, there's nothing more we
+ // can do.
+ if (Tok.isNot(tok::annot_typename))
+ return true;
+
+ // Retrieve the type from the annotation token, consume that token, and
+ // return.
+ EndLocation = Tok.getAnnotationEndLoc();
+ TypeTy *Type = Tok.getAnnotationValue();
+ ConsumeToken();
+ return Type;
+ }
+
// We have an identifier; check whether it is actually a type.
- TypeTy *Type = Actions.getTypeName(*Tok.getIdentifierInfo(),
- Tok.getLocation(), CurScope, SS,
- true);
- if (!Type) {
- Diag(Tok, DestrExpected ? diag::err_destructor_class_name
+ TypeTy *Type = Actions.getTypeName(*Id, IdLoc, CurScope, SS, true);
+ if (!Type) {
+ Diag(IdLoc, DestrExpected ? diag::err_destructor_class_name
: diag::err_expected_class_name);
return true;
}
// Consume the identifier.
- EndLocation = ConsumeToken();
+ EndLocation = IdLoc;
return Type;
}
@@ -1527,12 +1567,12 @@ Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) {
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
- if (TemplateId->Kind == TNK_Type_template) {
+ if (TemplateId->Kind == TNK_Type_template ||
+ TemplateId->Kind == TNK_Dependent_template_name) {
AnnotateTemplateIdTokenAsType(&SS);
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
TemplateTypeTy = Tok.getAnnotationValue();
}
- // FIXME. May need to check for TNK_Dependent_template as well.
}
if (!TemplateTypeTy && Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_member_or_base_name);
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index bdbc67f..669575c 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -200,11 +200,6 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
/// expression ',' assignment-expression
///
Parser::OwningExprResult Parser::ParseExpression() {
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteOrdinaryName(CurScope);
- ConsumeToken();
- }
-
OwningExprResult LHS(ParseAssignmentExpression());
if (LHS.isInvalid()) return move(LHS);
@@ -248,6 +243,11 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
/// ParseAssignmentExpression - Parse an expr that doesn't include commas.
///
Parser::OwningExprResult Parser::ParseAssignmentExpression() {
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression);
+ ConsumeToken();
+ }
+
if (Tok.is(tok::kw_throw))
return ParseThrowExpression();
@@ -616,9 +616,17 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// Turn a potentially qualified name into a annot_typename or
// annot_cxxscope if it would be valid. This handles things like x::y, etc.
if (getLang().CPlusPlus) {
- // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
- if (TryAnnotateTypeOrScopeToken())
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
+ // Avoid the unnecessary parse-time lookup in the common case
+ // where the syntax forbids a type.
+ const Token &Next = NextToken();
+ if (Next.is(tok::coloncolon) ||
+ (!ColonIsSacred && Next.is(tok::colon)) ||
+ Next.is(tok::less) ||
+ Next.is(tok::l_paren)) {
+ // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
+ if (TryAnnotateTypeOrScopeToken())
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
+ }
}
// Consume the identifier so that we can see if it is followed by a '(' or
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index abd26d7..ca50ef4 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -585,6 +585,11 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
/// \returns true if there was a parsing, false otherwise.
bool Parser::ParseCXXCondition(OwningExprResult &ExprResult,
DeclPtrTy &DeclResult) {
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Condition);
+ ConsumeToken();
+ }
+
if (!isCXXConditionDeclaration()) {
ExprResult = ParseExpression(); // expression
DeclResult = DeclPtrTy();
@@ -1148,6 +1153,13 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
IdentifierInfo *Id = Tok.getIdentifierInfo();
SourceLocation IdLoc = ConsumeToken();
+ if (!getLang().CPlusPlus) {
+ // If we're not in C++, only identifiers matter. Record the
+ // identifier and return.
+ Result.setIdentifier(Id, IdLoc);
+ return false;
+ }
+
if (AllowConstructorName &&
Actions.isCurrentClassName(*Id, CurScope, &SS)) {
// We have parsed a constructor name.
@@ -1170,12 +1182,41 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
// unqualified-id:
// template-id (already parsed and annotated)
if (Tok.is(tok::annot_template_id)) {
- // FIXME: Could this be a constructor name???
-
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation*>(Tok.getAnnotationValue());
+
+ // If the template-name names the current class, then this is a constructor
+ if (AllowConstructorName && TemplateId->Name &&
+ Actions.isCurrentClassName(*TemplateId->Name, CurScope, &SS)) {
+ if (SS.isSet()) {
+ // C++ [class.qual]p2 specifies that a qualified template-name
+ // is taken as the constructor name where a constructor can be
+ // declared. Thus, the template arguments are extraneous, so
+ // complain about them and remove them entirely.
+ Diag(TemplateId->TemplateNameLoc,
+ diag::err_out_of_line_constructor_template_id)
+ << TemplateId->Name
+ << CodeModificationHint::CreateRemoval(
+ SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc));
+ Result.setConstructorName(Actions.getTypeName(*TemplateId->Name,
+ TemplateId->TemplateNameLoc,
+ CurScope,
+ &SS, false),
+ TemplateId->TemplateNameLoc,
+ TemplateId->RAngleLoc);
+ TemplateId->Destroy();
+ ConsumeToken();
+ return false;
+ }
+
+ Result.setConstructorTemplateId(TemplateId);
+ ConsumeToken();
+ return false;
+ }
+
// We have already parsed a template-id; consume the annotation token as
// our unqualified-id.
- Result.setTemplateId(
- static_cast<TemplateIdAnnotation*>(Tok.getAnnotationValue()));
+ Result.setTemplateId(TemplateId);
ConsumeToken();
return false;
}
@@ -1202,7 +1243,8 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
return false;
}
- if ((AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) {
+ if (getLang().CPlusPlus &&
+ (AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) {
// C++ [expr.unary.op]p10:
// There is an ambiguity in the unary-expression ~X(), where X is a
// class-name. The ambiguity is resolved in favor of treating ~ as a
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 9904a2c..5e23635 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -309,7 +309,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
llvm::SmallVector<DeclGroupPtrTy, 8> allTUVariables;
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
- SourceLocation AtEndLoc;
+ SourceRange AtEnd;
while (1) {
// If this is a method prototype, parse it.
@@ -334,6 +334,14 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
if (Tok.is(tok::eof))
break;
+ // Code completion within an Objective-C interface.
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteOrdinaryName(CurScope,
+ ObjCImpDecl? Action::CCC_ObjCImplementation
+ : Action::CCC_ObjCInterface);
+ ConsumeToken();
+ }
+
// If we don't have an @ directive, parse it as a function definition.
if (Tok.isNot(tok::at)) {
// The code below does not consume '}'s because it is afraid of eating the
@@ -359,7 +367,8 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
if (DirectiveKind == tok::objc_end) { // @end -> terminate list
- AtEndLoc = AtLoc;
+ AtEnd.setBegin(AtLoc);
+ AtEnd.setEnd(Tok.getLocation());
break;
}
@@ -422,7 +431,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
// Insert collected methods declarations into the @interface object.
// This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
- Actions.ActOnAtEnd(AtEndLoc, interfaceDecl,
+ Actions.ActOnAtEnd(AtEnd, interfaceDecl,
allMethods.data(), allMethods.size(),
allProperties.data(), allProperties.size(),
allTUVariables.data(), allTUVariables.size());
@@ -964,6 +973,12 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
// Set the default visibility to private.
if (Tok.is(tok::at)) { // parse objc-visibility-spec
ConsumeToken(); // eat the @ sign
+
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteObjCAtVisibility(CurScope);
+ ConsumeToken();
+ }
+
switch (Tok.getObjCKeywordID()) {
case tok::objc_private:
case tok::objc_public:
@@ -978,6 +993,12 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
}
}
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteOrdinaryName(CurScope,
+ Action::CCC_ObjCInstanceVariableList);
+ ConsumeToken();
+ }
+
struct ObjCIvarCallback : FieldCallback {
Parser &P;
DeclPtrTy IDecl;
@@ -1197,18 +1218,20 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
return DeclPtrTy();
}
-Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) {
+Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
assert(Tok.isObjCAtKeyword(tok::objc_end) &&
"ParseObjCAtEndDeclaration(): Expected @end");
DeclPtrTy Result = ObjCImpDecl;
ConsumeToken(); // the "end" identifier
if (ObjCImpDecl) {
- Actions.ActOnAtEnd(atLoc, ObjCImpDecl);
+ Actions.ActOnAtEnd(atEnd, ObjCImpDecl);
ObjCImpDecl = DeclPtrTy();
PendingObjCImpDecl.pop_back();
}
- else
- Diag(atLoc, diag::warn_expected_implementation); // missing @implementation
+ else {
+ // missing @implementation
+ Diag(atEnd.getBegin(), diag::warn_expected_implementation);
+ }
return Result;
}
@@ -1216,7 +1239,7 @@ Parser::DeclGroupPtrTy Parser::RetrievePendingObjCImpDecl() {
if (PendingObjCImpDecl.empty())
return Actions.ConvertDeclToDeclGroup(DeclPtrTy());
DeclPtrTy ImpDecl = PendingObjCImpDecl.pop_back_val();
- Actions.ActOnAtEnd(SourceLocation(), ImpDecl);
+ Actions.ActOnAtEnd(SourceRange(), ImpDecl);
return Actions.ConvertDeclToDeclGroup(ImpDecl);
}
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 9085b87..21e960a 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -95,7 +95,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
}
case tok::code_completion:
- Actions.CodeCompleteOrdinaryName(CurScope);
+ Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Statement);
ConsumeToken();
return ParseStatementOrDeclaration(OnlyStatement);
@@ -955,7 +955,9 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
DeclPtrTy SecondVar;
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteOrdinaryName(CurScope);
+ Actions.CodeCompleteOrdinaryName(CurScope,
+ C99orCXXorObjC? Action::CCC_ForInit
+ : Action::CCC_Expression);
ConsumeToken();
}
@@ -1182,7 +1184,7 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() {
return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, Names.data(),
move_arg(Constraints), move_arg(Exprs),
move(AsmString), move_arg(Clobbers),
- Tok.getLocation());
+ Tok.getLocation(), true);
}
/// ParseAsmStatement - Parse a GNU extended asm statement.
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 8b8af99..797c1df 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -196,7 +196,8 @@ Parser::ParseSingleDeclarationAfterTemplate(
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
DS.AddAttributes(ParseCXX0XAttributes().AttrList);
- ParseDeclarationSpecifiers(DS, TemplateInfo, AS);
+ ParseDeclarationSpecifiers(DS, TemplateInfo, AS,
+ getDeclSpecContextFromDeclaratorContext(Context));
if (Tok.is(tok::semi)) {
DeclEnd = ConsumeToken();
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 52c0153..0aecac9 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -455,7 +455,9 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr)
SingleDecl = ParseObjCMethodDefinition();
break;
case tok::code_completion:
- Actions.CodeCompleteOrdinaryName(CurScope);
+ Actions.CodeCompleteOrdinaryName(CurScope,
+ ObjCImpDecl? Action::CCC_ObjCImplementation
+ : Action::CCC_Namespace);
ConsumeToken();
return ParseExternalDeclaration(Attr);
case tok::kw_using:
@@ -541,7 +543,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS,
if (Attr)
DS.AddAttributes(Attr);
- ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_top_level);
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp
index 27a5f8b..9744496 100644
--- a/lib/Rewrite/Rewriter.cpp
+++ b/lib/Rewrite/Rewriter.cpp
@@ -97,13 +97,13 @@ int Rewriter::getRangeSize(SourceRange Range) const {
return EndOff-StartOff;
}
-/// getRewritenText - Return the rewritten form of the text in the specified
+/// getRewrittenText - Return the rewritten form of the text in the specified
/// range. If the start or end of the range was unrewritable or if they are
/// in different buffers, this returns an empty string.
///
/// Note that this method is not particularly efficient.
///
-std::string Rewriter::getRewritenText(SourceRange Range) const {
+std::string Rewriter::getRewrittenText(SourceRange Range) const {
if (!isRewritable(Range.getBegin()) ||
!isRewritable(Range.getEnd()))
return "";
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index fd3265d..5be6712 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -29,6 +29,7 @@ add_clang_library(clangSema
SemaTemplateInstantiate.cpp
SemaTemplateInstantiateDecl.cpp
SemaType.cpp
+ TargetAttributesSema.cpp
)
add_dependencies(clangSema ClangDiagnosticSema)
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index b9b85df..fbd1450 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -85,6 +85,26 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text)
case CK_Comma:
this->Text = ", ";
break;
+
+ case CK_Colon:
+ this->Text = ": ";
+ break;
+
+ case CK_SemiColon:
+ this->Text = ";";
+ break;
+
+ case CK_Equal:
+ this->Text = " = ";
+ break;
+
+ case CK_HorizontalSpace:
+ this->Text = " ";
+ break;
+
+ case CK_VerticalSpace:
+ this->Text = "\n";
+ break;
}
}
@@ -140,6 +160,11 @@ CodeCompletionString::Chunk CodeCompletionString::Chunk::Clone() const {
case CK_LeftAngle:
case CK_RightAngle:
case CK_Comma:
+ case CK_Colon:
+ case CK_SemiColon:
+ case CK_Equal:
+ case CK_HorizontalSpace:
+ case CK_VerticalSpace:
return Chunk(Kind, Text);
case CK_Optional: {
@@ -177,6 +202,11 @@ CodeCompletionString::Chunk::Destroy() {
case CK_LeftAngle:
case CK_RightAngle:
case CK_Comma:
+ case CK_Colon:
+ case CK_SemiColon:
+ case CK_Equal:
+ case CK_HorizontalSpace:
+ case CK_VerticalSpace:
break;
}
}
@@ -271,6 +301,11 @@ void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const {
case CK_LeftAngle:
case CK_RightAngle:
case CK_Comma:
+ case CK_Colon:
+ case CK_SemiColon:
+ case CK_Equal:
+ case CK_HorizontalSpace:
+ case CK_VerticalSpace:
break;
}
}
@@ -326,6 +361,11 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str,
case CK_LeftAngle:
case CK_RightAngle:
case CK_Comma:
+ case CK_Colon:
+ case CK_SemiColon:
+ case CK_Equal:
+ case CK_HorizontalSpace:
+ case CK_VerticalSpace:
Result->AddChunk(Chunk(Kind));
break;
}
@@ -386,8 +426,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
OS << "COMPLETION: ";
switch (Results[I].Kind) {
case Result::RK_Declaration:
- OS << Results[I].Declaration->getNameAsString() << " : "
- << Results[I].Rank;
+ OS << Results[I].Declaration->getNameAsString() ;
if (Results[I].Hidden)
OS << " (Hidden)";
if (CodeCompletionString *CCS
@@ -400,13 +439,13 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
break;
case Result::RK_Keyword:
- OS << Results[I].Keyword << " : " << Results[I].Rank << '\n';
+ OS << Results[I].Keyword << '\n';
break;
case Result::RK_Macro: {
- OS << Results[I].Macro->getName() << " : " << Results[I].Rank;
+ OS << Results[I].Macro->getName();
if (CodeCompletionString *CCS
- = Results[I].CreateCodeCompletionString(SemaRef)) {
+ = Results[I].CreateCodeCompletionString(SemaRef)) {
OS << " : " << CCS->getAsString();
delete CCS;
}
@@ -415,7 +454,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
}
case Result::RK_Pattern: {
- OS << "Pattern : " << Results[I].Rank << " : "
+ OS << "Pattern : "
<< Results[I].Pattern->getAsString() << '\n';
break;
}
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index 0dbf219..bff4751 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -46,22 +46,6 @@ public:
// IdDeclInfo Implementation
//===----------------------------------------------------------------------===//
-/// AddShadowed - Add a decl by putting it directly above the 'Shadow' decl.
-/// Later lookups will find the 'Shadow' decl first. The 'Shadow' decl must
-/// be already added to the scope chain and must be in the same context as
-/// the decl that we want to add.
-void IdentifierResolver::IdDeclInfo::AddShadowed(NamedDecl *D,
- NamedDecl *Shadow) {
- for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) {
- if (Shadow == *(I-1)) {
- Decls.insert(I-1, D);
- return;
- }
- }
-
- assert(0 && "Shadow wasn't in scope chain!");
-}
-
/// RemoveDecl - Remove the decl from the scope chain.
/// The decl must already be part of the decl chain.
void IdentifierResolver::IdDeclInfo::RemoveDecl(NamedDecl *D) {
@@ -160,32 +144,6 @@ void IdentifierResolver::AddDecl(NamedDecl *D) {
IDI->AddDecl(D);
}
-/// AddShadowedDecl - Link the decl to its shadowed decl chain putting it
-/// after the decl that the iterator points to, thus the 'Shadow' decl will be
-/// encountered before the 'D' decl.
-void IdentifierResolver::AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow) {
- assert(D->getDeclName() == Shadow->getDeclName() && "Different ids!");
-
- DeclarationName Name = D->getDeclName();
- void *Ptr = Name.getFETokenInfo<void>();
- assert(Ptr && "No decl from Ptr ?");
-
- IdDeclInfo *IDI;
-
- if (isDeclPtr(Ptr)) {
- Name.setFETokenInfo(NULL);
- IDI = &(*IdDeclInfos)[Name];
- NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr);
- assert(PrevD == Shadow && "Invalid shadow decl ?");
- IDI->AddDecl(D);
- IDI->AddDecl(PrevD);
- return;
- }
-
- IDI = toIdDeclInfo(Ptr);
- IDI->AddShadowed(D, Shadow);
-}
-
/// RemoveDecl - Unlink the decl from its shadowed decl chain.
/// The decl must already be part of the decl chain.
void IdentifierResolver::RemoveDecl(NamedDecl *D) {
diff --git a/lib/Sema/IdentifierResolver.h b/lib/Sema/IdentifierResolver.h
index 65f3256..59bd834 100644
--- a/lib/Sema/IdentifierResolver.h
+++ b/lib/Sema/IdentifierResolver.h
@@ -41,12 +41,6 @@ class IdentifierResolver {
void AddDecl(NamedDecl *D) { Decls.push_back(D); }
- /// AddShadowed - Add a decl by putting it directly above the 'Shadow' decl.
- /// Later lookups will find the 'Shadow' decl first. The 'Shadow' decl must
- /// be already added to the scope chain and must be in the same context as
- /// the decl that we want to add.
- void AddShadowed(NamedDecl *D, NamedDecl *Shadow);
-
/// RemoveDecl - Remove the decl from the scope chain.
/// The decl must already be part of the decl chain.
void RemoveDecl(NamedDecl *D);
@@ -163,11 +157,6 @@ public:
/// AddDecl - Link the decl to its shadowed decl chain.
void AddDecl(NamedDecl *D);
- /// AddShadowedDecl - Link the decl to its shadowed decl chain putting it
- /// after the decl that the iterator points to, thus the 'Shadow' decl will be
- /// encountered before the 'D' decl.
- void AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow);
-
/// RemoveDecl - Unlink the decl from its shadowed decl chain.
/// The decl must already be part of the decl chain.
void RemoveDecl(NamedDecl *D);
diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h
index c5eecda..9064de6 100644
--- a/lib/Sema/Lookup.h
+++ b/lib/Sema/Lookup.h
@@ -32,6 +32,11 @@ public:
/// @brief No entity found met the criteria.
NotFound = 0,
+ /// @brief No entity found met the criteria within the current
+ /// instantiation,, but there were dependent base classes of the
+ /// current instantiation that could not be searched.
+ NotFoundInCurrentInstantiation,
+
/// @brief Name lookup found a single declaration that met the
/// criteria. getFoundDecl() will return this declaration.
Found,
@@ -268,6 +273,19 @@ public:
Decls.set_size(N);
}
+ /// \brief Determine whether no result was found because we could not
+ /// search into dependent base classes of the current instantiation.
+ bool wasNotFoundInCurrentInstantiation() const {
+ return ResultKind == NotFoundInCurrentInstantiation;
+ }
+
+ /// \brief Note that while no result was found in the current instantiation,
+ /// there were dependent base classes that could not be searched.
+ void setNotFoundInCurrentInstantiation() {
+ assert(ResultKind == NotFound && Decls.empty());
+ ResultKind = NotFoundInCurrentInstantiation;
+ }
+
/// \brief Resolves the result kind of the lookup, possibly hiding
/// decls.
///
@@ -278,9 +296,10 @@ public:
/// \brief Re-resolves the result kind of the lookup after a set of
/// removals has been performed.
void resolveKindAfterFilter() {
- if (Decls.empty())
- ResultKind = NotFound;
- else {
+ if (Decls.empty()) {
+ if (ResultKind != NotFoundInCurrentInstantiation)
+ ResultKind = NotFound;
+ } else {
ResultKind = Found;
resolveKind();
}
@@ -524,7 +543,11 @@ private:
///
/// \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;
+ ///
+ /// \param InBaseClass whether this declaration was found in base
+ /// class of the context we searched.
+ virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
+ bool InBaseClass) = 0;
};
}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 40ad90a..171101b 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "TargetAttributesSema.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/APFloat.h"
#include "clang/AST/ASTConsumer.h"
@@ -109,6 +110,12 @@ static bool ShouldAKA(ASTContext &Context, QualType QT,
if (isa<VectorType>(Underlying))
break;
+ // Don't desugar through the primary typedef of an anonymous type.
+ if (isa<TagType>(Underlying) && isa<TypedefType>(QT))
+ if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() ==
+ cast<TypedefType>(QT)->getDecl())
+ break;
+
// Otherwise, we're tearing through something opaque; note that
// we'll eventually need an a.k.a. clause and keep going.
AKA = true;
@@ -347,7 +354,8 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
bool CompleteTranslationUnit,
CodeCompleteConsumer *CodeCompleter)
- : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
+ : TheTargetAttributesSema(0),
+ LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0),
CurBlock(0), PackContext(0), ParsingDeclDepth(0),
@@ -368,313 +376,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0));
}
-/// Retrieves the width and signedness of the given integer type,
-/// or returns false if it is not an integer type.
-///
-/// \param T must be canonical
-static bool getIntProperties(ASTContext &C, const Type *T,
- unsigned &BitWidth, bool &Signed) {
- assert(T->isCanonicalUnqualified());
-
- if (const VectorType *VT = dyn_cast<VectorType>(T))
- T = VT->getElementType().getTypePtr();
- if (const ComplexType *CT = dyn_cast<ComplexType>(T))
- T = CT->getElementType().getTypePtr();
-
- if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) {
- if (!BT->isInteger()) return false;
-
- BitWidth = C.getIntWidth(QualType(T, 0));
- Signed = BT->isSignedInteger();
- return true;
- }
-
- return false;
-}
-
-/// Checks whether the given value will have the same value if it it
-/// is truncated to the given width, then extended back to the
-/// original width.
-static bool IsSameIntAfterCast(const llvm::APSInt &value,
- unsigned TargetWidth) {
- unsigned SourceWidth = value.getBitWidth();
- llvm::APSInt truncated = value;
- truncated.trunc(TargetWidth);
- truncated.extend(SourceWidth);
- return (truncated == value);
-}
-
-/// Checks whether the given value will have the same value if it
-/// is truncated to the given width, then extended back to the original
-/// width.
-///
-/// The value might be a vector or a complex.
-static bool IsSameIntAfterCast(const APValue &value, unsigned TargetWidth) {
- if (value.isInt())
- return IsSameIntAfterCast(value.getInt(), TargetWidth);
-
- if (value.isVector()) {
- for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i)
- if (!IsSameIntAfterCast(value.getVectorElt(i), TargetWidth))
- return false;
- return true;
- }
-
- if (value.isComplexInt()) {
- return IsSameIntAfterCast(value.getComplexIntReal(), TargetWidth) &&
- IsSameIntAfterCast(value.getComplexIntImag(), TargetWidth);
- }
-
- // This can happen with lossless casts to intptr_t of "based" lvalues.
- // Assume it might use arbitrary bits.
- assert(value.isLValue());
- return false;
-}
-
-
-/// Checks whether the given value, which currently has the given
-/// source semantics, has the same value when coerced through the
-/// target semantics.
-static bool IsSameFloatAfterCast(const llvm::APFloat &value,
- const llvm::fltSemantics &Src,
- const llvm::fltSemantics &Tgt) {
- llvm::APFloat truncated = value;
-
- bool ignored;
- truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored);
- truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored);
-
- return truncated.bitwiseIsEqual(value);
-}
-
-/// Checks whether the given value, which currently has the given
-/// source semantics, has the same value when coerced through the
-/// target semantics.
-///
-/// The value might be a vector of floats (or a complex number).
-static bool IsSameFloatAfterCast(const APValue &value,
- const llvm::fltSemantics &Src,
- const llvm::fltSemantics &Tgt) {
- if (value.isFloat())
- return IsSameFloatAfterCast(value.getFloat(), Src, Tgt);
-
- if (value.isVector()) {
- for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i)
- if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt))
- return false;
- return true;
- }
-
- assert(value.isComplexFloat());
- return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) &&
- IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
-}
-
-/// Determines if it's reasonable for the given expression to be truncated
-/// down to the given integer width.
-/// * Boolean expressions are automatically white-listed.
-/// * Arithmetic operations on implicitly-promoted operands of the
-/// target width or less are okay --- not because the results are
-/// actually guaranteed to fit within the width, but because the
-/// user is effectively pretending that the operations are closed
-/// within the implicitly-promoted type.
-static bool IsExprValueWithinWidth(ASTContext &C, Expr *E, unsigned Width) {
- E = E->IgnoreParens();
-
-#ifndef NDEBUG
- {
- const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr();
- unsigned EWidth;
- bool ESigned;
-
- if (!getIntProperties(C, ETy, EWidth, ESigned))
- assert(0 && "expression not of integer type");
-
- // The caller should never let this happen.
- assert(EWidth > Width && "called on expr whose type is too small");
- }
-#endif
-
- // Strip implicit casts off.
- while (isa<ImplicitCastExpr>(E)) {
- E = cast<ImplicitCastExpr>(E)->getSubExpr();
-
- const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr();
-
- unsigned EWidth;
- bool ESigned;
- if (!getIntProperties(C, ETy, EWidth, ESigned))
- return false;
-
- if (EWidth <= Width)
- return true;
- }
-
- if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
- switch (BO->getOpcode()) {
-
- // Boolean-valued operations are white-listed.
- case BinaryOperator::LAnd:
- case BinaryOperator::LOr:
- case BinaryOperator::LT:
- case BinaryOperator::GT:
- case BinaryOperator::LE:
- case BinaryOperator::GE:
- case BinaryOperator::EQ:
- case BinaryOperator::NE:
- return true;
-
- // Operations with opaque sources are black-listed.
- case BinaryOperator::PtrMemD:
- case BinaryOperator::PtrMemI:
- return false;
-
- // Left shift gets black-listed based on a judgement call.
- case BinaryOperator::Shl:
- return false;
-
- // Various special cases.
- case BinaryOperator::Shr:
- return IsExprValueWithinWidth(C, BO->getLHS(), Width);
- case BinaryOperator::Comma:
- return IsExprValueWithinWidth(C, BO->getRHS(), Width);
- case BinaryOperator::Sub:
- if (BO->getLHS()->getType()->isPointerType())
- return false;
- // fallthrough
-
- // Any other operator is okay if the operands are
- // promoted from expressions of appropriate size.
- default:
- return IsExprValueWithinWidth(C, BO->getLHS(), Width) &&
- IsExprValueWithinWidth(C, BO->getRHS(), Width);
- }
- }
-
- if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
- switch (UO->getOpcode()) {
- // Boolean-valued operations are white-listed.
- case UnaryOperator::LNot:
- return true;
-
- // Operations with opaque sources are black-listed.
- case UnaryOperator::Deref:
- case UnaryOperator::AddrOf: // should be impossible
- return false;
-
- case UnaryOperator::OffsetOf:
- return false;
-
- default:
- return IsExprValueWithinWidth(C, UO->getSubExpr(), Width);
- }
- }
-
- // Don't diagnose if the expression is an integer constant
- // whose value in the target type is the same as it was
- // in the original type.
- Expr::EvalResult result;
- if (E->Evaluate(result, C))
- if (IsSameIntAfterCast(result.Val, Width))
- return true;
-
- return false;
-}
-
-/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
-static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) {
- S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange();
-}
-
-/// Implements -Wconversion.
-static void CheckImplicitConversion(Sema &S, Expr *E, QualType T) {
- // Don't diagnose in unevaluated contexts.
- if (S.ExprEvalContexts.back().Context == Sema::Unevaluated)
- return;
-
- // Don't diagnose for value-dependent expressions.
- if (E->isValueDependent())
- return;
-
- const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr();
- const Type *Target = S.Context.getCanonicalType(T).getTypePtr();
-
- // Never diagnose implicit casts to bool.
- if (Target->isSpecificBuiltinType(BuiltinType::Bool))
- return;
-
- // Strip vector types.
- if (isa<VectorType>(Source)) {
- if (!isa<VectorType>(Target))
- return DiagnoseImpCast(S, E, T, diag::warn_impcast_vector_scalar);
-
- Source = cast<VectorType>(Source)->getElementType().getTypePtr();
- Target = cast<VectorType>(Target)->getElementType().getTypePtr();
- }
-
- // Strip complex types.
- if (isa<ComplexType>(Source)) {
- if (!isa<ComplexType>(Target))
- return DiagnoseImpCast(S, E, T, diag::warn_impcast_complex_scalar);
-
- Source = cast<ComplexType>(Source)->getElementType().getTypePtr();
- Target = cast<ComplexType>(Target)->getElementType().getTypePtr();
- }
-
- const BuiltinType *SourceBT = dyn_cast<BuiltinType>(Source);
- const BuiltinType *TargetBT = dyn_cast<BuiltinType>(Target);
-
- // If the source is floating point...
- if (SourceBT && SourceBT->isFloatingPoint()) {
- // ...and the target is floating point...
- if (TargetBT && TargetBT->isFloatingPoint()) {
- // ...then warn if we're dropping FP rank.
-
- // Builtin FP kinds are ordered by increasing FP rank.
- if (SourceBT->getKind() > TargetBT->getKind()) {
- // Don't warn about float constants that are precisely
- // representable in the target type.
- Expr::EvalResult result;
- if (E->Evaluate(result, S.Context)) {
- // Value might be a float, a float vector, or a float complex.
- if (IsSameFloatAfterCast(result.Val,
- S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)),
- S.Context.getFloatTypeSemantics(QualType(SourceBT, 0))))
- return;
- }
-
- DiagnoseImpCast(S, E, T, diag::warn_impcast_float_precision);
- }
- return;
- }
-
- // If the target is integral, always warn.
- if ((TargetBT && TargetBT->isInteger()))
- // TODO: don't warn for integer values?
- return DiagnoseImpCast(S, E, T, diag::warn_impcast_float_integer);
-
- return;
- }
-
- unsigned SourceWidth, TargetWidth;
- bool SourceSigned, TargetSigned;
-
- if (!getIntProperties(S.Context, Source, SourceWidth, SourceSigned) ||
- !getIntProperties(S.Context, Target, TargetWidth, TargetSigned))
- return;
-
- if (SourceWidth > TargetWidth) {
- if (IsExprValueWithinWidth(S.Context, E, TargetWidth))
- return;
-
- // People want to build with -Wshorten-64-to-32 and not -Wconversion
- // and by god we'll let them.
- if (SourceWidth == 64 && TargetWidth == 32)
- return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_64_32);
- return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_precision);
- }
-
- return;
+Sema::~Sema() {
+ if (PackContext) FreePackedContext();
+ delete TheTargetAttributesSema;
}
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
@@ -697,7 +401,7 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,
}
}
- CheckImplicitConversion(*this, Expr, Ty);
+ CheckImplicitConversion(Expr, Ty);
if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
if (ImpCast->getCastKind() == Kind) {
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 4cecee4..fab7292 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -42,6 +42,7 @@ namespace llvm {
}
namespace clang {
+ class AnalysisContext;
class ASTContext;
class ASTConsumer;
class CodeCompleteConsumer;
@@ -101,6 +102,7 @@ namespace clang {
class InitializationKind;
class InitializationSequence;
class VisibleDeclConsumer;
+ class TargetAttributesSema;
/// BlockSemaInfo - When a block is being parsed, this contains information
/// about the block. It is pointed to from Sema::CurBlock.
@@ -176,6 +178,7 @@ public:
class Sema : public Action {
Sema(const Sema&); // DO NOT IMPLEMENT
void operator=(const Sema&); // DO NOT IMPLEMENT
+ mutable const TargetAttributesSema* TheTargetAttributesSema;
public:
const LangOptions &LangOpts;
Preprocessor &PP;
@@ -426,13 +429,12 @@ public:
Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
bool CompleteTranslationUnit = true,
CodeCompleteConsumer *CompletionConsumer = 0);
- ~Sema() {
- if (PackContext) FreePackedContext();
- }
+ ~Sema();
const LangOptions &getLangOptions() const { return LangOpts; }
Diagnostic &getDiagnostics() const { return Diags; }
SourceManager &getSourceManager() const { return SourceMgr; }
+ const TargetAttributesSema &getTargetAttributesSema() const;
/// \brief Helper class that creates diagnostics with optional
/// template instantiation stacks.
@@ -561,8 +563,6 @@ public:
const FunctionProtoType *Target, SourceLocation TargetLoc,
const FunctionProtoType *Source, SourceLocation SourceLoc);
- QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D);
-
bool UnwrapSimilarPointerTypes(QualType& T1, QualType& T2);
virtual TypeResult ActOnTypeName(Scope *S, Declarator &D);
@@ -1030,10 +1030,25 @@ public:
OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet,
SourceLocation Loc,
OverloadCandidateSet::iterator& Best);
+
+ enum OverloadCandidateDisplayKind {
+ /// Requests that all candidates be shown. Viable candidates will
+ /// be printed first.
+ OCD_AllCandidates,
+
+ /// Requests that only viable candidates be shown.
+ OCD_ViableCandidates
+ };
void PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
- bool OnlyViable,
- const char *Opc=0,
- SourceLocation Loc=SourceLocation());
+ OverloadCandidateDisplayKind OCD,
+ Expr **Args, unsigned NumArgs,
+ const char *Opc = 0,
+ SourceLocation Loc = SourceLocation());
+
+ void NoteOverloadCandidate(FunctionDecl *Fn);
+ void DiagnoseAmbiguousConversion(const ImplicitConversionSequence &ICS,
+ SourceLocation CaretLoc,
+ const PartialDiagnostic &PDiag);
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
bool Complain);
@@ -1083,6 +1098,9 @@ public:
OwningExprResult BuildOverloadedArrowExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc);
+ /// CheckUnreachable - Check for unreachable code.
+ void CheckUnreachable(AnalysisContext &);
+
/// CheckCallReturnType - Checks that a call expression's return type is
/// complete. Returns true on failure. The location passed in is the location
/// that best represents the call.
@@ -1090,14 +1108,14 @@ public:
CallExpr *CE, FunctionDecl *FD);
/// Helpers for dealing with blocks and functions.
- void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body);
- void CheckFallThroughForBlock(QualType BlockTy, Stmt *Body);
+ void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, AnalysisContext &);
+ void CheckFallThroughForBlock(QualType BlockTy, Stmt *, AnalysisContext &);
bool CheckParmsForFunctionDef(FunctionDecl *FD);
void CheckCXXDefaultArguments(FunctionDecl *FD);
void CheckExtraCXXDefaultArguments(Declarator &D);
enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1,
AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 };
- ControlFlowKind CheckFallThrough(Stmt *);
+ ControlFlowKind CheckFallThrough(AnalysisContext &);
Scope *getNonFieldDeclScope(Scope *S);
@@ -1168,8 +1186,14 @@ public:
LookupObjCImplementationName
};
+ /// \brief Specifies whether (or how) name lookup is being performed for a
+ /// redeclaration (vs. a reference).
enum RedeclarationKind {
- NotForRedeclaration,
+ /// \brief The lookup is a reference to this name that is not for the
+ /// purpose of redeclaring the name.
+ NotForRedeclaration = 0,
+ /// \brief The lookup results will be used for redeclaration of a name,
+ /// if an entity by that name already exists.
ForRedeclaration
};
@@ -1188,7 +1212,8 @@ public:
= NotForRedeclaration);
bool LookupName(LookupResult &R, Scope *S,
bool AllowBuiltinCreation = false);
- bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx);
+ bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
+ bool InUnqualifiedLookup = false);
bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
bool AllowBuiltinCreation = false,
bool EnteringContext = false);
@@ -1210,7 +1235,8 @@ public:
bool CorrectTypo(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
DeclContext *MemberContext = 0,
- bool EnteringContext = false);
+ bool EnteringContext = false,
+ const ObjCObjectPointerType *OPT = 0);
void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
AssociatedNamespaceSet &AssociatedNamespaces,
@@ -1219,7 +1245,8 @@ public:
bool DiagnoseAmbiguousLookup(LookupResult &Result);
//@}
- ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id);
+ ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id,
+ SourceLocation RecoverLoc = SourceLocation());
NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
Scope *S, bool ForRedeclaration,
SourceLocation Loc);
@@ -1383,7 +1410,8 @@ public:
MultiExprArg Exprs,
ExprArg AsmString,
MultiExprArg Clobbers,
- SourceLocation RParenLoc);
+ SourceLocation RParenLoc,
+ bool MSAsm = false);
virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
SourceLocation RParen,
@@ -1437,10 +1465,6 @@ public:
void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
Expr **Args, unsigned NumArgs);
- void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc,
- const PartialDiagnostic &PD,
- bool Equality = false);
-
virtual void
PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext);
@@ -1462,7 +1486,8 @@ public:
OwningExprResult LookupInObjCMethod(LookupResult &R,
Scope *S,
- IdentifierInfo *II);
+ IdentifierInfo *II,
+ bool AllowBuiltinCreation=false);
OwningExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS,
DeclarationName Name,
@@ -1571,13 +1596,13 @@ public:
QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs);
OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base,
bool &IsArrow, SourceLocation OpLoc,
const CXXScopeSpec &SS,
- NamedDecl *FirstQualifierInScope,
DeclPtrTy ObjCImpDecl);
bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType,
@@ -2008,6 +2033,7 @@ public:
bool isDependentScopeSpecifier(const CXXScopeSpec &SS);
CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS);
bool isUnknownSpecialization(const CXXScopeSpec &SS);
+ bool isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS);
/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
/// global scope ('::').
@@ -2175,11 +2201,11 @@ public:
void MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor);
/// ClassesWithUnmarkedVirtualMembers - Contains record decls whose virtual
- /// members might need to be marked as referenced. This is either done when
- /// the key function definition is emitted (this is handled by by
- /// MaybeMarkVirtualMembersReferenced), or at the end of the translation unit
- /// (done by ProcessPendingClassesWithUnmarkedVirtualMembers).
- std::map<CXXRecordDecl *, SourceLocation> ClassesWithUnmarkedVirtualMembers;
+ /// members need to be marked as referenced at the end of the translation
+ /// unit. It will contain polymorphic classes that do not have a key
+ /// function or have a key function that has been defined.
+ llvm::SmallVector<std::pair<CXXRecordDecl *, SourceLocation>, 4>
+ ClassesWithUnmarkedVirtualMembers;
/// MaybeMarkVirtualMembersReferenced - If the passed in method is the
/// key function of the record decl, will mark virtual member functions as
@@ -2236,8 +2262,6 @@ public:
void CheckConversionDeclarator(Declarator &D, QualType &R,
FunctionDecl::StorageClass& SC);
DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion);
-
- bool isImplicitMemberReference(const LookupResult &R, QualType &ThisType);
//===--------------------------------------------------------------------===//
// C++ Derived Classes
@@ -2338,6 +2362,8 @@ public:
bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl);
+ bool CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl);
+
//===--------------------------------------------------------------------===//
// C++ Templates [C++ 14]
//
@@ -2350,6 +2376,14 @@ public:
TypeTy *ObjectType,
bool EnteringContext,
TemplateTy &Template);
+
+ virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
+ SourceLocation IILoc,
+ Scope *S,
+ const CXXScopeSpec *SS,
+ TemplateTy &SuggestedTemplate,
+ TemplateNameKind &SuggestedKind);
+
bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl);
@@ -3348,10 +3382,11 @@ public:
void MergeOneProtocolPropertiesIntoClass(Decl *CDecl,
ObjCProtocolDecl *PDecl);
- virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
- DeclPtrTy *allMethods = 0, unsigned allNum = 0,
- DeclPtrTy *allProperties = 0, unsigned pNum = 0,
- DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0);
+ virtual void ActOnAtEnd(SourceRange AtEnd,
+ DeclPtrTy classDecl,
+ DeclPtrTy *allMethods = 0, unsigned allNum = 0,
+ DeclPtrTy *allProperties = 0, unsigned pNum = 0,
+ DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0);
virtual DeclPtrTy ActOnProperty(Scope *S, SourceLocation AtLoc,
FieldDeclarator &FD, ObjCDeclSpec &ODS,
@@ -3617,9 +3652,6 @@ public:
bool PerformImplicitConversion(Expr *&From, QualType ToType,
const StandardConversionSequence& SCS,
AssignmentAction Action, bool IgnoreBaseAccess);
-
- bool BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind,
- const ImplicitConversionSequence& ICS);
/// the following "Check" methods will return a valid/converted QualType
/// or a null QualType (indicating an error diagnostic was issued).
@@ -3629,7 +3661,8 @@ public:
QualType CheckPointerToMemberOperands( // C++ 5.5
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isIndirect);
QualType CheckMultiplyDivideOperands( // C99 6.5.5
- Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign,
+ bool isDivide);
QualType CheckRemainderOperands( // C99 6.5.5
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
QualType CheckAdditionOperands( // C99 6.5.6
@@ -3801,7 +3834,8 @@ public:
/// \name Code completion
//@{
- virtual void CodeCompleteOrdinaryName(Scope *S);
+ virtual void CodeCompleteOrdinaryName(Scope *S,
+ CodeCompletionContext CompletionContext);
virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base,
SourceLocation OpLoc,
bool IsArrow);
@@ -3819,6 +3853,7 @@ public:
virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl,
bool InInterface);
+ virtual void CodeCompleteObjCAtVisibility(Scope *S);
virtual void CodeCompleteObjCAtStatement(Scope *S);
virtual void CodeCompleteObjCAtExpression(Scope *S);
virtual void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS);
@@ -3895,6 +3930,11 @@ private:
void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc);
void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
+ void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc,
+ const PartialDiagnostic &PD,
+ bool Equality = false);
+ void CheckImplicitConversion(Expr *E, QualType Target);
+
};
//===--------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 800c544..f924bd3 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -893,7 +893,7 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
/*InOverloadResolution=*/false,
/*one of user provided casts*/true);
- if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion)
+ if (ICS.isBad())
return TC_NotApplicable;
// The conversion is possible, so commit to it.
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 82d58ea..8594583 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -210,6 +210,28 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) {
return getCurrentInstantiationOf(NNS) == 0;
}
+/// \brief Determine whether the given scope specifier refers to a
+/// current instantiation that has any dependent base clases.
+///
+/// This check is typically used when we've performed lookup into the
+/// current instantiation of a template, but that lookup failed. When
+/// there are dependent bases present, however, the lookup needs to be
+/// delayed until template instantiation time.
+bool Sema::isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS) {
+ if (!SS.isSet())
+ return false;
+
+ NestedNameSpecifier *NNS = (NestedNameSpecifier*)SS.getScopeRep();
+ if (!NNS->isDependent())
+ return false;
+
+ CXXRecordDecl *CurrentInstantiation = getCurrentInstantiationOf(NNS);
+ if (!CurrentInstantiation)
+ return false;
+
+ return CurrentInstantiation->hasAnyDependentBases();
+}
+
/// \brief If the given nested name specifier refers to the current
/// instantiation, return the declaration that corresponds to that
/// current instantiation (C++0x [temp.dep.type]p1).
@@ -446,6 +468,10 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
<< Name << Found.getLookupName()
<< CodeModificationHint::CreateReplacement(Found.getNameLoc(),
Found.getLookupName().getAsString());
+
+ if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
+ Diag(ND->getLocation(), diag::note_previous_decl)
+ << ND->getDeclName();
} else
Found.clear();
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index f10fa07..5f124e4 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -14,6 +14,7 @@
#include "Sema.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
@@ -318,7 +319,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
// Determine the index of the size.
unsigned SizeIndex;
- switch (Context.getTypeSize(ValType)/8) {
+ switch (Context.getTypeSizeInChars(ValType).getQuantity()) {
case 1: SizeIndex = 0; break;
case 2: SizeIndex = 1; break;
case 4: SizeIndex = 2; break;
@@ -966,9 +967,6 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
///
/// (8) Check that the format string is a wide literal.
///
-/// (9) Also check the arguments of functions with the __format__ attribute.
-/// (TODO).
-///
/// All of these checks can be done by parsing the format string.
///
/// For now, we ONLY do (1), (3), (5), (6), (7), and (8).
@@ -1559,3 +1557,475 @@ void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) {
Diag(loc, diag::warn_floatingpoint_eq)
<< lex->getSourceRange() << rex->getSourceRange();
}
+
+//===--- CHECK: Integer mixed-sign comparisons (-Wsign-compare) --------===//
+//===--- CHECK: Lossy implicit conversions (-Wconversion) --------------===//
+
+namespace {
+
+/// Structure recording the 'active' range of an integer-valued
+/// expression.
+struct IntRange {
+ /// The number of bits active in the int.
+ unsigned Width;
+
+ /// True if the int is known not to have negative values.
+ bool NonNegative;
+
+ IntRange() {}
+ IntRange(unsigned Width, bool NonNegative)
+ : Width(Width), NonNegative(NonNegative)
+ {}
+
+ // Returns the range of the bool type.
+ static IntRange forBoolType() {
+ return IntRange(1, true);
+ }
+
+ // Returns the range of an integral type.
+ static IntRange forType(ASTContext &C, QualType T) {
+ return forCanonicalType(C, T->getCanonicalTypeInternal().getTypePtr());
+ }
+
+ // Returns the range of an integeral type based on its canonical
+ // representation.
+ static IntRange forCanonicalType(ASTContext &C, const Type *T) {
+ assert(T->isCanonicalUnqualified());
+
+ if (const VectorType *VT = dyn_cast<VectorType>(T))
+ T = VT->getElementType().getTypePtr();
+ if (const ComplexType *CT = dyn_cast<ComplexType>(T))
+ T = CT->getElementType().getTypePtr();
+ if (const EnumType *ET = dyn_cast<EnumType>(T))
+ T = ET->getDecl()->getIntegerType().getTypePtr();
+
+ const BuiltinType *BT = cast<BuiltinType>(T);
+ assert(BT->isInteger());
+
+ return IntRange(C.getIntWidth(QualType(T, 0)), BT->isUnsignedInteger());
+ }
+
+ // Returns the supremum of two ranges: i.e. their conservative merge.
+ static IntRange join(const IntRange &L, const IntRange &R) {
+ return IntRange(std::max(L.Width, R.Width),
+ L.NonNegative && R.NonNegative);
+ }
+
+ // Returns the infinum of two ranges: i.e. their aggressive merge.
+ static IntRange meet(const IntRange &L, const IntRange &R) {
+ return IntRange(std::min(L.Width, R.Width),
+ L.NonNegative || R.NonNegative);
+ }
+};
+
+IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) {
+ if (value.isSigned() && value.isNegative())
+ return IntRange(value.getMinSignedBits(), false);
+
+ if (value.getBitWidth() > MaxWidth)
+ value.trunc(MaxWidth);
+
+ // isNonNegative() just checks the sign bit without considering
+ // signedness.
+ return IntRange(value.getActiveBits(), true);
+}
+
+IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty,
+ unsigned MaxWidth) {
+ if (result.isInt())
+ return GetValueRange(C, result.getInt(), MaxWidth);
+
+ if (result.isVector()) {
+ IntRange R = GetValueRange(C, result.getVectorElt(0), Ty, MaxWidth);
+ for (unsigned i = 1, e = result.getVectorLength(); i != e; ++i) {
+ IntRange El = GetValueRange(C, result.getVectorElt(i), Ty, MaxWidth);
+ R = IntRange::join(R, El);
+ }
+ return R;
+ }
+
+ if (result.isComplexInt()) {
+ IntRange R = GetValueRange(C, result.getComplexIntReal(), MaxWidth);
+ IntRange I = GetValueRange(C, result.getComplexIntImag(), MaxWidth);
+ return IntRange::join(R, I);
+ }
+
+ // This can happen with lossless casts to intptr_t of "based" lvalues.
+ // Assume it might use arbitrary bits.
+ // FIXME: The only reason we need to pass the type in here is to get
+ // the sign right on this one case. It would be nice if APValue
+ // preserved this.
+ assert(result.isLValue());
+ return IntRange(MaxWidth, Ty->isUnsignedIntegerType());
+}
+
+/// Pseudo-evaluate the given integer expression, estimating the
+/// range of values it might take.
+///
+/// \param MaxWidth - the width to which the value will be truncated
+IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
+ E = E->IgnoreParens();
+
+ // Try a full evaluation first.
+ Expr::EvalResult result;
+ if (E->Evaluate(result, C))
+ return GetValueRange(C, result.Val, E->getType(), MaxWidth);
+
+ // I think we only want to look through implicit casts here; if the
+ // user has an explicit widening cast, we should treat the value as
+ // being of the new, wider type.
+ if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) {
+ if (CE->getCastKind() == CastExpr::CK_NoOp)
+ return GetExprRange(C, CE->getSubExpr(), MaxWidth);
+
+ IntRange OutputTypeRange = IntRange::forType(C, CE->getType());
+
+ bool isIntegerCast = (CE->getCastKind() == CastExpr::CK_IntegralCast);
+ if (!isIntegerCast && CE->getCastKind() == CastExpr::CK_Unknown)
+ isIntegerCast = CE->getSubExpr()->getType()->isIntegerType();
+
+ // Assume that non-integer casts can span the full range of the type.
+ if (!isIntegerCast)
+ return OutputTypeRange;
+
+ IntRange SubRange
+ = GetExprRange(C, CE->getSubExpr(),
+ std::min(MaxWidth, OutputTypeRange.Width));
+
+ // Bail out if the subexpr's range is as wide as the cast type.
+ if (SubRange.Width >= OutputTypeRange.Width)
+ return OutputTypeRange;
+
+ // Otherwise, we take the smaller width, and we're non-negative if
+ // either the output type or the subexpr is.
+ return IntRange(SubRange.Width,
+ SubRange.NonNegative || OutputTypeRange.NonNegative);
+ }
+
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ // If we can fold the condition, just take that operand.
+ bool CondResult;
+ if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C))
+ return GetExprRange(C, CondResult ? CO->getTrueExpr()
+ : CO->getFalseExpr(),
+ MaxWidth);
+
+ // Otherwise, conservatively merge.
+ IntRange L = GetExprRange(C, CO->getTrueExpr(), MaxWidth);
+ IntRange R = GetExprRange(C, CO->getFalseExpr(), MaxWidth);
+ return IntRange::join(L, R);
+ }
+
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ switch (BO->getOpcode()) {
+
+ // Boolean-valued operations are single-bit and positive.
+ case BinaryOperator::LAnd:
+ case BinaryOperator::LOr:
+ case BinaryOperator::LT:
+ case BinaryOperator::GT:
+ case BinaryOperator::LE:
+ case BinaryOperator::GE:
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ return IntRange::forBoolType();
+
+ // Operations with opaque sources are black-listed.
+ case BinaryOperator::PtrMemD:
+ case BinaryOperator::PtrMemI:
+ return IntRange::forType(C, E->getType());
+
+ // Bitwise-and uses the *infinum* of the two source ranges.
+ case BinaryOperator::And:
+ return IntRange::meet(GetExprRange(C, BO->getLHS(), MaxWidth),
+ GetExprRange(C, BO->getRHS(), MaxWidth));
+
+ // Left shift gets black-listed based on a judgement call.
+ case BinaryOperator::Shl:
+ return IntRange::forType(C, E->getType());
+
+ // Right shift by a constant can narrow its left argument.
+ case BinaryOperator::Shr: {
+ IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth);
+
+ // If the shift amount is a positive constant, drop the width by
+ // that much.
+ llvm::APSInt shift;
+ if (BO->getRHS()->isIntegerConstantExpr(shift, C) &&
+ shift.isNonNegative()) {
+ unsigned zext = shift.getZExtValue();
+ if (zext >= L.Width)
+ L.Width = (L.NonNegative ? 0 : 1);
+ else
+ L.Width -= zext;
+ }
+
+ return L;
+ }
+
+ // Comma acts as its right operand.
+ case BinaryOperator::Comma:
+ return GetExprRange(C, BO->getRHS(), MaxWidth);
+
+ // Black-list pointer subtractions.
+ case BinaryOperator::Sub:
+ if (BO->getLHS()->getType()->isPointerType())
+ return IntRange::forType(C, E->getType());
+ // fallthrough
+
+ default:
+ break;
+ }
+
+ // Treat every other operator as if it were closed on the
+ // narrowest type that encompasses both operands.
+ IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth);
+ IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth);
+ return IntRange::join(L, R);
+ }
+
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ switch (UO->getOpcode()) {
+ // Boolean-valued operations are white-listed.
+ case UnaryOperator::LNot:
+ return IntRange::forBoolType();
+
+ // Operations with opaque sources are black-listed.
+ case UnaryOperator::Deref:
+ case UnaryOperator::AddrOf: // should be impossible
+ case UnaryOperator::OffsetOf:
+ return IntRange::forType(C, E->getType());
+
+ default:
+ return GetExprRange(C, UO->getSubExpr(), MaxWidth);
+ }
+ }
+
+ FieldDecl *BitField = E->getBitField();
+ if (BitField) {
+ llvm::APSInt BitWidthAP = BitField->getBitWidth()->EvaluateAsInt(C);
+ unsigned BitWidth = BitWidthAP.getZExtValue();
+
+ return IntRange(BitWidth, BitField->getType()->isUnsignedIntegerType());
+ }
+
+ return IntRange::forType(C, E->getType());
+}
+
+/// Checks whether the given value, which currently has the given
+/// source semantics, has the same value when coerced through the
+/// target semantics.
+bool IsSameFloatAfterCast(const llvm::APFloat &value,
+ const llvm::fltSemantics &Src,
+ const llvm::fltSemantics &Tgt) {
+ llvm::APFloat truncated = value;
+
+ bool ignored;
+ truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored);
+ truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored);
+
+ return truncated.bitwiseIsEqual(value);
+}
+
+/// Checks whether the given value, which currently has the given
+/// source semantics, has the same value when coerced through the
+/// target semantics.
+///
+/// The value might be a vector of floats (or a complex number).
+bool IsSameFloatAfterCast(const APValue &value,
+ const llvm::fltSemantics &Src,
+ const llvm::fltSemantics &Tgt) {
+ if (value.isFloat())
+ return IsSameFloatAfterCast(value.getFloat(), Src, Tgt);
+
+ if (value.isVector()) {
+ for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i)
+ if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt))
+ return false;
+ return true;
+ }
+
+ assert(value.isComplexFloat());
+ return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) &&
+ IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
+}
+
+} // end anonymous namespace
+
+/// \brief Implements -Wsign-compare.
+///
+/// \param lex the left-hand expression
+/// \param rex the right-hand expression
+/// \param OpLoc the location of the joining operator
+/// \param Equality whether this is an "equality-like" join, which
+/// suppresses the warning in some cases
+void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc,
+ const PartialDiagnostic &PD, bool Equality) {
+ // Don't warn if we're in an unevaluated context.
+ if (ExprEvalContexts.back().Context == Unevaluated)
+ return;
+
+ // If either expression is value-dependent, don't warn. We'll get another
+ // chance at instantiation time.
+ if (lex->isValueDependent() || rex->isValueDependent())
+ return;
+
+ QualType lt = lex->getType(), rt = rex->getType();
+
+ // Only warn if both operands are integral.
+ if (!lt->isIntegerType() || !rt->isIntegerType())
+ return;
+
+ // In C, the width of a bitfield determines its type, and the
+ // declared type only contributes the signedness. This duplicates
+ // the work that will later be done by UsualUnaryConversions.
+ // Eventually, this check will be reorganized in a way that avoids
+ // this duplication.
+ if (!getLangOptions().CPlusPlus) {
+ QualType tmp;
+ tmp = Context.isPromotableBitField(lex);
+ if (!tmp.isNull()) lt = tmp;
+ tmp = Context.isPromotableBitField(rex);
+ if (!tmp.isNull()) rt = tmp;
+ }
+
+ // The rule is that the signed operand becomes unsigned, so isolate the
+ // signed operand.
+ Expr *signedOperand = lex, *unsignedOperand = rex;
+ QualType signedType = lt, unsignedType = rt;
+ if (lt->isSignedIntegerType()) {
+ if (rt->isSignedIntegerType()) return;
+ } else {
+ if (!rt->isSignedIntegerType()) return;
+ std::swap(signedOperand, unsignedOperand);
+ std::swap(signedType, unsignedType);
+ }
+
+ unsigned unsignedWidth = Context.getIntWidth(unsignedType);
+ unsigned signedWidth = Context.getIntWidth(signedType);
+
+ // If the unsigned type is strictly smaller than the signed type,
+ // then (1) the result type will be signed and (2) the unsigned
+ // value will fit fully within the signed type, and thus the result
+ // of the comparison will be exact.
+ if (signedWidth > unsignedWidth)
+ return;
+
+ // Otherwise, calculate the effective ranges.
+ IntRange signedRange = GetExprRange(Context, signedOperand, signedWidth);
+ IntRange unsignedRange = GetExprRange(Context, unsignedOperand, unsignedWidth);
+
+ // We should never be unable to prove that the unsigned operand is
+ // non-negative.
+ assert(unsignedRange.NonNegative && "unsigned range includes negative?");
+
+ // If the signed operand is non-negative, then the signed->unsigned
+ // conversion won't change it.
+ if (signedRange.NonNegative)
+ return;
+
+ // For (in)equality comparisons, if the unsigned operand is a
+ // constant which cannot collide with a overflowed signed operand,
+ // then reinterpreting the signed operand as unsigned will not
+ // change the result of the comparison.
+ if (Equality && unsignedRange.Width < unsignedWidth)
+ return;
+
+ Diag(OpLoc, PD)
+ << lt << rt << lex->getSourceRange() << rex->getSourceRange();
+}
+
+/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
+static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) {
+ S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange();
+}
+
+/// Implements -Wconversion.
+void Sema::CheckImplicitConversion(Expr *E, QualType T) {
+ // Don't diagnose in unevaluated contexts.
+ if (ExprEvalContexts.back().Context == Sema::Unevaluated)
+ return;
+
+ // Don't diagnose for value-dependent expressions.
+ if (E->isValueDependent())
+ return;
+
+ const Type *Source = Context.getCanonicalType(E->getType()).getTypePtr();
+ const Type *Target = Context.getCanonicalType(T).getTypePtr();
+
+ // Never diagnose implicit casts to bool.
+ if (Target->isSpecificBuiltinType(BuiltinType::Bool))
+ return;
+
+ // Strip vector types.
+ if (isa<VectorType>(Source)) {
+ if (!isa<VectorType>(Target))
+ return DiagnoseImpCast(*this, E, T, diag::warn_impcast_vector_scalar);
+
+ Source = cast<VectorType>(Source)->getElementType().getTypePtr();
+ Target = cast<VectorType>(Target)->getElementType().getTypePtr();
+ }
+
+ // Strip complex types.
+ if (isa<ComplexType>(Source)) {
+ if (!isa<ComplexType>(Target))
+ return DiagnoseImpCast(*this, E, T, diag::warn_impcast_complex_scalar);
+
+ Source = cast<ComplexType>(Source)->getElementType().getTypePtr();
+ Target = cast<ComplexType>(Target)->getElementType().getTypePtr();
+ }
+
+ const BuiltinType *SourceBT = dyn_cast<BuiltinType>(Source);
+ const BuiltinType *TargetBT = dyn_cast<BuiltinType>(Target);
+
+ // If the source is floating point...
+ if (SourceBT && SourceBT->isFloatingPoint()) {
+ // ...and the target is floating point...
+ if (TargetBT && TargetBT->isFloatingPoint()) {
+ // ...then warn if we're dropping FP rank.
+
+ // Builtin FP kinds are ordered by increasing FP rank.
+ if (SourceBT->getKind() > TargetBT->getKind()) {
+ // Don't warn about float constants that are precisely
+ // representable in the target type.
+ Expr::EvalResult result;
+ if (E->Evaluate(result, Context)) {
+ // Value might be a float, a float vector, or a float complex.
+ if (IsSameFloatAfterCast(result.Val,
+ Context.getFloatTypeSemantics(QualType(TargetBT, 0)),
+ Context.getFloatTypeSemantics(QualType(SourceBT, 0))))
+ return;
+ }
+
+ DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_precision);
+ }
+ return;
+ }
+
+ // If the target is integral, always warn.
+ if ((TargetBT && TargetBT->isInteger()))
+ // TODO: don't warn for integer values?
+ return DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_integer);
+
+ return;
+ }
+
+ if (!Source->isIntegerType() || !Target->isIntegerType())
+ return;
+
+ IntRange SourceRange = GetExprRange(Context, E, Context.getIntWidth(E->getType()));
+ IntRange TargetRange = IntRange::forCanonicalType(Context, Target);
+
+ // FIXME: also signed<->unsigned?
+
+ if (SourceRange.Width > TargetRange.Width) {
+ // People want to build with -Wshorten-64-to-32 and not -Wconversion
+ // and by god we'll let them.
+ if (SourceRange.Width == 64 && TargetRange.Width == 32)
+ return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_64_32);
+ return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_precision);
+ }
+
+ return;
+}
+
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index ef82a94..a4cda01 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
@@ -111,14 +112,18 @@ namespace {
/// \brief If non-NULL, a filter function used to remove any code-completion
/// results that are not desirable.
LookupFilter Filter;
-
+
+ /// \brief Whether we should allow declarations as
+ /// nested-name-specifiers that would otherwise be filtered out.
+ bool AllowNestedNameSpecifiers;
+
/// \brief A list of shadow maps, which is used to model name hiding at
/// different levels of, e.g., the inheritance hierarchy.
std::list<ShadowMap> ShadowMaps;
public:
explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0)
- : SemaRef(SemaRef), Filter(Filter) { }
+ : SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false) { }
/// \brief Set the filter used for code-completion results.
void setFilter(LookupFilter Filter) {
@@ -133,15 +138,55 @@ namespace {
unsigned size() const { return Results.size(); }
bool empty() const { return Results.empty(); }
+ /// \brief Specify whether nested-name-specifiers are allowed.
+ void allowNestedNameSpecifiers(bool Allow = true) {
+ AllowNestedNameSpecifiers = Allow;
+ }
+
+ /// \brief Determine whether the given declaration is at all interesting
+ /// as a code-completion result.
+ ///
+ /// \param ND the declaration that we are inspecting.
+ ///
+ /// \param AsNestedNameSpecifier will be set true if this declaration is
+ /// only interesting when it is a nested-name-specifier.
+ bool isInterestingDecl(NamedDecl *ND, bool &AsNestedNameSpecifier) const;
+
+ /// \brief Check whether the result is hidden by the Hiding declaration.
+ ///
+ /// \returns true if the result is hidden and cannot be found, false if
+ /// the hidden result could still be found. When false, \p R may be
+ /// modified to describe how the result can be found (e.g., via extra
+ /// qualification).
+ bool CheckHiddenResult(Result &R, DeclContext *CurContext,
+ NamedDecl *Hiding);
+
/// \brief Add a new result to this result set (if it isn't already in one
/// of the shadow maps), or replace an existing result (for, e.g., a
/// redeclaration).
///
- /// \param R the result to add (if it is unique).
+ /// \param CurContext the result to add (if it is unique).
///
/// \param R the context in which this result will be named.
void MaybeAddResult(Result R, DeclContext *CurContext = 0);
+ /// \brief Add a new result to this result set, where we already know
+ /// the hiding declation (if any).
+ ///
+ /// \param R the result to add (if it is unique).
+ ///
+ /// \param CurContext the context in which this result will be named.
+ ///
+ /// \param Hiding the declaration that hides the result.
+ ///
+ /// \param InBaseClass whether the result was found in a base
+ /// class of the searched context.
+ void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding,
+ bool InBaseClass);
+
+ /// \brief Add a new non-declaration result to this result set.
+ void AddResult(Result R);
+
/// \brief Enter into a new scope.
void EnterNewScope();
@@ -158,6 +203,7 @@ namespace {
///
//@{
bool IsOrdinaryName(NamedDecl *ND) const;
+ bool IsOrdinaryNonValueName(NamedDecl *ND) const;
bool IsNestedNameSpecifier(NamedDecl *ND) const;
bool IsEnum(NamedDecl *ND) const;
bool IsClassOrStruct(NamedDecl *ND) const;
@@ -166,6 +212,7 @@ namespace {
bool IsNamespaceOrAlias(NamedDecl *ND) const;
bool IsType(NamedDecl *ND) const;
bool IsMember(NamedDecl *ND) const;
+ bool IsObjCIvar(NamedDecl *ND) const;
//@}
};
}
@@ -259,31 +306,6 @@ ResultBuilder::ShadowMapEntry::end() const {
return iterator(DeclOrVector.get<DeclIndexPairVector *>()->end());
}
-/// \brief Determines whether the given hidden result could be found with
-/// some extra work, e.g., by qualifying the name.
-///
-/// \param Hidden the declaration that is hidden by the currenly \p Visible
-/// declaration.
-///
-/// \param Visible the declaration with the same name that is already visible.
-///
-/// \returns true if the hidden result can be found by some mechanism,
-/// false otherwise.
-static bool canHiddenResultBeFound(const LangOptions &LangOpts,
- NamedDecl *Hidden, NamedDecl *Visible) {
- // In C, there is no way to refer to a hidden name.
- if (!LangOpts.CPlusPlus)
- return false;
-
- DeclContext *HiddenCtx = Hidden->getDeclContext()->getLookupContext();
-
- // There is no way to qualify a name declared in a function or method.
- if (HiddenCtx->isFunctionOrMethod())
- return false;
-
- return HiddenCtx != Visible->getDeclContext()->getLookupContext();
-}
-
/// \brief Compute the qualification required to get from the current context
/// (\p CurContext) to the target context (\p TargetContext).
///
@@ -330,46 +352,37 @@ getRequiredQualification(ASTContext &Context,
return Result;
}
-void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
- assert(!ShadowMaps.empty() && "Must enter into a results scope");
-
- if (R.Kind != Result::RK_Declaration) {
- // For non-declaration results, just add the result.
- Results.push_back(R);
- return;
- }
+bool ResultBuilder::isInterestingDecl(NamedDecl *ND,
+ bool &AsNestedNameSpecifier) const {
+ AsNestedNameSpecifier = false;
+
+ ND = ND->getUnderlyingDecl();
+ unsigned IDNS = ND->getIdentifierNamespace();
// Skip unnamed entities.
- if (!R.Declaration->getDeclName())
- return;
-
- // Look through using declarations.
- if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration))
- MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier),
- CurContext);
-
- Decl *CanonDecl = R.Declaration->getCanonicalDecl();
- unsigned IDNS = CanonDecl->getIdentifierNamespace();
+ if (!ND->getDeclName())
+ return false;
// Friend declarations and declarations introduced due to friends are never
// added as results.
- if (isa<FriendDecl>(CanonDecl) ||
+ if (isa<FriendDecl>(ND) ||
(IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend)))
- return;
-
+ return false;
+
// Class template (partial) specializations are never added as results.
- if (isa<ClassTemplateSpecializationDecl>(CanonDecl) ||
- isa<ClassTemplatePartialSpecializationDecl>(CanonDecl))
- return;
+ if (isa<ClassTemplateSpecializationDecl>(ND) ||
+ isa<ClassTemplatePartialSpecializationDecl>(ND))
+ return false;
// Using declarations themselves are never added as results.
- if (isa<UsingDecl>(CanonDecl))
- return;
-
- if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) {
+ if (isa<UsingDecl>(ND))
+ return false;
+
+ // Some declarations have reserved names that we don't want to ever show.
+ if (const IdentifierInfo *Id = ND->getIdentifier()) {
// __va_list_tag is a freak of nature. Find it and skip it.
if (Id->isStr("__va_list_tag") || Id->isStr("__builtin_va_list"))
- return;
+ return false;
// Filter out names reserved for the implementation (C99 7.1.3,
// C++ [lib.global.names]). Users don't need to see those.
@@ -379,18 +392,83 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
const char *Name = Id->getNameStart();
if (Name[0] == '_' &&
(Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z')))
- return;
+ return false;
}
}
-
+
// C++ constructors are never found by name lookup.
- if (isa<CXXConstructorDecl>(CanonDecl))
- return;
+ if (isa<CXXConstructorDecl>(ND))
+ return false;
// Filter out any unwanted results.
- if (Filter && !(this->*Filter)(R.Declaration))
+ if (Filter && !(this->*Filter)(ND)) {
+ // Check whether it is interesting as a nested-name-specifier.
+ if (AllowNestedNameSpecifiers && SemaRef.getLangOptions().CPlusPlus &&
+ IsNestedNameSpecifier(ND) &&
+ (Filter != &ResultBuilder::IsMember ||
+ (isa<CXXRecordDecl>(ND) &&
+ cast<CXXRecordDecl>(ND)->isInjectedClassName()))) {
+ AsNestedNameSpecifier = true;
+ return true;
+ }
+
+ return false;
+ }
+
+ // ... then it must be interesting!
+ return true;
+}
+
+bool ResultBuilder::CheckHiddenResult(Result &R, DeclContext *CurContext,
+ NamedDecl *Hiding) {
+ // In C, there is no way to refer to a hidden name.
+ // FIXME: This isn't true; we can find a tag name hidden by an ordinary
+ // name if we introduce the tag type.
+ if (!SemaRef.getLangOptions().CPlusPlus)
+ return true;
+
+ DeclContext *HiddenCtx = R.Declaration->getDeclContext()->getLookupContext();
+
+ // There is no way to qualify a name declared in a function or method.
+ if (HiddenCtx->isFunctionOrMethod())
+ return true;
+
+ if (HiddenCtx == Hiding->getDeclContext()->getLookupContext())
+ return true;
+
+ // We can refer to the result with the appropriate qualification. Do it.
+ R.Hidden = true;
+ R.QualifierIsInformative = false;
+
+ if (!R.Qualifier)
+ R.Qualifier = getRequiredQualification(SemaRef.Context,
+ CurContext,
+ R.Declaration->getDeclContext());
+ return false;
+}
+
+void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
+ assert(!ShadowMaps.empty() && "Must enter into a results scope");
+
+ if (R.Kind != Result::RK_Declaration) {
+ // For non-declaration results, just add the result.
+ Results.push_back(R);
return;
+ }
+
+ // Look through using declarations.
+ if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {
+ MaybeAddResult(Result(Using->getTargetDecl(), R.Qualifier), CurContext);
+ return;
+ }
+ Decl *CanonDecl = R.Declaration->getCanonicalDecl();
+ unsigned IDNS = CanonDecl->getIdentifierNamespace();
+
+ bool AsNestedNameSpecifier = false;
+ if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier))
+ return;
+
ShadowMap &SMap = ShadowMaps.back();
ShadowMapEntry::iterator I, IEnd;
ShadowMap::iterator NamePos = SMap.find(R.Declaration->getDeclName());
@@ -406,9 +484,6 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
// This is a redeclaration. Always pick the newer declaration.
Results[Index].Declaration = R.Declaration;
- // Pick the best rank of the two.
- Results[Index].Rank = std::min(Results[Index].Rank, R.Rank);
-
// We're done.
return;
}
@@ -440,21 +515,8 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
continue;
// The newly-added result is hidden by an entry in the shadow map.
- if (canHiddenResultBeFound(SemaRef.getLangOptions(), R.Declaration,
- I->first)) {
- // Note that this result was hidden.
- R.Hidden = true;
- R.QualifierIsInformative = false;
-
- if (!R.Qualifier)
- R.Qualifier = getRequiredQualification(SemaRef.Context,
- CurContext,
- R.Declaration->getDeclContext());
- } else {
- // This result was hidden and cannot be found; don't bother adding
- // it.
+ if (CheckHiddenResult(R, CurContext, I->first))
return;
- }
break;
}
@@ -466,10 +528,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
// If the filter is for nested-name-specifiers, then this result starts a
// nested-name-specifier.
- if ((Filter == &ResultBuilder::IsNestedNameSpecifier) ||
- (Filter == &ResultBuilder::IsMember &&
- isa<CXXRecordDecl>(R.Declaration) &&
- cast<CXXRecordDecl>(R.Declaration)->isInjectedClassName()))
+ if (AsNestedNameSpecifier)
R.StartsNestedNameSpecifier = true;
// If this result is supposed to have an informative qualifier, add one.
@@ -491,6 +550,63 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
Results.push_back(R);
}
+void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
+ NamedDecl *Hiding, bool InBaseClass = false) {
+ if (R.Kind != Result::RK_Declaration) {
+ // For non-declaration results, just add the result.
+ Results.push_back(R);
+ return;
+ }
+
+ // Look through using declarations.
+ if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {
+ AddResult(Result(Using->getTargetDecl(), R.Qualifier), CurContext, Hiding);
+ return;
+ }
+
+ bool AsNestedNameSpecifier = false;
+ if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier))
+ return;
+
+ if (Hiding && CheckHiddenResult(R, CurContext, Hiding))
+ return;
+
+ // Make sure that any given declaration only shows up in the result set once.
+ if (!AllDeclsFound.insert(R.Declaration->getCanonicalDecl()))
+ return;
+
+ // If the filter is for nested-name-specifiers, then this result starts a
+ // nested-name-specifier.
+ if (AsNestedNameSpecifier)
+ R.StartsNestedNameSpecifier = true;
+ else if (Filter == &ResultBuilder::IsMember && !R.Qualifier && InBaseClass &&
+ isa<CXXRecordDecl>(R.Declaration->getDeclContext()
+ ->getLookupContext()))
+ R.QualifierIsInformative = true;
+
+ // If this result is supposed to have an informative qualifier, add one.
+ if (R.QualifierIsInformative && !R.Qualifier &&
+ !R.StartsNestedNameSpecifier) {
+ DeclContext *Ctx = R.Declaration->getDeclContext();
+ if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))
+ R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, Namespace);
+ else if (TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
+ R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
+ SemaRef.Context.getTypeDeclType(Tag).getTypePtr());
+ else
+ R.QualifierIsInformative = false;
+ }
+
+ // Insert this result into the set of results.
+ Results.push_back(R);
+}
+
+void ResultBuilder::AddResult(Result R) {
+ assert(R.Kind != Result::RK_Declaration &&
+ "Declaration results need more context");
+ Results.push_back(R);
+}
+
/// \brief Enter into a new scope.
void ResultBuilder::EnterNewScope() {
ShadowMaps.push_back(ShadowMap());
@@ -513,10 +629,23 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
unsigned IDNS = Decl::IDNS_Ordinary;
if (SemaRef.getLangOptions().CPlusPlus)
IDNS |= Decl::IDNS_Tag;
-
+ else if (SemaRef.getLangOptions().ObjC1 && isa<ObjCIvarDecl>(ND))
+ return true;
+
return ND->getIdentifierNamespace() & IDNS;
}
+/// \brief Determines whether this given declaration will be found by
+/// ordinary name lookup.
+bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const {
+ unsigned IDNS = Decl::IDNS_Ordinary;
+ if (SemaRef.getLangOptions().CPlusPlus)
+ IDNS |= Decl::IDNS_Tag;
+
+ return (ND->getIdentifierNamespace() & IDNS) &&
+ !isa<ValueDecl>(ND) && !isa<FunctionTemplateDecl>(ND);
+}
+
/// \brief Determines whether the given declaration is suitable as the
/// start of a C++ nested-name-specifier, e.g., a class or namespace.
bool ResultBuilder::IsNestedNameSpecifier(NamedDecl *ND) const {
@@ -584,251 +713,601 @@ bool ResultBuilder::IsMember(NamedDecl *ND) const {
isa<ObjCPropertyDecl>(ND);
}
-// Find the next outer declaration context corresponding to this scope.
-static DeclContext *findOuterContext(Scope *S) {
- for (S = S->getParent(); S; S = S->getParent())
- if (S->getEntity())
- return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext();
-
- return 0;
-}
-
-/// \brief Collect the results of searching for members within the given
-/// declaration context.
-///
-/// \param Ctx the declaration context from which we will gather results.
-///
-/// \param Rank the rank given to results in this declaration context.
-///
-/// \param Visited the set of declaration contexts that have already been
-/// visited. Declaration contexts will only be visited once.
-///
-/// \param Results the result set that will be extended with any results
-/// found within this declaration context (and, for a C++ class, its bases).
-///
-/// \param InBaseClass whether we are in a base class.
-///
-/// \returns the next higher rank value, after considering all of the
-/// names within this declaration context.
-static unsigned CollectMemberLookupResults(DeclContext *Ctx,
- unsigned Rank,
- DeclContext *CurContext,
- llvm::SmallPtrSet<DeclContext *, 16> &Visited,
- ResultBuilder &Results,
- bool InBaseClass = false) {
- // Make sure we don't visit the same context twice.
- if (!Visited.insert(Ctx->getPrimaryContext()))
- return Rank;
-
- // Enumerate all of the results in this context.
- typedef CodeCompleteConsumer::Result Result;
- Results.EnterNewScope();
- 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))
- Results.MaybeAddResult(Result(ND, Rank, 0, InBaseClass), CurContext);
-
- // Visit transparent contexts inside this context.
- if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) {
- if (InnerCtx->isTransparentContext())
- CollectMemberLookupResults(InnerCtx, Rank, CurContext, Visited,
- Results, InBaseClass);
- }
- }
- }
-
- // 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, code
- // completion could be smart enough to qualify the member with the
- // base class, e.g.,
- //
- // c->B::member
- //
- // or
- //
- // c->A::member
-
- // Collect results from this base class (and its bases).
- CollectMemberLookupResults(Record->getDecl(), Rank, CurContext, Visited,
- Results, /*InBaseClass=*/true);
- }
- }
-
- // FIXME: Look into base classes in Objective-C!
-
- Results.ExitScope();
- return Rank + 1;
+/// \rief Determines whether the given declaration is an Objective-C
+/// instance variable.
+bool ResultBuilder::IsObjCIvar(NamedDecl *ND) const {
+ return isa<ObjCIvarDecl>(ND);
}
-/// \brief Collect the results of searching for members within the given
-/// declaration context.
-///
-/// \param Ctx the declaration context from which we will gather results.
-///
-/// \param InitialRank the initial rank given to results in this declaration
-/// context. Larger rank values will be used for, e.g., members found in
-/// base classes.
-///
-/// \param Results the result set that will be extended with any results
-/// found within this declaration context (and, for a C++ class, its bases).
-///
-/// \returns the next higher rank value, after considering all of the
-/// names within this declaration context.
-static unsigned CollectMemberLookupResults(DeclContext *Ctx,
- unsigned InitialRank,
- DeclContext *CurContext,
- ResultBuilder &Results) {
- llvm::SmallPtrSet<DeclContext *, 16> Visited;
- return CollectMemberLookupResults(Ctx, InitialRank, CurContext, Visited,
- Results);
-}
-
-/// \brief Collect the results of searching for declarations within the given
-/// scope and its parent scopes.
-///
-/// \param S the scope in which we will start looking for declarations.
-///
-/// \param InitialRank the initial rank given to results in this scope.
-/// Larger rank values will be used for results found in parent scopes.
-///
-/// \param CurContext the context from which lookup results will be found.
-///
-/// \param Results the builder object that will receive each result.
-static unsigned CollectLookupResults(Scope *S,
- TranslationUnitDecl *TranslationUnit,
- unsigned InitialRank,
- DeclContext *CurContext,
- ResultBuilder &Results) {
- if (!S)
- return InitialRank;
-
- // FIXME: Using directives!
-
- unsigned NextRank = InitialRank;
- Results.EnterNewScope();
- 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.
- DeclContext *Ctx = (DeclContext *)S->getEntity();
- DeclContext *OuterCtx = findOuterContext(S);
-
- for (; Ctx && Ctx->getPrimaryContext() != OuterCtx;
- Ctx = Ctx->getLookupParent()) {
- if (Ctx->isFunctionOrMethod())
- continue;
-
- NextRank = CollectMemberLookupResults(Ctx, NextRank + 1, CurContext,
- Results);
- }
- } 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.
- NextRank = CollectMemberLookupResults(TranslationUnit, NextRank + 1,
- CurContext, Results);
- } 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())))
- Results.MaybeAddResult(CodeCompleteConsumer::Result(ND, NextRank),
- CurContext);
- }
+namespace {
+ /// \brief Visible declaration consumer that adds a code-completion result
+ /// for each visible declaration.
+ class CodeCompletionDeclConsumer : public VisibleDeclConsumer {
+ ResultBuilder &Results;
+ DeclContext *CurContext;
- NextRank = NextRank + 1;
- }
-
- // Lookup names in the parent scope.
- NextRank = CollectLookupResults(S->getParent(), TranslationUnit, NextRank,
- CurContext, Results);
- Results.ExitScope();
-
- return NextRank;
+ public:
+ CodeCompletionDeclConsumer(ResultBuilder &Results, DeclContext *CurContext)
+ : Results(Results), CurContext(CurContext) { }
+
+ virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass) {
+ Results.AddResult(ND, CurContext, Hiding, InBaseClass);
+ }
+ };
}
/// \brief Add type specifiers for the current language as keyword results.
-static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank,
+static void AddTypeSpecifierResults(const LangOptions &LangOpts,
ResultBuilder &Results) {
typedef CodeCompleteConsumer::Result Result;
- Results.MaybeAddResult(Result("short", Rank));
- Results.MaybeAddResult(Result("long", Rank));
- Results.MaybeAddResult(Result("signed", Rank));
- Results.MaybeAddResult(Result("unsigned", Rank));
- Results.MaybeAddResult(Result("void", Rank));
- Results.MaybeAddResult(Result("char", Rank));
- Results.MaybeAddResult(Result("int", Rank));
- Results.MaybeAddResult(Result("float", Rank));
- Results.MaybeAddResult(Result("double", Rank));
- Results.MaybeAddResult(Result("enum", Rank));
- Results.MaybeAddResult(Result("struct", Rank));
- Results.MaybeAddResult(Result("union", Rank));
-
+ Results.AddResult(Result("short"));
+ Results.AddResult(Result("long"));
+ Results.AddResult(Result("signed"));
+ Results.AddResult(Result("unsigned"));
+ Results.AddResult(Result("void"));
+ Results.AddResult(Result("char"));
+ Results.AddResult(Result("int"));
+ Results.AddResult(Result("float"));
+ Results.AddResult(Result("double"));
+ Results.AddResult(Result("enum"));
+ Results.AddResult(Result("struct"));
+ Results.AddResult(Result("union"));
+ Results.AddResult(Result("const"));
+ Results.AddResult(Result("volatile"));
+
if (LangOpts.C99) {
// C99-specific
- Results.MaybeAddResult(Result("_Complex", Rank));
- Results.MaybeAddResult(Result("_Imaginary", Rank));
- Results.MaybeAddResult(Result("_Bool", Rank));
+ Results.AddResult(Result("_Complex"));
+ Results.AddResult(Result("_Imaginary"));
+ Results.AddResult(Result("_Bool"));
+ Results.AddResult(Result("restrict"));
}
if (LangOpts.CPlusPlus) {
// C++-specific
- Results.MaybeAddResult(Result("bool", Rank));
- Results.MaybeAddResult(Result("class", Rank));
- Results.MaybeAddResult(Result("typename", Rank));
- Results.MaybeAddResult(Result("wchar_t", Rank));
+ Results.AddResult(Result("bool"));
+ Results.AddResult(Result("class"));
+ Results.AddResult(Result("wchar_t"));
+ // typename qualified-id
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("typename");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("qualified-id");
+ Results.AddResult(Result(Pattern));
+
if (LangOpts.CPlusPlus0x) {
- Results.MaybeAddResult(Result("char16_t", Rank));
- Results.MaybeAddResult(Result("char32_t", Rank));
- Results.MaybeAddResult(Result("decltype", Rank));
+ Results.AddResult(Result("auto"));
+ Results.AddResult(Result("char16_t"));
+ Results.AddResult(Result("char32_t"));
+ Results.AddResult(Result("decltype"));
}
}
// GNU extensions
if (LangOpts.GNUMode) {
// FIXME: Enable when we actually support decimal floating point.
- // Results.MaybeAddResult(Result("_Decimal32", Rank));
- // Results.MaybeAddResult(Result("_Decimal64", Rank));
- // Results.MaybeAddResult(Result("_Decimal128", Rank));
- Results.MaybeAddResult(Result("typeof", Rank));
+ // Results.AddResult(Result("_Decimal32"));
+ // Results.AddResult(Result("_Decimal64"));
+ // Results.AddResult(Result("_Decimal128"));
+
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("typeof");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression-or-type");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
}
}
+static void AddStorageSpecifiers(Action::CodeCompletionContext CCC,
+ const LangOptions &LangOpts,
+ ResultBuilder &Results) {
+ typedef CodeCompleteConsumer::Result Result;
+ // Note: we don't suggest either "auto" or "register", because both
+ // are pointless as storage specifiers. Elsewhere, we suggest "auto"
+ // in C++0x as a type specifier.
+ Results.AddResult(Result("extern"));
+ Results.AddResult(Result("static"));
+}
+
+static void AddFunctionSpecifiers(Action::CodeCompletionContext CCC,
+ const LangOptions &LangOpts,
+ ResultBuilder &Results) {
+ typedef CodeCompleteConsumer::Result Result;
+ switch (CCC) {
+ case Action::CCC_Class:
+ case Action::CCC_MemberTemplate:
+ if (LangOpts.CPlusPlus) {
+ Results.AddResult(Result("explicit"));
+ Results.AddResult(Result("friend"));
+ Results.AddResult(Result("mutable"));
+ Results.AddResult(Result("virtual"));
+ }
+ // Fall through
+
+ case Action::CCC_ObjCInterface:
+ case Action::CCC_ObjCImplementation:
+ case Action::CCC_Namespace:
+ case Action::CCC_Template:
+ if (LangOpts.CPlusPlus || LangOpts.C99)
+ Results.AddResult(Result("inline"));
+ break;
+
+ case Action::CCC_ObjCInstanceVariableList:
+ case Action::CCC_Expression:
+ case Action::CCC_Statement:
+ case Action::CCC_ForInit:
+ case Action::CCC_Condition:
+ break;
+ }
+}
+
+static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt);
+static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt);
+static void AddObjCVisibilityResults(const LangOptions &LangOpts,
+ ResultBuilder &Results,
+ bool NeedAt);
+static void AddObjCImplementationResults(const LangOptions &LangOpts,
+ ResultBuilder &Results,
+ bool NeedAt);
+static void AddObjCInterfaceResults(const LangOptions &LangOpts,
+ ResultBuilder &Results,
+ bool NeedAt);
+static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt);
+
+/// \brief Add language constructs that show up for "ordinary" names.
+static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
+ Scope *S,
+ Sema &SemaRef,
+ ResultBuilder &Results) {
+ typedef CodeCompleteConsumer::Result Result;
+ switch (CCC) {
+ case Action::CCC_Namespace:
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ // namespace <identifier> { }
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("namespace");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("declarations");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+
+ // namespace identifier = identifier ;
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("namespace");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddChunk(CodeCompletionString::CK_Equal);
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // Using directives
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("using");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk("namespace");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // asm(string-literal)
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("asm");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("string-literal");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // Explicit template instantiation
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("template");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("declaration");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+ }
+
+ if (SemaRef.getLangOptions().ObjC1)
+ AddObjCTopLevelResults(Results, true);
+
+ // Fall through
+
+ case Action::CCC_Class:
+ Results.AddResult(Result("typedef"));
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ // Using declaration
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("using");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("qualified-id");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // using typename qualified-id; (only in a dependent context)
+ if (SemaRef.CurContext->isDependentContext()) {
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("using");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk("typename");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("qualified-id");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+ }
+
+ if (CCC == Action::CCC_Class) {
+ // public:
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("public");
+ Pattern->AddChunk(CodeCompletionString::CK_Colon);
+ Results.AddResult(Result(Pattern));
+
+ // protected:
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("protected");
+ Pattern->AddChunk(CodeCompletionString::CK_Colon);
+ Results.AddResult(Result(Pattern));
+
+ // private:
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("private");
+ Pattern->AddChunk(CodeCompletionString::CK_Colon);
+ Results.AddResult(Result(Pattern));
+ }
+ }
+ // Fall through
+
+ case Action::CCC_Template:
+ case Action::CCC_MemberTemplate:
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ // template < parameters >
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("template");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("parameters");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Results.AddResult(Result(Pattern));
+ }
+
+ AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ break;
+
+ case Action::CCC_ObjCInterface:
+ AddObjCInterfaceResults(SemaRef.getLangOptions(), Results, true);
+ AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ break;
+
+ case Action::CCC_ObjCImplementation:
+ AddObjCImplementationResults(SemaRef.getLangOptions(), Results, true);
+ AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ break;
+
+ case Action::CCC_ObjCInstanceVariableList:
+ AddObjCVisibilityResults(SemaRef.getLangOptions(), Results, true);
+ break;
+
+ case Action::CCC_Statement: {
+ Results.AddResult(Result("typedef"));
+
+ CodeCompletionString *Pattern = 0;
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("try");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Pattern->AddTextChunk("catch");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("declaration");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+ }
+ if (SemaRef.getLangOptions().ObjC1)
+ AddObjCStatementResults(Results, true);
+
+ // if (condition) { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("if");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Pattern->AddPlaceholderChunk("condition");
+ else
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+
+ // switch (condition) { }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("switch");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Pattern->AddPlaceholderChunk("condition");
+ else
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+
+ // Switch-specific statements.
+ if (!SemaRef.getSwitchStack().empty()) {
+ // case expression:
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("case");
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_Colon);
+ Results.AddResult(Result(Pattern));
+
+ // default:
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("default");
+ Pattern->AddChunk(CodeCompletionString::CK_Colon);
+ Results.AddResult(Result(Pattern));
+ }
+
+ /// while (condition) { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("while");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Pattern->AddPlaceholderChunk("condition");
+ else
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+
+ // do { statements } while ( expression );
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("do");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Pattern->AddTextChunk("while");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // for ( for-init-statement ; condition ; expression ) { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("for");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus || SemaRef.getLangOptions().C99)
+ Pattern->AddPlaceholderChunk("init-statement");
+ else
+ Pattern->AddPlaceholderChunk("init-expression");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Pattern->AddPlaceholderChunk("condition");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Pattern->AddPlaceholderChunk("inc-expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+
+ if (S->getContinueParent()) {
+ // continue ;
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("continue");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+ }
+
+ if (S->getBreakParent()) {
+ // break ;
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("break");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+ }
+
+ // "return expression ;" or "return ;", depending on whether we
+ // know the function is void or not.
+ bool isVoid = false;
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(SemaRef.CurContext))
+ isVoid = Function->getResultType()->isVoidType();
+ else if (ObjCMethodDecl *Method
+ = dyn_cast<ObjCMethodDecl>(SemaRef.CurContext))
+ isVoid = Method->getResultType()->isVoidType();
+ else if (SemaRef.CurBlock && !SemaRef.CurBlock->ReturnType.isNull())
+ isVoid = SemaRef.CurBlock->ReturnType->isVoidType();
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("return");
+ if (!isVoid)
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // goto identifier ;
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("goto");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // Using directives
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("using");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk("namespace");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+ }
+
+ // Fall through (for statement expressions).
+ case Action::CCC_ForInit:
+ case Action::CCC_Condition:
+ AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ // Fall through: conditions and statements can have expressions.
+
+ case Action::CCC_Expression: {
+ CodeCompletionString *Pattern = 0;
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ // 'this', if we're in a non-static member function.
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(SemaRef.CurContext))
+ if (!Method->isStatic())
+ Results.AddResult(Result("this"));
+
+ // true, false
+ Results.AddResult(Result("true"));
+ Results.AddResult(Result("false"));
+
+ // dynamic_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("dynamic_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // static_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("static_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // reinterpret_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("reinterpret_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // const_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("const_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // typeid ( expression-or-type )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("typeid");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression-or-type");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // new T ( ... )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("new");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expressions");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // new T [ ] ( ... )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("new");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBracket);
+ Pattern->AddPlaceholderChunk("size");
+ Pattern->AddChunk(CodeCompletionString::CK_RightBracket);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expressions");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // delete expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("delete");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Pattern));
+
+ // delete [] expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("delete");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBracket);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBracket);
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Pattern));
+
+ // throw expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("throw");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Pattern));
+ }
+
+ if (SemaRef.getLangOptions().ObjC1) {
+ // Add "super", if we're in an Objective-C class with a superclass.
+ if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl())
+ if (Method->getClassInterface()->getSuperClass())
+ Results.AddResult(Result("super"));
+
+ AddObjCExpressionResults(Results, true);
+ }
+
+ // sizeof expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("sizeof");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression-or-type");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+ break;
+ }
+ }
+
+ AddTypeSpecifierResults(SemaRef.getLangOptions(), Results);
+
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Results.AddResult(Result("operator"));
+}
+
/// \brief If the given declaration has an associated type, add it as a result
/// type chunk.
static void AddResultTypeChunk(ASTContext &Context,
@@ -1178,7 +1657,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
if (Idx > 0) {
std::string Keyword;
if (Idx > StartParameter)
- Keyword = " ";
+ Result->AddChunk(CodeCompletionString::CK_HorizontalSpace);
if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx))
Keyword += II->getName().str();
Keyword += ":";
@@ -1344,29 +1823,49 @@ namespace {
Y.getAsString()) < 0;
}
- bool operator()(const Result &X, const Result &Y) const {
- // Sort first by rank.
- if (X.Rank < Y.Rank)
- return true;
- else if (X.Rank > Y.Rank)
- return false;
-
- // We use a special ordering for keywords and patterns, based on the
- // typed text.
- if ((X.Kind == Result::RK_Keyword || X.Kind == Result::RK_Pattern) &&
- (Y.Kind == Result::RK_Keyword || Y.Kind == Result::RK_Pattern)) {
- const char *XStr = (X.Kind == Result::RK_Keyword)? X.Keyword
- : X.Pattern->getTypedText();
- const char *YStr = (Y.Kind == Result::RK_Keyword)? Y.Keyword
- : Y.Pattern->getTypedText();
- return llvm::StringRef(XStr).compare_lower(YStr) < 0;
+ /// \brief Retrieve the name that should be used to order a result.
+ ///
+ /// If the name needs to be constructed as a string, that string will be
+ /// saved into Saved and the returned StringRef will refer to it.
+ static llvm::StringRef getOrderedName(const Result &R,
+ std::string &Saved) {
+ switch (R.Kind) {
+ case Result::RK_Keyword:
+ return R.Keyword;
+
+ case Result::RK_Pattern:
+ return R.Pattern->getTypedText();
+
+ case Result::RK_Macro:
+ return R.Macro->getName();
+
+ case Result::RK_Declaration:
+ // Handle declarations below.
+ break;
}
+
+ DeclarationName Name = R.Declaration->getDeclName();
- // Result kinds are ordered by decreasing importance.
- if (X.Kind < Y.Kind)
- return true;
- else if (X.Kind > Y.Kind)
- return false;
+ // If the name is a simple identifier (by far the common case), or a
+ // zero-argument selector, just return a reference to that identifier.
+ if (IdentifierInfo *Id = Name.getAsIdentifierInfo())
+ return Id->getName();
+ if (Name.isObjCZeroArgSelector())
+ if (IdentifierInfo *Id
+ = Name.getObjCSelector().getIdentifierInfoForSlot(0))
+ return Id->getName();
+
+ Saved = Name.getAsString();
+ return Saved;
+ }
+
+ bool operator()(const Result &X, const Result &Y) const {
+ std::string XSaved, YSaved;
+ llvm::StringRef XStr = getOrderedName(X, XSaved);
+ llvm::StringRef YStr = getOrderedName(Y, YSaved);
+ int cmp = XStr.compare_lower(YStr);
+ if (cmp)
+ return cmp < 0;
// Non-hidden names precede hidden names.
if (X.Hidden != Y.Hidden)
@@ -1376,35 +1875,17 @@ namespace {
if (X.StartsNestedNameSpecifier != Y.StartsNestedNameSpecifier)
return !X.StartsNestedNameSpecifier;
- // Ordering depends on the kind of result.
- switch (X.Kind) {
- case Result::RK_Declaration:
- // Order based on the declaration names.
- return isEarlierDeclarationName(X.Declaration->getDeclName(),
- Y.Declaration->getDeclName());
-
- case Result::RK_Macro:
- return X.Macro->getName().compare_lower(Y.Macro->getName()) < 0;
-
- case Result::RK_Keyword:
- case Result::RK_Pattern:
- llvm_unreachable("Result kinds handled above");
- break;
- }
-
- // Silence GCC warning.
return false;
}
};
}
-static void AddMacroResults(Preprocessor &PP, unsigned Rank,
- ResultBuilder &Results) {
+static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results) {
Results.EnterNewScope();
for (Preprocessor::macro_iterator M = PP.macro_begin(),
MEnd = PP.macro_end();
M != MEnd; ++M)
- Results.MaybeAddResult(CodeCompleteConsumer::Result(M->first, Rank));
+ Results.AddResult(M->first);
Results.ExitScope();
}
@@ -1412,7 +1893,6 @@ static void HandleCodeCompleteResults(Sema *S,
CodeCompleteConsumer *CodeCompleter,
CodeCompleteConsumer::Result *Results,
unsigned NumResults) {
- // Sort the results by rank/kind/etc.
std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult());
if (CodeCompleter)
@@ -1422,26 +1902,42 @@ static void HandleCodeCompleteResults(Sema *S,
Results[I].Destroy();
}
-void Sema::CodeCompleteOrdinaryName(Scope *S) {
+void Sema::CodeCompleteOrdinaryName(Scope *S,
+ CodeCompletionContext CompletionContext) {
typedef CodeCompleteConsumer::Result Result;
- ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName);
- unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- 0, CurContext, Results);
+ ResultBuilder Results(*this);
- Results.EnterNewScope();
- AddTypeSpecifierResults(getLangOptions(), NextRank, Results);
-
- if (getLangOptions().ObjC1) {
- // Add the "super" keyword, if appropriate.
- if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(CurContext))
- if (Method->getClassInterface()->getSuperClass())
- Results.MaybeAddResult(Result("super", NextRank));
+ // Determine how to filter results, e.g., so that the names of
+ // values (functions, enumerators, function templates, etc.) are
+ // only allowed where we can have an expression.
+ switch (CompletionContext) {
+ case CCC_Namespace:
+ case CCC_Class:
+ case CCC_ObjCInterface:
+ case CCC_ObjCImplementation:
+ case CCC_ObjCInstanceVariableList:
+ case CCC_Template:
+ case CCC_MemberTemplate:
+ Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName);
+ break;
+
+ case CCC_Expression:
+ case CCC_Statement:
+ case CCC_ForInit:
+ case CCC_Condition:
+ Results.setFilter(&ResultBuilder::IsOrdinaryName);
+ break;
}
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
+
+ Results.EnterNewScope();
+ AddOrdinaryNameResults(CompletionContext, S, *this, Results);
Results.ExitScope();
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1513,13 +2009,12 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
}
ResultBuilder Results(*this, &ResultBuilder::IsMember);
- unsigned NextRank = 0;
-
Results.EnterNewScope();
if (const RecordType *Record = BaseType->getAs<RecordType>()) {
// Access to a C/C++ class, struct, or union.
- NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank,
- Record->getDecl(), Results);
+ Results.allowNestedNameSpecifiers();
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(Record->getDecl(), LookupMemberName, Consumer);
if (getLangOptions().CPlusPlus) {
if (!Results.empty()) {
@@ -1536,16 +2031,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
}
if (IsDependent)
- Results.MaybeAddResult(Result("template", NextRank++));
+ Results.AddResult(Result("template"));
}
-
- // We could have the start of a nested-name-specifier. Add those
- // results as well.
- // FIXME: We should really walk base classes to produce
- // nested-name-specifiers so that we produce more-precise results.
- Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
- CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank,
- CurContext, Results);
}
} else if (!IsArrow && BaseType->getAsObjCInterfacePointerType()) {
// Objective-C property reference.
@@ -1561,9 +2048,6 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
E = ObjCPtr->qual_end();
I != E; ++I)
AddObjCProperties(*I, true, CurContext, Results);
-
- // FIXME: We could (should?) also look for "implicit" properties, identified
- // only by the presence of nullary and unary selectors.
} else if ((IsArrow && BaseType->isObjCObjectPointerType()) ||
(!IsArrow && BaseType->isObjCInterfaceType())) {
// Objective-C instance variable access.
@@ -1575,11 +2059,10 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
Class = BaseType->getAs<ObjCInterfaceType>()->getDecl();
// Add all ivars from this class and its superclasses.
- for (; Class; Class = Class->getSuperClass()) {
- for (ObjCInterfaceDecl::ivar_iterator IVar = Class->ivar_begin(),
- IVarEnd = Class->ivar_end();
- IVar != IVarEnd; ++IVar)
- Results.MaybeAddResult(Result(*IVar, 0), CurContext);
+ if (Class) {
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ Results.setFilter(&ResultBuilder::IsObjCIvar);
+ LookupVisibleDecls(Class, LookupMemberName, Consumer);
}
}
@@ -1589,7 +2072,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
// Add macros
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank, Results);
+ AddMacroResults(PP, Results);
// Hand off the results found for code completion.
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
@@ -1621,19 +2104,12 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
}
ResultBuilder Results(*this, Filter);
- unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- 0, CurContext, Results);
-
- if (getLangOptions().CPlusPlus) {
- // We could have the start of a nested-name-specifier. Add those
- // results as well.
- Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
- NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- NextRank, CurContext, Results);
- }
+ Results.allowNestedNameSpecifiers();
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(S, LookupTagName, Consumer);
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1707,12 +2183,13 @@ void Sema::CodeCompleteCase(Scope *S) {
if (EnumeratorsSeen.count(*E))
continue;
- Results.MaybeAddResult(CodeCompleteConsumer::Result(*E, 0, Qualifier));
+ Results.AddResult(CodeCompleteConsumer::Result(*E, Qualifier),
+ CurContext, 0, false);
}
Results.ExitScope();
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, 1, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1746,7 +2223,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
// Ignore type-dependent call expressions entirely.
if (Fn->isTypeDependent() ||
Expr::hasAnyTypeDependentArguments(Args, NumArgs)) {
- CodeCompleteOrdinaryName(S);
+ CodeCompleteOrdinaryName(S, CCC_Expression);
return;
}
@@ -1784,7 +2261,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
}
if (Results.empty())
- CodeCompleteOrdinaryName(S);
+ CodeCompleteOrdinaryName(S, CCC_Expression);
else
CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(),
Results.size());
@@ -1805,16 +2282,17 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
return;
ResultBuilder Results(*this);
- unsigned NextRank = CollectMemberLookupResults(Ctx, 0, Ctx, Results);
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer);
// The "template" keyword can follow "::" in the grammar, but only
// put it into the grammar if the nested-name-specifier is dependent.
NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
if (!Results.empty() && NNS->isDependent())
- Results.MaybeAddResult(CodeCompleteConsumer::Result("template", NextRank));
+ Results.AddResult("template");
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank + 1, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1827,16 +2305,16 @@ void Sema::CodeCompleteUsing(Scope *S) {
// If we aren't in class scope, we could see the "namespace" keyword.
if (!S->isClassScope())
- Results.MaybeAddResult(CodeCompleteConsumer::Result("namespace", 0));
+ Results.AddResult(CodeCompleteConsumer::Result("namespace"));
// After "using", we can see anything that would start a
// nested-name-specifier.
- unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- 0, CurContext, Results);
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
Results.ExitScope();
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1848,11 +2326,11 @@ void Sema::CodeCompleteUsingDirective(Scope *S) {
// alias.
ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias);
Results.EnterNewScope();
- unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- 0, CurContext, Results);
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
Results.ExitScope();
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1882,13 +2360,13 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) {
for (std::map<NamespaceDecl *, NamespaceDecl *>::iterator
NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end();
NS != NSEnd; ++NS)
- Results.MaybeAddResult(CodeCompleteConsumer::Result(NS->second, 0),
- CurContext);
+ Results.AddResult(CodeCompleteConsumer::Result(NS->second, 0),
+ CurContext, 0, false);
Results.ExitScope();
}
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, 1, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1898,10 +2376,10 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) {
// After "namespace", we expect to see a namespace or alias.
ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias);
- unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- 0, CurContext, Results);
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1916,155 +2394,168 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
// Add the names of overloadable operators.
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
if (std::strcmp(Spelling, "?")) \
- Results.MaybeAddResult(Result(Spelling, 0));
+ Results.AddResult(Result(Spelling));
#include "clang/Basic/OperatorKinds.def"
// Add any type names visible from the current scope
- unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- 0, CurContext, Results);
+ Results.allowNestedNameSpecifiers();
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
// Add any type specifiers
- AddTypeSpecifierResults(getLangOptions(), 0, Results);
-
- // Add any nested-name-specifiers
- Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
- NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- NextRank + 1, CurContext, Results);
+ AddTypeSpecifierResults(getLangOptions(), Results);
Results.ExitScope();
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
-void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl,
- bool InInterface) {
+// Macro that expands to @Keyword or Keyword, depending on whether NeedAt is
+// true or false.
+#define OBJC_AT_KEYWORD_NAME(NeedAt,Keyword) NeedAt? "@" #Keyword : #Keyword
+static void AddObjCImplementationResults(const LangOptions &LangOpts,
+ ResultBuilder &Results,
+ bool NeedAt) {
typedef CodeCompleteConsumer::Result Result;
- ResultBuilder Results(*this);
- Results.EnterNewScope();
- if (ObjCImpDecl) {
- // Since we have an implementation, we can end it.
- Results.MaybeAddResult(Result("end", 0));
-
- CodeCompletionString *Pattern = 0;
- Decl *ImpDecl = ObjCImpDecl.getAs<Decl>();
- if (isa<ObjCImplementationDecl>(ImpDecl) ||
- isa<ObjCCategoryImplDecl>(ImpDecl)) {
- // @dynamic
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("dynamic");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("property");
- Results.MaybeAddResult(Result(Pattern, 0));
-
- // @synthesize
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("synthesize");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("property");
- Results.MaybeAddResult(Result(Pattern, 0));
- }
- } else if (InInterface) {
- // Since we have an interface or protocol, we can end it.
- Results.MaybeAddResult(Result("end", 0));
-
- if (LangOpts.ObjC2) {
- // @property
- Results.MaybeAddResult(Result("property", 0));
- }
-
- // @required
- Results.MaybeAddResult(Result("required", 0));
-
- // @optional
- Results.MaybeAddResult(Result("optional", 0));
- } else {
- CodeCompletionString *Pattern = 0;
-
- // @class name ;
+ // Since we have an implementation, we can end it.
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end)));
+
+ CodeCompletionString *Pattern = 0;
+ if (LangOpts.ObjC2) {
+ // @dynamic
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("class");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("identifier");
- Pattern->AddTextChunk(";"); // add ';' chunk
- Results.MaybeAddResult(Result(Pattern, 0));
-
- // @interface name
- // FIXME: Could introduce the whole pattern, including superclasses and
- // such.
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,dynamic));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("property");
+ Results.AddResult(Result(Pattern));
+
+ // @synthesize
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("interface");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("class");
- Results.MaybeAddResult(Result(Pattern, 0));
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,synthesize));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("property");
+ Results.AddResult(Result(Pattern));
+ }
+}
- // @protocol name
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("protocol");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("protocol");
- Results.MaybeAddResult(Result(Pattern, 0));
+static void AddObjCInterfaceResults(const LangOptions &LangOpts,
+ ResultBuilder &Results,
+ bool NeedAt) {
+ typedef CodeCompleteConsumer::Result Result;
+
+ // Since we have an interface or protocol, we can end it.
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end)));
+
+ if (LangOpts.ObjC2) {
+ // @property
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,property)));
+
+ // @required
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,required)));
+
+ // @optional
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,optional)));
+ }
+}
- // @implementation name
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("implementation");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("class");
- Results.MaybeAddResult(Result(Pattern, 0));
+static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
+ typedef CodeCompleteConsumer::Result Result;
+ CodeCompletionString *Pattern = 0;
+
+ // @class name ;
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,class));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // @interface name
+ // FIXME: Could introduce the whole pattern, including superclasses and
+ // such.
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,interface));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("class");
+ Results.AddResult(Result(Pattern));
+
+ // @protocol name
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,protocol));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("protocol");
+ Results.AddResult(Result(Pattern));
+
+ // @implementation name
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,implementation));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("class");
+ Results.AddResult(Result(Pattern));
+
+ // @compatibility_alias name
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,compatibility_alias));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("alias");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("class");
+ Results.AddResult(Result(Pattern));
+}
- // @compatibility_alias name
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("compatibility_alias");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("alias");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("class");
- Results.MaybeAddResult(Result(Pattern, 0));
- }
+void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl,
+ bool InInterface) {
+ typedef CodeCompleteConsumer::Result Result;
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ if (ObjCImpDecl)
+ AddObjCImplementationResults(getLangOptions(), Results, false);
+ else if (InInterface)
+ AddObjCInterfaceResults(getLangOptions(), Results, false);
+ else
+ AddObjCTopLevelResults(Results, false);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
-static void AddObjCExpressionResults(unsigned Rank, ResultBuilder &Results) {
+static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) {
typedef CodeCompleteConsumer::Result Result;
CodeCompletionString *Pattern = 0;
// @encode ( type-name )
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("encode");
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,encode));
Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
Pattern->AddPlaceholderChunk("type-name");
Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.MaybeAddResult(Result(Pattern, Rank));
+ Results.AddResult(Result(Pattern));
// @protocol ( protocol-name )
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("protocol");
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,protocol));
Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
Pattern->AddPlaceholderChunk("protocol-name");
Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.MaybeAddResult(Result(Pattern, Rank));
+ Results.AddResult(Result(Pattern));
// @selector ( selector )
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("selector");
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,selector));
Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
Pattern->AddPlaceholderChunk("selector");
Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.MaybeAddResult(Result(Pattern, Rank));
+ Results.AddResult(Result(Pattern));
}
-void Sema::CodeCompleteObjCAtStatement(Scope *S) {
+static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) {
typedef CodeCompleteConsumer::Result Result;
- ResultBuilder Results(*this);
- Results.EnterNewScope();
-
CodeCompletionString *Pattern = 0;
-
+
// @try { statements } @catch ( declaration ) { statements } @finally
// { statements }
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("try");
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,try));
Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
Pattern->AddPlaceholderChunk("statements");
Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
@@ -2079,29 +2570,53 @@ void Sema::CodeCompleteObjCAtStatement(Scope *S) {
Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
Pattern->AddPlaceholderChunk("statements");
Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
- Results.MaybeAddResult(Result(Pattern, 0));
-
+ Results.AddResult(Result(Pattern));
+
// @throw
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("throw");
- Pattern->AddTextChunk(" ");
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,throw));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("expression");
- Pattern->AddTextChunk(";");
- Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk
-
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
// @synchronized ( expression ) { statements }
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("synchronized");
- Pattern->AddTextChunk(" ");
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,synchronized));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
Pattern->AddPlaceholderChunk("expression");
Pattern->AddChunk(CodeCompletionString::CK_RightParen);
Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
Pattern->AddPlaceholderChunk("statements");
Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
- Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk
+ Results.AddResult(Result(Pattern));
+}
+
+static void AddObjCVisibilityResults(const LangOptions &LangOpts,
+ ResultBuilder &Results,
+ bool NeedAt) {
+ typedef CodeCompleteConsumer::Result Result;
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,private)));
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,protected)));
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,public)));
+ if (LangOpts.ObjC2)
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,package)));
+}
- AddObjCExpressionResults(0, Results);
+void Sema::CodeCompleteObjCAtVisibility(Scope *S) {
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ AddObjCVisibilityResults(getLangOptions(), Results, false);
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
+
+void Sema::CodeCompleteObjCAtStatement(Scope *S) {
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ AddObjCStatementResults(Results, false);
+ AddObjCExpressionResults(Results, false);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2109,7 +2624,7 @@ void Sema::CodeCompleteObjCAtStatement(Scope *S) {
void Sema::CodeCompleteObjCAtExpression(Scope *S) {
ResultBuilder Results(*this);
Results.EnterNewScope();
- AddObjCExpressionResults(0, Results);
+ AddObjCExpressionResults(Results, false);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2154,30 +2669,30 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
ResultBuilder Results(*this);
Results.EnterNewScope();
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readonly))
- Results.MaybeAddResult(CodeCompleteConsumer::Result("readonly", 0));
+ Results.AddResult(CodeCompleteConsumer::Result("readonly"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_assign))
- Results.MaybeAddResult(CodeCompleteConsumer::Result("assign", 0));
+ Results.AddResult(CodeCompleteConsumer::Result("assign"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readwrite))
- Results.MaybeAddResult(CodeCompleteConsumer::Result("readwrite", 0));
+ Results.AddResult(CodeCompleteConsumer::Result("readwrite"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_retain))
- Results.MaybeAddResult(CodeCompleteConsumer::Result("retain", 0));
+ Results.AddResult(CodeCompleteConsumer::Result("retain"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_copy))
- Results.MaybeAddResult(CodeCompleteConsumer::Result("copy", 0));
+ Results.AddResult(CodeCompleteConsumer::Result("copy"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic))
- Results.MaybeAddResult(CodeCompleteConsumer::Result("nonatomic", 0));
+ Results.AddResult(CodeCompleteConsumer::Result("nonatomic"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) {
CodeCompletionString *Setter = new CodeCompletionString;
Setter->AddTypedTextChunk("setter");
Setter->AddTextChunk(" = ");
Setter->AddPlaceholderChunk("method");
- Results.MaybeAddResult(CodeCompleteConsumer::Result(Setter, 0));
+ Results.AddResult(CodeCompleteConsumer::Result(Setter));
}
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_getter)) {
CodeCompletionString *Getter = new CodeCompletionString;
Getter->AddTypedTextChunk("getter");
Getter->AddTextChunk(" = ");
Getter->AddPlaceholderChunk("method");
- Results.MaybeAddResult(CodeCompleteConsumer::Result(Getter, 0));
+ Results.AddResult(CodeCompleteConsumer::Result(Getter));
}
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
@@ -2522,7 +3037,7 @@ static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext,
// Record any protocols we find.
if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*D))
if (!OnlyForwardDeclarations || Proto->isForwardDecl())
- Results.MaybeAddResult(Result(Proto, 0), CurContext);
+ Results.AddResult(Result(Proto, 0), CurContext, 0, false);
// Record any forward-declared protocols we find.
if (ObjCForwardProtocolDecl *Forward
@@ -2532,7 +3047,7 @@ static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext,
PEnd = Forward->protocol_end();
P != PEnd; ++P)
if (!OnlyForwardDeclarations || (*P)->isForwardDecl())
- Results.MaybeAddResult(Result(*P, 0), CurContext);
+ Results.AddResult(Result(*P, 0), CurContext, 0, false);
}
}
}
@@ -2583,7 +3098,7 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext,
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*D))
if ((!OnlyForwardDeclarations || Class->isForwardDecl()) &&
(!OnlyUnimplemented || !Class->getImplementation()))
- Results.MaybeAddResult(Result(Class, 0), CurContext);
+ Results.AddResult(Result(Class, 0), CurContext, 0, false);
// Record any forward-declared interfaces we find.
if (ObjCClassDecl *Forward = dyn_cast<ObjCClassDecl>(*D)) {
@@ -2591,7 +3106,8 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext,
C != CEnd; ++C)
if ((!OnlyForwardDeclarations || C->getInterface()->isForwardDecl()) &&
(!OnlyUnimplemented || !C->getInterface()->getImplementation()))
- Results.MaybeAddResult(Result(C->getInterface(), 0), CurContext);
+ Results.AddResult(Result(C->getInterface(), 0), CurContext,
+ 0, false);
}
}
}
@@ -2662,7 +3178,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
D != DEnd; ++D)
if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(*D))
if (CategoryNames.insert(Category->getIdentifier()))
- Results.MaybeAddResult(Result(Category, 0), CurContext);
+ Results.AddResult(Result(Category, 0), CurContext, 0, false);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
@@ -2694,7 +3210,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
Category = Category->getNextClassCategory())
if ((!IgnoreImplemented || !Category->getImplementation()) &&
CategoryNames.insert(Category->getIdentifier()))
- Results.MaybeAddResult(Result(Category, 0), CurContext);
+ Results.AddResult(Result(Category, 0), CurContext, 0, false);
Class = Class->getSuperClass();
IgnoreImplemented = false;
@@ -2768,7 +3284,7 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
for (ObjCInterfaceDecl::ivar_iterator IVar = Class->ivar_begin(),
IVarEnd = Class->ivar_end();
IVar != IVarEnd; ++IVar)
- Results.MaybeAddResult(Result(*IVar, 0), CurContext);
+ Results.AddResult(Result(*IVar, 0), CurContext, 0, false);
}
Results.ExitScope();
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 2253f09..0ccb8f2 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -14,6 +14,7 @@
#include "Sema.h"
#include "SemaInit.h"
#include "Lookup.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -137,6 +138,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
NamedDecl *IIDecl = 0;
switch (Result.getResultKind()) {
case LookupResult::NotFound:
+ case LookupResult::NotFoundInCurrentInstantiation:
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
return 0;
@@ -281,6 +283,9 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
else
llvm_unreachable("could not have corrected a typo here");
+ Diag(Result->getLocation(), diag::note_previous_decl)
+ << Result->getDeclName();
+
SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS);
return true;
}
@@ -555,11 +560,38 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
/// getObjCInterfaceDecl - Look up a for a class declaration in the scope.
/// return 0 if one not found.
-ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
+///
+/// \param Id the name of the Objective-C class we're looking for. If
+/// typo-correction fixes this name, the Id will be updated
+/// to the fixed name.
+///
+/// \param RecoverLoc if provided, this routine will attempt to
+/// recover from a typo in the name of an existing Objective-C class
+/// and, if successful, will return the lookup that results from
+/// typo-correction.
+ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
+ SourceLocation RecoverLoc) {
// The third "scope" argument is 0 since we aren't enabling lazy built-in
// creation from this context.
NamedDecl *IDecl = LookupSingleName(TUScope, Id, LookupOrdinaryName);
+ if (!IDecl && !RecoverLoc.isInvalid()) {
+ // Perform typo correction at the given location, but only if we
+ // find an Objective-C class name.
+ LookupResult R(*this, Id, RecoverLoc, LookupOrdinaryName);
+ if (CorrectTypo(R, TUScope, 0) &&
+ (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+ Diag(RecoverLoc, diag::err_undef_interface_suggest)
+ << Id << IDecl->getDeclName()
+ << CodeModificationHint::CreateReplacement(RecoverLoc,
+ IDecl->getNameAsString());
+ Diag(IDecl->getLocation(), diag::note_previous_decl)
+ << IDecl->getDeclName();
+
+ Id = IDecl->getIdentifier();
+ }
+ }
+
return dyn_cast_or_null<ObjCInterfaceDecl>(IDecl);
}
@@ -773,13 +805,38 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) {
if (getLangOptions().Microsoft)
return;
- // C++ [dcl.typedef]p2:
- // In a given non-class scope, a typedef specifier can be used to
- // redefine the name of any type declared in that scope to refer
- // to the type to which it already refers.
if (getLangOptions().CPlusPlus) {
+ // C++ [dcl.typedef]p2:
+ // In a given non-class scope, a typedef specifier can be used to
+ // redefine the name of any type declared in that scope to refer
+ // to the type to which it already refers.
if (!isa<CXXRecordDecl>(CurContext))
return;
+
+ // C++0x [dcl.typedef]p4:
+ // In a given class scope, a typedef specifier can be used to redefine
+ // any class-name declared in that scope that is not also a typedef-name
+ // to refer to the type to which it already refers.
+ //
+ // This wording came in via DR424, which was a correction to the
+ // wording in DR56, which accidentally banned code like:
+ //
+ // struct S {
+ // typedef struct A { } A;
+ // };
+ //
+ // in the C++03 standard. We implement the C++0x semantics, which
+ // allow the above but disallow
+ //
+ // struct S {
+ // typedef int I;
+ // typedef int I;
+ // };
+ //
+ // since that was the intent of DR56.
+ if (!isa<TypedefDecl >(Old))
+ return;
+
Diag(New->getLocation(), diag::err_redefinition)
<< New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
@@ -1250,34 +1307,61 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
New->setPreviousDeclaration(Old);
}
-/// CheckFallThrough - Check that we don't fall off the end of a
-/// Statement that should return a value.
-///
-/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
-/// MaybeFallThrough iff we might or might not fall off the end,
-/// NeverFallThroughOrReturn iff we never fall off the end of the statement or
-/// return. We assume NeverFallThrough iff we never fall off the end of the
-/// statement but we may return. We assume that functions not marked noreturn
-/// will return.
-Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
- // FIXME: Eventually share this CFG object when we have other warnings based
- // of the CFG. This can be done using AnalysisContext.
- llvm::OwningPtr<CFG> cfg (CFG::buildCFG(Root, &Context));
+static void MarkLive(CFGBlock *e, llvm::BitVector &live) {
+ std::queue<CFGBlock*> workq;
+ // Prep work queue
+ workq.push(e);
+ // Solve
+ while (!workq.empty()) {
+ CFGBlock *item = workq.front();
+ workq.pop();
+ live.set(item->getBlockID());
+ for (CFGBlock::succ_iterator I=item->succ_begin(),
+ E=item->succ_end();
+ I != E;
+ ++I) {
+ if ((*I) && !live[(*I)->getBlockID()]) {
+ live.set((*I)->getBlockID());
+ workq.push(*I);
+ }
+ }
+ }
+}
- // FIXME: They should never return 0, fix that, delete this code.
- if (cfg == 0)
- // FIXME: This should be NeverFallThrough
- return NeverFallThroughOrReturn;
- // The CFG leaves in dead things, and we don't want to dead code paths to
- // confuse us, so we mark all live things first.
+static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live,
+ SourceManager &SM) {
std::queue<CFGBlock*> workq;
- llvm::BitVector live(cfg->getNumBlockIDs());
// Prep work queue
- workq.push(&cfg->getEntry());
+ workq.push(e);
+ SourceLocation top;
+ if (!e->empty())
+ top = e[0][0].getStmt()->getLocStart();
+ bool FromMainFile = false;
+ bool FromSystemHeader = false;
+ bool TopValid = false;
+ if (top.isValid()) {
+ FromMainFile = SM.isFromMainFile(top);
+ FromSystemHeader = SM.isInSystemHeader(top);
+ TopValid = true;
+ }
// Solve
while (!workq.empty()) {
CFGBlock *item = workq.front();
workq.pop();
+ SourceLocation c;
+ if (!item->empty())
+ c = item[0][0].getStmt()->getLocStart();
+ else if (item->getTerminator())
+ c = item->getTerminator()->getLocStart();
+ if (c.isValid()
+ && (!TopValid
+ || (SM.isFromMainFile(c) && !FromMainFile)
+ || (FromSystemHeader && !SM.isInSystemHeader(c))
+ || SM.isBeforeInTranslationUnit(c, top))) {
+ top = c;
+ FromMainFile = SM.isFromMainFile(top);
+ FromSystemHeader = SM.isInSystemHeader(top);
+ }
live.set(item->getBlockID());
for (CFGBlock::succ_iterator I=item->succ_begin(),
E=item->succ_end();
@@ -1289,6 +1373,92 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
}
}
}
+ return top;
+}
+
+namespace {
+class LineCmp {
+ SourceManager &SM;
+public:
+ LineCmp(SourceManager &sm) : SM(sm) {
+ }
+ bool operator () (SourceLocation l1, SourceLocation l2) {
+ return l1 < l2;
+ }
+};
+}
+
+/// CheckUnreachable - Check for unreachable code.
+void Sema::CheckUnreachable(AnalysisContext &AC) {
+ // We avoid checking when there are errors, as the CFG won't faithfully match
+ // the user's code.
+ if (getDiagnostics().hasErrorOccurred())
+ return;
+ if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored)
+ return;
+
+ CFG *cfg = AC.getCFG();
+ if (cfg == 0)
+ return;
+
+ llvm::BitVector live(cfg->getNumBlockIDs());
+ // Mark all live things first.
+ MarkLive(&cfg->getEntry(), live);
+
+ llvm::SmallVector<SourceLocation, 24> lines;
+ // First, give warnings for blocks with no predecessors, as they
+ // can't be part of a loop.
+ for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
+ CFGBlock &b = **I;
+ if (!live[b.getBlockID()]) {
+ if (b.pred_begin() == b.pred_end()) {
+ if (!b.empty())
+ lines.push_back(b[0].getStmt()->getLocStart());
+ else if (b.getTerminator())
+ lines.push_back(b.getTerminator()->getLocStart());
+ // Avoid excessive errors by marking everything reachable from here
+ MarkLive(&b, live);
+ }
+ }
+ }
+
+ // And then give warnings for the tops of loops.
+ for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
+ CFGBlock &b = **I;
+ if (!live[b.getBlockID()])
+ // Avoid excessive errors by marking everything reachable from here
+ lines.push_back(MarkLiveTop(&b, live, Context.getSourceManager()));
+ }
+
+ std::sort(lines.begin(), lines.end(), LineCmp(Context.getSourceManager()));
+ for (llvm::SmallVector<SourceLocation, 24>::iterator I = lines.begin(),
+ E = lines.end();
+ I != E;
+ ++I)
+ if (I->isValid())
+ Diag(*I, diag::warn_unreachable);
+}
+
+/// CheckFallThrough - Check that we don't fall off the end of a
+/// Statement that should return a value.
+///
+/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
+/// MaybeFallThrough iff we might or might not fall off the end,
+/// NeverFallThroughOrReturn iff we never fall off the end of the statement or
+/// return. We assume NeverFallThrough iff we never fall off the end of the
+/// statement but we may return. We assume that functions not marked noreturn
+/// will return.
+Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) {
+ CFG *cfg = AC.getCFG();
+ if (cfg == 0)
+ // FIXME: This should be NeverFallThrough
+ return NeverFallThroughOrReturn;
+
+ // The CFG leaves in dead things, and we don't want to dead code paths to
+ // confuse us, so we mark all live things first.
+ std::queue<CFGBlock*> workq;
+ llvm::BitVector live(cfg->getNumBlockIDs());
+ MarkLive(&cfg->getEntry(), live);
// Now we know what is live, we check the live precessors of the exit block
// and look for fall through paths, being careful to ignore normal returns,
@@ -1321,6 +1491,14 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
HasFakeEdge = true;
continue;
}
+ if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {
+ if (AS->isMSAsm()) {
+ HasFakeEdge = true;
+ HasLiveReturn = true;
+ continue;
+ }
+ }
+
bool NoReturnEdge = false;
if (CallExpr *C = dyn_cast<CallExpr>(S)) {
Expr *CEE = C->getCallee()->IgnoreParenCasts();
@@ -1356,7 +1534,8 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
/// function that should return a value. Check that we don't fall off the end
/// of a noreturn function. We assume that functions and blocks not marked
/// noreturn will return.
-void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) {
+void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body,
+ AnalysisContext &AC) {
// FIXME: Would be nice if we had a better way to control cascading errors,
// but for now, avoid them. The problem is that when Parse sees:
// int foo() { return a; }
@@ -1394,7 +1573,7 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) {
return;
// FIXME: Function try block
if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
- switch (CheckFallThrough(Body)) {
+ switch (CheckFallThrough(AC)) {
case MaybeFallThrough:
if (HasNoReturn)
Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
@@ -1421,7 +1600,8 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) {
/// that should return a value. Check that we don't fall off the end of a
/// noreturn block. We assume that functions and blocks not marked noreturn
/// will return.
-void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) {
+void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body,
+ AnalysisContext &AC) {
// FIXME: Would be nice if we had a better way to control cascading errors,
// but for now, avoid them. The problem is that when Parse sees:
// int foo() { return a; }
@@ -1447,7 +1627,7 @@ void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) {
return;
// FIXME: Funtion try block
if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
- switch (CheckFallThrough(Body)) {
+ switch (CheckFallThrough(AC)) {
case MaybeFallThrough:
if (HasNoReturn)
Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
@@ -1878,6 +2058,30 @@ DeclarationName Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) {
Context.getCanonicalType(Ty));
}
+ case UnqualifiedId::IK_ConstructorTemplateId: {
+ // In well-formed code, we can only have a constructor
+ // template-id that refers to the current context, so go there
+ // to find the actual type being constructed.
+ CXXRecordDecl *CurClass = dyn_cast<CXXRecordDecl>(CurContext);
+ if (!CurClass || CurClass->getIdentifier() != Name.TemplateId->Name)
+ return DeclarationName();
+
+ // Determine the type of the class being constructed.
+ QualType CurClassType;
+ if (ClassTemplateDecl *ClassTemplate
+ = CurClass->getDescribedClassTemplate())
+ CurClassType = ClassTemplate->getInjectedClassNameType(Context);
+ else
+ CurClassType = Context.getTypeDeclType(CurClass);
+
+ // FIXME: Check two things: that the template-id names the same type as
+ // CurClassType, and that the template-id does not occur when the name
+ // was qualified.
+
+ return Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(CurClassType));
+ }
+
case UnqualifiedId::IK_DestructorName: {
QualType Ty = GetTypeFromParser(Name.DestructorName);
if (Ty.isNull())
@@ -3393,7 +3597,12 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (NewFD->isOverloadedOperator() &&
CheckOverloadedOperatorDeclaration(NewFD))
return NewFD->setInvalidDecl();
-
+
+ // Extra checking for C++0x literal operators (C++0x [over.literal]).
+ if (NewFD->getLiteralIdentifier() &&
+ CheckLiteralOperatorDeclaration(NewFD))
+ return NewFD->setInvalidDecl();
+
// In C++, check default arguments now that we have merged decls. Unless
// the lexical context is the class, because in this case this is done
// during delayed parsing anyway.
@@ -3717,7 +3926,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
if (getLangOptions().CPlusPlus) {
// Make sure we mark the destructor as used if necessary.
QualType InitType = VDecl->getType();
- if (const ArrayType *Array = Context.getAsArrayType(InitType))
+ while (const ArrayType *Array = Context.getAsArrayType(InitType))
InitType = Context.getBaseElementType(Array);
if (InitType->isRecordType())
FinalizeVarWithDestructor(VDecl, InitType);
@@ -4267,6 +4476,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
Decl *dcl = D.getAs<Decl>();
Stmt *Body = BodyArg.takeAs<Stmt>();
+ AnalysisContext AC(dcl);
FunctionDecl *FD = 0;
FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl);
if (FunTmpl)
@@ -4281,7 +4491,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
// Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3.
FD->setHasImplicitReturnZero(true);
else
- CheckFallThroughForFunctionDef(FD, Body);
+ CheckFallThroughForFunctionDef(FD, Body, AC);
if (!FD->isInvalidDecl())
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
@@ -4293,7 +4503,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
assert(MD == getCurMethodDecl() && "Method parsing confused");
MD->setBody(Body);
- CheckFallThroughForFunctionDef(MD, Body);
+ CheckFallThroughForFunctionDef(MD, Body, AC);
MD->setEndLoc(Body->getLocEnd());
if (!MD->isInvalidDecl())
@@ -4351,6 +4561,8 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
if (!Body) return D;
+ CheckUnreachable(AC);
+
// Verify that that gotos and switch cases don't jump into scopes illegally.
if (CurFunctionNeedsScopeChecking)
DiagnoseInvalidJumps(Body);
@@ -4657,8 +4869,18 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (Previous.isAmbiguous())
return DeclPtrTy();
- // A tag 'foo::bar' must already exist.
if (Previous.empty()) {
+ // Name lookup did not find anything. However, if the
+ // nested-name-specifier refers to the current instantiation,
+ // and that current instantiation has any dependent base
+ // classes, we might find something at instantiation time: treat
+ // this as a dependent elaborated-type-specifier.
+ if (Previous.wasNotFoundInCurrentInstantiation()) {
+ IsDependent = true;
+ return DeclPtrTy();
+ }
+
+ // A tag 'foo::bar' must already exist.
Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange();
Name = 0;
Invalid = true;
@@ -5054,6 +5276,29 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagD,
"Broken injected-class-name");
}
+// Traverses the class and any nested classes, making a note of any
+// dynamic classes that have no key function so that we can mark all of
+// their virtual member functions as "used" at the end of the translation
+// unit. This ensures that all functions needed by the vtable will get
+// instantiated/synthesized.
+static void
+RecordDynamicClassesWithNoKeyFunction(Sema &S, CXXRecordDecl *Record,
+ SourceLocation Loc) {
+ // We don't look at dependent or undefined classes.
+ if (Record->isDependentContext() || !Record->isDefinition())
+ return;
+
+ if (Record->isDynamicClass() && !S.Context.getKeyFunction(Record))
+ S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record, Loc));
+
+ for (DeclContext::decl_iterator D = Record->decls_begin(),
+ DEnd = Record->decls_end();
+ D != DEnd; ++D) {
+ if (CXXRecordDecl *Nested = dyn_cast<CXXRecordDecl>(*D))
+ RecordDynamicClassesWithNoKeyFunction(S, Nested, Loc);
+ }
+}
+
void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
SourceLocation RBraceLoc) {
AdjustDeclIfTemplate(TagD);
@@ -5066,6 +5311,10 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
// Exit this scope of this tag's definition.
PopDeclContext();
+ if (isa<CXXRecordDecl>(Tag) && !Tag->getDeclContext()->isRecord())
+ RecordDynamicClassesWithNoKeyFunction(*this, cast<CXXRecordDecl>(Tag),
+ RBraceLoc);
+
// Notify the consumer that we've defined a tag.
Consumer.HandleTagDeclDefinition(Tag);
}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 094e5b5..1a12208 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "TargetAttributesSema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
@@ -925,14 +926,19 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// If the target wants to validate the section specifier, make it happen.
std::string Error = S.Context.Target.isValidSectionSpecifier(SE->getString());
- if (Error.empty()) {
- D->addAttr(::new (S.Context) SectionAttr(SE->getString()));
+ if (!Error.empty()) {
+ S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target)
+ << Error;
return;
}
- S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target)
- << Error;
-
+ // This attribute cannot be applied to local variables.
+ if (isa<VarDecl>(D) && cast<VarDecl>(D)->hasLocalStorage()) {
+ S.Diag(SE->getLocStart(), diag::err_attribute_section_local_variable);
+ return;
+ }
+
+ D->addAttr(::new (S.Context) SectionAttr(SE->getString()));
}
static void HandleCDeclAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -1959,7 +1965,10 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
// Just ignore
break;
default:
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+ // Ask target about the attribute.
+ const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();
+ if (!TargetAttrs.ProcessDeclAttribute(scope, D, Attr, S))
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
break;
}
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 204d776..a81a04e 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -270,18 +270,18 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
ParmVarDecl *NewParam = New->getParamDecl(p);
if (OldParam->hasDefaultArg() && NewParam->hasDefaultArg()) {
- // FIXME: If the parameter doesn't have an identifier then the location
- // points to the '=' which means that the fixit hint won't remove any
- // extra spaces between the type and the '='.
- SourceLocation Begin = NewParam->getLocation();
- if (NewParam->getIdentifier())
- Begin = PP.getLocForEndOfToken(Begin);
-
+ // FIXME: If we knew where the '=' was, we could easily provide a fix-it
+ // hint here. Alternatively, we could walk the type-source information
+ // for NewParam to find the last source location in the type... but it
+ // isn't worth the effort right now. This is the kind of test case that
+ // is hard to get right:
+
+ // int f(int);
+ // void g(int (*fp)(int) = f);
+ // void g(int (*fp)(int) = &f);
Diag(NewParam->getLocation(),
diag::err_param_default_argument_redefinition)
- << NewParam->getDefaultArgRange()
- << CodeModificationHint::CreateRemoval(SourceRange(Begin,
- NewParam->getLocEnd()));
+ << NewParam->getDefaultArgRange();
// Look for the function declaration where the default argument was
// actually written, which may be a declaration prior to Old.
@@ -424,6 +424,8 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
/// the innermost class.
bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
const CXXScopeSpec *SS) {
+ assert(getLangOptions().CPlusPlus && "No class names in C!");
+
CXXRecordDecl *CurDecl;
if (SS && SS->isSet() && !SS->isInvalid()) {
DeclContext *DC = computeDeclContext(*SS, true);
@@ -1072,6 +1074,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
<< MemberOrBase << true << R.getLookupName()
<< CodeModificationHint::CreateReplacement(R.getNameLoc(),
R.getLookupName().getAsString());
+ Diag(Member->getLocation(), diag::note_previous_decl)
+ << Member->getDeclName();
return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
LParenLoc, RParenLoc);
@@ -1089,7 +1093,14 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
<< MemberOrBase << false << R.getLookupName()
<< CodeModificationHint::CreateReplacement(R.getNameLoc(),
R.getLookupName().getAsString());
-
+
+ const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec
+ : VirtualBaseSpec;
+ Diag(BaseSpec->getSourceRange().getBegin(),
+ diag::note_base_class_specified_here)
+ << BaseSpec->getType()
+ << BaseSpec->getSourceRange();
+
TyD = Type;
}
}
@@ -2054,7 +2065,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
if (!Record->isDependentType())
AddImplicitlyDeclaredMembersToClass(Record);
-
+
if (Record->isInvalidDecl())
return;
@@ -2734,18 +2745,23 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
<< ClassType << ConvType;
}
- if (Conversion->getPreviousDeclaration()) {
- const NamedDecl *ExpectedPrevDecl = Conversion->getPreviousDeclaration();
+ if (Conversion->getPrimaryTemplate()) {
+ // ignore specializations
+ } else if (Conversion->getPreviousDeclaration()) {
if (FunctionTemplateDecl *ConversionTemplate
- = Conversion->getDescribedFunctionTemplate())
- ExpectedPrevDecl = ConversionTemplate->getPreviousDeclaration();
- if (ClassDecl->replaceConversion(ExpectedPrevDecl, Conversion))
+ = Conversion->getDescribedFunctionTemplate()) {
+ if (ClassDecl->replaceConversion(
+ ConversionTemplate->getPreviousDeclaration(),
+ ConversionTemplate))
+ return DeclPtrTy::make(ConversionTemplate);
+ } else if (ClassDecl->replaceConversion(Conversion->getPreviousDeclaration(),
+ Conversion))
return DeclPtrTy::make(Conversion);
assert(Conversion->isInvalidDecl() && "Conversion should not get here.");
} else if (FunctionTemplateDecl *ConversionTemplate
= Conversion->getDescribedFunctionTemplate())
ClassDecl->addConversionFunction(ConversionTemplate);
- else if (!Conversion->getPrimaryTemplate()) // ignore specializations
+ else
ClassDecl->addConversionFunction(Conversion);
return DeclPtrTy::make(Conversion);
@@ -2986,6 +3002,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
break;
case UnqualifiedId::IK_ConstructorName:
+ case UnqualifiedId::IK_ConstructorTemplateId:
// C++0x inherited constructors.
if (getLangOptions().CPlusPlus0x) break;
@@ -4184,7 +4201,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
else
Diag(Loc, diag::err_ovl_no_viable_function_in_init)
<< ClassType << Range;
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
return 0;
case OR_Ambiguous:
@@ -4192,7 +4209,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range;
else
Diag(Loc, diag::err_ovl_ambiguous_init) << ClassType << Range;
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs);
return 0;
case OR_Deleted:
@@ -4207,7 +4224,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
<< Best->Function->isDeleted()
<< RD->getDeclName() << Range;
}
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
return 0;
}
@@ -4373,8 +4390,10 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
= CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase);
// Most paths end in a failed conversion.
- if (ICS)
- ICS->ConversionKind = ImplicitConversionSequence::BadConversion;
+ if (ICS) {
+ ICS->setBad();
+ ICS->Bad.init(BadConversionSequence::no_conversion, Init, DeclType);
+ }
// C++ [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression
@@ -4412,7 +4431,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// has a type that is a derived class of the parameter type,
// in which case the implicit conversion sequence is a
// derived-to-base Conversion (13.3.3.1).
- ICS->ConversionKind = ImplicitConversionSequence::StandardConversion;
+ ICS->setStandard();
ICS->Standard.First = ICK_Identity;
ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
ICS->Standard.Third = ICK_Identity;
@@ -4497,7 +4516,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// conversion or, if the conversion function returns an
// entity of a type that is a derived class of the parameter
// type, a derived-to-base Conversion.
- ICS->ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
+ ICS->setUserDefined();
ICS->UserDefined.Before = Best->Conversions[0].Standard;
ICS->UserDefined.After = Best->FinalConversion;
ICS->UserDefined.ConversionFunction = Best->Function;
@@ -4523,15 +4542,16 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
case OR_Ambiguous:
if (ICS) {
+ ICS->setAmbiguous();
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
Cand != CandidateSet.end(); ++Cand)
if (Cand->Viable)
- ICS->ConversionFunctionSet.push_back(Cand->Function);
+ ICS->Ambiguous.addConversion(Cand->Function);
break;
}
Diag(DeclLoc, diag::err_ref_init_ambiguous) << DeclType << Init->getType()
<< Init->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, &Init, 1);
return true;
case OR_No_Viable_Function:
@@ -4600,7 +4620,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
if (InitLvalue != Expr::LV_Valid && T2->isRecordType() &&
RefRelationship >= Ref_Compatible_With_Added_Qualification) {
if (ICS) {
- ICS->ConversionKind = ImplicitConversionSequence::StandardConversion;
+ ICS->setStandard();
ICS->Standard.First = ICK_Identity;
ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
ICS->Standard.Third = ICK_Identity;
@@ -4672,30 +4692,27 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
/*InOverloadResolution=*/false);
// Of course, that's still a reference binding.
- if (ICS->ConversionKind == ImplicitConversionSequence::StandardConversion) {
+ if (ICS->isStandard()) {
ICS->Standard.ReferenceBinding = true;
ICS->Standard.RRefBinding = isRValRef;
- } else if (ICS->ConversionKind ==
- ImplicitConversionSequence::UserDefinedConversion) {
+ } else if (ICS->isUserDefined()) {
ICS->UserDefined.After.ReferenceBinding = true;
ICS->UserDefined.After.RRefBinding = isRValRef;
}
- return ICS->ConversionKind == ImplicitConversionSequence::BadConversion;
+ return ICS->isBad();
} else {
ImplicitConversionSequence Conversions;
bool badConversion = PerformImplicitConversion(Init, T1, AA_Initializing,
false, false,
Conversions);
if (badConversion) {
- if ((Conversions.ConversionKind ==
- ImplicitConversionSequence::BadConversion)
- && !Conversions.ConversionFunctionSet.empty()) {
+ if (Conversions.isAmbiguous()) {
Diag(DeclLoc,
diag::err_lvalue_to_rvalue_ambig_ref) << Init->getSourceRange();
- for (int j = Conversions.ConversionFunctionSet.size()-1;
+ for (int j = Conversions.Ambiguous.conversions().size()-1;
j >= 0; j--) {
- FunctionDecl *Func = Conversions.ConversionFunctionSet[j];
- Diag(Func->getLocation(), diag::err_ovl_candidate);
+ FunctionDecl *Func = Conversions.Ambiguous.conversions()[j];
+ NoteOverloadCandidate(Func);
}
}
else {
@@ -4993,6 +5010,88 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
return false;
}
+/// CheckLiteralOperatorDeclaration - Check whether the declaration
+/// of this literal operator function is well-formed. If so, returns
+/// false; otherwise, emits appropriate diagnostics and returns true.
+bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
+ DeclContext *DC = FnDecl->getDeclContext();
+ Decl::Kind Kind = DC->getDeclKind();
+ if (Kind != Decl::TranslationUnit && Kind != Decl::Namespace &&
+ Kind != Decl::LinkageSpec) {
+ Diag(FnDecl->getLocation(), diag::err_literal_operator_outside_namespace)
+ << FnDecl->getDeclName();
+ return true;
+ }
+
+ bool Valid = false;
+
+ // FIXME: Check for the one valid template signature
+ // template <char...> type operator "" name();
+
+ if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) {
+ // Check the first parameter
+ QualType T = (*Param)->getType();
+
+ // unsigned long long int and long double are allowed, but only
+ // alone.
+ // We also allow any character type; their omission seems to be a bug
+ // in n3000
+ if (Context.hasSameType(T, Context.UnsignedLongLongTy) ||
+ Context.hasSameType(T, Context.LongDoubleTy) ||
+ Context.hasSameType(T, Context.CharTy) ||
+ Context.hasSameType(T, Context.WCharTy) ||
+ Context.hasSameType(T, Context.Char16Ty) ||
+ Context.hasSameType(T, Context.Char32Ty)) {
+ if (++Param == FnDecl->param_end())
+ Valid = true;
+ goto FinishedParams;
+ }
+
+ // Otherwise it must be a pointer to const; let's strip those.
+ const PointerType *PT = T->getAs<PointerType>();
+ if (!PT)
+ goto FinishedParams;
+ T = PT->getPointeeType();
+ if (!T.isConstQualified())
+ goto FinishedParams;
+ T = T.getUnqualifiedType();
+
+ // Move on to the second parameter;
+ ++Param;
+
+ // If there is no second parameter, the first must be a const char *
+ if (Param == FnDecl->param_end()) {
+ if (Context.hasSameType(T, Context.CharTy))
+ Valid = true;
+ goto FinishedParams;
+ }
+
+ // const char *, const wchar_t*, const char16_t*, and const char32_t*
+ // are allowed as the first parameter to a two-parameter function
+ if (!(Context.hasSameType(T, Context.CharTy) ||
+ Context.hasSameType(T, Context.WCharTy) ||
+ Context.hasSameType(T, Context.Char16Ty) ||
+ Context.hasSameType(T, Context.Char32Ty)))
+ goto FinishedParams;
+
+ // The second and final parameter must be an std::size_t
+ T = (*Param)->getType().getUnqualifiedType();
+ if (Context.hasSameType(T, Context.getSizeType()) &&
+ ++Param == FnDecl->param_end())
+ Valid = true;
+ }
+
+ // FIXME: This diagnostic is absolutely terrible.
+FinishedParams:
+ if (!Valid) {
+ Diag(FnDecl->getLocation(), diag::err_literal_operator_params)
+ << FnDecl->getDeclName();
+ return true;
+ }
+
+ return false;
+}
+
/// ActOnStartLinkageSpecification - Parsed the beginning of a C++
/// linkage specification, including the language and (if present)
/// the '{'. ExternLoc is the location of the 'extern', LangLoc is
@@ -5693,55 +5792,56 @@ void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc,
if (!RD->isDynamicClass())
return;
- if (!MD->isOutOfLine()) {
- // The only inline functions we care about are constructors. We also defer
- // marking the virtual members as referenced until we've reached the end
- // of the translation unit. We do this because we need to know the key
- // function of the class in order to determine the key function.
- if (isa<CXXConstructorDecl>(MD))
- ClassesWithUnmarkedVirtualMembers.insert(std::make_pair(RD, Loc));
+ // Ignore declarations that are not definitions.
+ if (!MD->isThisDeclarationADefinition())
return;
- }
- const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
-
- if (!KeyFunction) {
- // This record does not have a key function, so we assume that the vtable
- // will be emitted when it's used by the constructor.
- if (!isa<CXXConstructorDecl>(MD))
+ if (isa<CXXConstructorDecl>(MD)) {
+ switch (MD->getParent()->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ // Classes that aren't instantiations of templates don't need their
+ // virtual methods marked until we see the definition of the key
+ // function.
+ return;
+
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ // This is a constructor of a class template; mark all of the virtual
+ // members as referenced to ensure that they get instantiatied.
+ break;
+ }
+ } else if (!MD->isOutOfLine()) {
+ // Consider only out-of-line definitions of member functions. When we see
+ // an inline definition, it's too early to compute the key function.
+ return;
+ } else if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD)) {
+ // If this is not the key function, we don't need to mark virtual members.
+ if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl())
return;
- } else if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) {
- // We don't have the right key function.
+ } else {
+ // The class has no key function, so we've already noted that we need to
+ // mark the virtual members of this class.
return;
}
- // Mark the members as referenced.
- MarkVirtualMembersReferenced(Loc, RD);
- ClassesWithUnmarkedVirtualMembers.erase(RD);
+ // We will need to mark all of the virtual members as referenced to build the
+ // vtable.
+ ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(RD, Loc));
}
bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() {
if (ClassesWithUnmarkedVirtualMembers.empty())
return false;
- for (std::map<CXXRecordDecl *, SourceLocation>::iterator i =
- ClassesWithUnmarkedVirtualMembers.begin(),
- e = ClassesWithUnmarkedVirtualMembers.end(); i != e; ++i) {
- CXXRecordDecl *RD = i->first;
-
- const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
- if (KeyFunction) {
- // We know that the class has a key function. If the key function was
- // declared in this translation unit, then it the class decl would not
- // have been in the ClassesWithUnmarkedVirtualMembers map.
- continue;
- }
-
- SourceLocation Loc = i->second;
+ while (!ClassesWithUnmarkedVirtualMembers.empty()) {
+ CXXRecordDecl *RD = ClassesWithUnmarkedVirtualMembers.back().first;
+ SourceLocation Loc = ClassesWithUnmarkedVirtualMembers.back().second;
+ ClassesWithUnmarkedVirtualMembers.pop_back();
MarkVirtualMembersReferenced(Loc, RD);
}
- ClassesWithUnmarkedVirtualMembers.clear();
return true;
}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index beadb58..f2fc1f4 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ASTContext.h"
@@ -133,6 +134,19 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (SuperName) {
// Check if a different kind of symbol declared in this scope.
PrevDecl = LookupSingleName(TUScope, SuperName, LookupOrdinaryName);
+
+ if (!PrevDecl) {
+ // Try to correct for a typo in the superclass name.
+ LookupResult R(*this, SuperName, SuperLoc, LookupOrdinaryName);
+ if (CorrectTypo(R, TUScope, 0) &&
+ (PrevDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+ Diag(SuperLoc, diag::err_undef_superclass_suggest)
+ << SuperName << ClassName << PrevDecl->getDeclName();
+ Diag(PrevDecl->getLocation(), diag::note_previous_decl)
+ << PrevDecl->getDeclName();
+ }
+ }
+
if (PrevDecl == IDecl) {
Diag(SuperLoc, diag::err_recursive_superclass)
<< SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
@@ -317,6 +331,18 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
for (unsigned i = 0; i != NumProtocols; ++i) {
ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first);
if (!PDecl) {
+ LookupResult R(*this, ProtocolId[i].first, ProtocolId[i].second,
+ LookupObjCProtocolName);
+ if (CorrectTypo(R, TUScope, 0) &&
+ (PDecl = R.getAsSingle<ObjCProtocolDecl>())) {
+ Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest)
+ << ProtocolId[i].first << R.getLookupName();
+ Diag(PDecl->getLocation(), diag::note_previous_decl)
+ << PDecl->getDeclName();
+ }
+ }
+
+ if (!PDecl) {
Diag(ProtocolId[i].second, diag::err_undeclared_protocol)
<< ProtocolId[i].first;
continue;
@@ -568,7 +594,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
// FIXME: PushOnScopeChains?
CurContext->addDecl(CDecl);
- ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName);
+ ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc);
/// Check that class of this category is already completely declared.
if (!IDecl || IDecl->isForwardDecl()) {
CDecl->setInvalidDecl();
@@ -616,7 +642,7 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation(
SourceLocation AtCatImplLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
IdentifierInfo *CatName, SourceLocation CatLoc) {
- ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName);
+ ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc);
ObjCCategoryDecl *CatIDecl = 0;
if (IDecl) {
CatIDecl = IDecl->FindCategoryDeclaration(CatName);
@@ -667,13 +693,33 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- } else {
- // Is there an interface declaration of this class; if not, warn!
- IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
- if (!IDecl || IDecl->isForwardDecl()) {
+ } else if ((IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl))) {
+ // If this is a forward declaration of an interface, warn.
+ if (IDecl->isForwardDecl()) {
Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
IDecl = 0;
}
+ } else {
+ // We did not find anything with the name ClassName; try to correct for
+ // typos in the class name.
+ LookupResult R(*this, ClassName, ClassLoc, LookupOrdinaryName);
+ if (CorrectTypo(R, TUScope, 0) &&
+ (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+ // Suggest the (potentially) correct interface name. However, put the
+ // fix-it hint itself in a separate note, since changing the name in
+ // the warning would make the fix-it change semantics.However, don't
+ // provide a code-modification hint or use the typo name for recovery,
+ // because this is just a warning. The program may actually be correct.
+ Diag(ClassLoc, diag::warn_undef_interface_suggest)
+ << ClassName << R.getLookupName();
+ Diag(IDecl->getLocation(), diag::note_previous_decl)
+ << R.getLookupName()
+ << CodeModificationHint::CreateReplacement(ClassLoc,
+ R.getLookupName().getAsString());
+ IDecl = 0;
+ } else {
+ Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
+ }
}
// Check that super class name is valid class name
@@ -1437,8 +1483,11 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
property->getLocation());
if (SetterMethod) {
- if (Context.getCanonicalType(SetterMethod->getResultType())
- != Context.VoidTy)
+ ObjCPropertyDecl::PropertyAttributeKind CAttr =
+ property->getPropertyAttributes();
+ if ((!(CAttr & ObjCPropertyDecl::OBJC_PR_readonly)) &&
+ Context.getCanonicalType(SetterMethod->getResultType()) !=
+ Context.VoidTy)
Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
if (SetterMethod->param_size() != 1 ||
((*SetterMethod->param_begin())->getType() != property->getType())) {
@@ -1563,7 +1612,8 @@ void Sema::CompareMethodParamsInBaseAndSuper(Decl *ClassDecl,
// Note: For class/category implemenations, allMethods/allProperties is
// always null.
-void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
+void Sema::ActOnAtEnd(SourceRange AtEnd,
+ DeclPtrTy classDecl,
DeclPtrTy *allMethods, unsigned allNum,
DeclPtrTy *allProperties, unsigned pNum,
DeclGroupPtrTy *allTUVars, unsigned tuvNum) {
@@ -1580,9 +1630,13 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
|| isa<ObjCProtocolDecl>(ClassDecl);
bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl);
- if (!isInterfaceDeclKind && AtEndLoc.isInvalid()) {
- AtEndLoc = ClassDecl->getLocation();
- Diag(AtEndLoc, diag::warn_missing_atend);
+ if (!isInterfaceDeclKind && AtEnd.isInvalid()) {
+ // FIXME: This is wrong. We shouldn't be pretending that there is
+ // an '@end' in the declaration.
+ SourceLocation L = ClassDecl->getLocation();
+ AtEnd.setBegin(L);
+ AtEnd.setEnd(L);
+ Diag(L, diag::warn_missing_atend);
}
DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
@@ -1659,17 +1713,17 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
E = CDecl->prop_end();
I != E; ++I)
ProcessPropertyDecl(*I, CDecl);
- CDecl->setAtEndLoc(AtEndLoc);
+ CDecl->setAtEndRange(AtEnd);
}
if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
- IC->setAtEndLoc(AtEndLoc);
+ IC->setAtEndRange(AtEnd);
if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) {
ImplMethodsVsClassMethods(IC, IDecl);
AtomicPropertySetterGetterRules(IC, IDecl);
}
} else if (ObjCCategoryImplDecl* CatImplClass =
dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
- CatImplClass->setAtEndLoc(AtEndLoc);
+ CatImplClass->setAtEndRange(AtEnd);
// Find category interface decl and then check that all methods declared
// in this interface are implemented in the category @implementation.
@@ -1980,6 +2034,32 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
Diag(AtLoc, diag::warn_property_attr_mismatch);
Diag(PIDecl->getLocation(), diag::note_property_declare);
}
+ DeclContext *DC = dyn_cast<DeclContext>(CCPrimary);
+ assert(DC && "ClassDecl is not a DeclContext");
+ DeclContext::lookup_result Found =
+ DC->lookup(PIDecl->getDeclName());
+ bool PropertyInPrimaryClass = false;
+ for (; Found.first != Found.second; ++Found.first)
+ if (isa<ObjCPropertyDecl>(*Found.first)) {
+ PropertyInPrimaryClass = true;
+ break;
+ }
+ if (!PropertyInPrimaryClass) {
+ // Protocol is not in the primary class. Must build one for it.
+ ObjCDeclSpec ProtocolPropertyODS;
+ // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind and
+ // ObjCPropertyDecl::PropertyAttributeKind have identical values.
+ // Should consolidate both into one enum type.
+ ProtocolPropertyODS.setPropertyAttributes(
+ (ObjCDeclSpec::ObjCPropertyAttributeKind)PIkind);
+ DeclPtrTy ProtocolPtrTy =
+ ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS,
+ PIDecl->getGetterName(),
+ PIDecl->getSetterName(),
+ DeclPtrTy::make(CCPrimary), isOverridingProperty,
+ MethodImplKind);
+ PIDecl = ProtocolPtrTy.getAs<ObjCPropertyDecl>();
+ }
PIDecl->makeitReadWriteAttribute();
if (Attributes & ObjCDeclSpec::DQ_PR_retain)
PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 7bf04d8..034accd 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -14,6 +14,7 @@
#include "Sema.h"
#include "SemaInit.h"
#include "Lookup.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -565,7 +566,8 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
IsDerivedFrom(ThisType, AnonFieldType)) {
// Our base object expression is "this".
BaseObjectExpr = new (Context) CXXThisExpr(Loc,
- MD->getThisType(Context));
+ MD->getThisType(Context),
+ /*isImplicit=*/true);
BaseObjectIsPointer = true;
}
} else {
@@ -943,7 +945,10 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
<< SS.getRange()
<< CodeModificationHint::CreateReplacement(R.getNameLoc(),
R.getLookupName().getAsString());
-
+ if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
+ Diag(ND->getLocation(), diag::note_previous_decl)
+ << ND->getDeclName();
+
// Tell the callee to try to recover.
return false;
}
@@ -1006,11 +1011,18 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
// C++ [temp.dep.expr]p3:
// An id-expression is type-dependent if it contains:
+ // -- an identifier that was declared with a dependent type,
+ // (note: handled after lookup)
+ // -- a template-id that is dependent,
+ // (note: handled in BuildTemplateIdExpr)
+ // -- a conversion-function-id that specifies a dependent type,
// -- a nested-name-specifier that contains a class-name that
// names a dependent type.
// Determine whether this is a member of an unknown specialization;
// we need to handle these differently.
- if (SS.isSet() && IsDependentIdExpression(*this, SS)) {
+ if ((Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
+ Name.getCXXNameType()->isDependentType()) ||
+ (SS.isSet() && IsDependentIdExpression(*this, SS))) {
return ActOnDependentIdExpression(SS, Name, NameLoc,
isAddressOfOperand,
TemplateArgs);
@@ -1022,12 +1034,13 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
// Just re-use the lookup done by isTemplateName.
DecomposeTemplateName(R, Id);
} else {
- LookupParsedName(R, S, &SS, true);
+ bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl());
+ LookupParsedName(R, S, &SS, !IvarLookupFollowUp);
// If this reference is in an Objective-C method, then we need to do
// some special Objective-C lookup, too.
- if (!SS.isSet() && II && getCurMethodDecl()) {
- OwningExprResult E(LookupInObjCMethod(R, S, II));
+ if (IvarLookupFollowUp) {
+ OwningExprResult E(LookupInObjCMethod(R, S, II, true));
if (E.isInvalid())
return ExprError();
@@ -1059,6 +1072,16 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
assert(!R.empty() &&
"DiagnoseEmptyLookup returned false but added no results");
+
+ // If we found an Objective-C instance variable, let
+ // LookupInObjCMethod build the appropriate expression to
+ // reference the ivar.
+ if (ObjCIvarDecl *Ivar = R.getAsSingle<ObjCIvarDecl>()) {
+ R.clear();
+ OwningExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier()));
+ assert(E.isInvalid() || E.get());
+ return move(E);
+ }
}
}
@@ -1197,7 +1220,8 @@ Sema::BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS,
/// Returns a null sentinel to indicate trivial success.
Sema::OwningExprResult
Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
- IdentifierInfo *II) {
+ IdentifierInfo *II,
+ bool AllowBuiltinCreation) {
SourceLocation Loc = Lookup.getNameLoc();
// There are two cases to handle here. 1) scoped lookup could have failed,
@@ -1278,7 +1302,18 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
T = Context.getObjCClassType();
return Owned(new (Context) ObjCSuperExpr(Loc, T));
}
-
+ if (Lookup.empty() && II && AllowBuiltinCreation) {
+ // FIXME. Consolidate this with similar code in LookupName.
+ if (unsigned BuiltinID = II->getBuiltinID()) {
+ if (!(getLangOptions().CPlusPlus &&
+ Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))) {
+ NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
+ S, Lookup.isForRedeclaration(),
+ Lookup.getNameLoc());
+ if (D) Lookup.addDecl(D);
+ }
+ }
+ }
// Sentinel value saying that we didn't do anything special.
return Owned((Expr*) 0);
}
@@ -1353,13 +1388,18 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context);
Expr *This = 0; // null signifies implicit access
if (IsKnownInstance) {
- This = new (Context) CXXThisExpr(SourceLocation(), ThisType);
+ SourceLocation Loc = R.getNameLoc();
+ if (SS.getRange().isValid())
+ Loc = SS.getRange().getBegin();
+ This = new (Context) CXXThisExpr(Loc, ThisType, /*isImplicit=*/true);
}
return BuildMemberReferenceExpr(ExprArg(*this, This), ThisType,
/*OpLoc*/ SourceLocation(),
/*IsArrow*/ true,
- SS, R, TemplateArgs);
+ SS,
+ /*FirstQualifierInScope*/ 0,
+ R, TemplateArgs);
}
bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
@@ -1521,6 +1561,18 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// as they do not get snapshotted.
//
if (CurBlock && ShouldSnapshotBlockValueReference(CurBlock, VD)) {
+ if (VD->getType().getTypePtr()->isVariablyModifiedType()) {
+ Diag(Loc, diag::err_ref_vm_type);
+ Diag(D->getLocation(), diag::note_declared_at);
+ return ExprError();
+ }
+
+ if (VD->getType()->isArrayType()) {
+ Diag(Loc, diag::err_ref_array_type);
+ Diag(D->getLocation(), diag::note_declared_at);
+ return ExprError();
+ }
+
MarkDeclarationReferenced(Loc, VD);
QualType ExprTy = VD->getType().getNonReferenceType();
// The BlocksAttr indicates the variable is bound by-reference.
@@ -2252,7 +2304,7 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType,
}
}
- assert(BaseType->isDependentType());
+ assert(BaseType->isDependentType() || Name.isDependentName());
// Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
// must have pointer type, and the accessed type is the pointee.
@@ -2378,6 +2430,9 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
<< Name << DC << R.getLookupName() << SS.getRange()
<< CodeModificationHint::CreateReplacement(R.getNameLoc(),
R.getLookupName().getAsString());
+ if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
+ SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
+ << ND->getDeclName();
return false;
} else {
R.clear();
@@ -2418,8 +2473,7 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType,
} else {
OwningExprResult Result =
LookupMemberExpr(R, Base, IsArrow, OpLoc,
- SS, FirstQualifierInScope,
- /*ObjCImpDecl*/ DeclPtrTy());
+ SS, /*ObjCImpDecl*/ DeclPtrTy());
if (Result.isInvalid()) {
Owned(Base);
@@ -2431,13 +2485,15 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType,
}
return BuildMemberReferenceExpr(ExprArg(*this, Base), BaseType,
- OpLoc, IsArrow, SS, R, TemplateArgs);
+ OpLoc, IsArrow, SS, FirstQualifierInScope,
+ R, TemplateArgs);
}
Sema::OwningExprResult
Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
SourceLocation OpLoc, bool IsArrow,
const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
Expr *BaseExpr = Base.takeAs<Expr>();
@@ -2467,11 +2523,17 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
return ExprError();
}
- // Diagnose qualified lookups that find only declarations from a
- // non-base type. Note that it's okay for lookup to find
- // declarations from a non-base type as long as those aren't the
- // ones picked by overload resolution.
- if (SS.isSet() && CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
+ // Diagnose lookups that find only declarations from a non-base
+ // type. This is possible for either qualified lookups (which may
+ // have been qualified with an unrelated type) or implicit member
+ // expressions (which were found with unqualified lookup and thus
+ // may have come from an enclosing scope). Note that it's okay for
+ // lookup to find declarations from a non-base type as long as those
+ // aren't the ones picked by overload resolution.
+ if ((SS.isSet() || !BaseExpr ||
+ (isa<CXXThisExpr>(BaseExpr) &&
+ cast<CXXThisExpr>(BaseExpr)->isImplicit())) &&
+ CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
return ExprError();
// Construct an unresolved result if we in fact got an unresolved
@@ -2513,7 +2575,10 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
if (!IsInstanceMember(MemberDecl))
return BuildDeclarationNameExpr(SS, R.getNameLoc(), MemberDecl);
- BaseExpr = new (Context) CXXThisExpr(SourceLocation(), BaseExprType);
+ SourceLocation Loc = R.getNameLoc();
+ if (SS.getRange().isValid())
+ Loc = SS.getRange().getBegin();
+ BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true);
}
bool ShouldCheckUse = true;
@@ -2610,7 +2675,6 @@ Sema::OwningExprResult
Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
bool &IsArrow, SourceLocation OpLoc,
const CXXScopeSpec &SS,
- NamedDecl *FirstQualifierInScope,
DeclPtrTy ObjCImpDecl) {
assert(BaseExpr && "no base expression");
@@ -2848,6 +2912,22 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
ObjCInterfaceDecl *ClassDeclared;
ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
+ if (!IV) {
+ // Attempt to correct for typos in ivar names.
+ LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
+ LookupMemberName);
+ if (CorrectTypo(Res, 0, 0, IDecl) &&
+ (IV = Res.getAsSingle<ObjCIvarDecl>())) {
+ Diag(R.getNameLoc(),
+ diag::err_typecheck_member_reference_ivar_suggest)
+ << IDecl->getDeclName() << MemberName << IV->getDeclName()
+ << CodeModificationHint::CreateReplacement(R.getNameLoc(),
+ IV->getNameAsString());
+ Diag(IV->getLocation(), diag::note_previous_decl)
+ << IV->getDeclName();
+ }
+ }
+
if (IV) {
// If the decl being referenced had an error, return an error for this
// sub-expr without emitting another error, in order to avoid cascading
@@ -3014,6 +3094,24 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType,
Setter, MemberLoc, BaseExpr));
}
+
+ // Attempt to correct for typos in property names.
+ LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
+ LookupOrdinaryName);
+ if (CorrectTypo(Res, 0, 0, IFace, false, OPT) &&
+ Res.getAsSingle<ObjCPropertyDecl>()) {
+ Diag(R.getNameLoc(), diag::err_property_not_found_suggest)
+ << MemberName << BaseType << Res.getLookupName()
+ << CodeModificationHint::CreateReplacement(R.getNameLoc(),
+ Res.getLookupName().getAsString());
+ ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>();
+ Diag(Property->getLocation(), diag::note_previous_decl)
+ << Property->getDeclName();
+
+ return LookupMemberExpr(Res, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl);
+ }
+
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
<< MemberName << BaseType);
}
@@ -3101,7 +3199,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
Expr *Base = BaseArg.takeAs<Expr>();
OwningExprResult Result(*this);
- if (Base->getType()->isDependentType()) {
+ if (Base->getType()->isDependentType() || Name.isDependentName()) {
Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(),
IsArrow, OpLoc,
SS, FirstQualifierInScope,
@@ -3114,8 +3212,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
DecomposeTemplateName(R, Id);
} else {
Result = LookupMemberExpr(R, Base, IsArrow, OpLoc,
- SS, FirstQualifierInScope,
- ObjCImpDecl);
+ SS, ObjCImpDecl);
if (Result.isInvalid()) {
Owned(Base);
@@ -3136,7 +3233,8 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
}
Result = BuildMemberReferenceExpr(ExprArg(*this, Base), Base->getType(),
- OpLoc, IsArrow, SS, R, TemplateArgs);
+ OpLoc, IsArrow, SS, FirstQualifierInScope,
+ R, TemplateArgs);
}
return move(Result);
@@ -4717,8 +4815,7 @@ QualType Sema::InvalidOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
return QualType();
}
-inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
- Expr *&rex) {
+QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
QualType lhsType =
@@ -4779,19 +4876,27 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
return QualType();
}
-inline QualType Sema::CheckMultiplyDivideOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
+QualType Sema::CheckMultiplyDivideOperands(
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign, bool isDiv) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
return CheckVectorOperands(Loc, lex, rex);
QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
- if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
- return compType;
- return InvalidOperands(Loc, lex, rex);
+ if (!lex->getType()->isArithmeticType() ||
+ !rex->getType()->isArithmeticType())
+ return InvalidOperands(Loc, lex, rex);
+
+ // Check for division by zero.
+ if (isDiv &&
+ rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
+ DiagRuntimeBehavior(Loc, PDiag(diag::warn_division_by_zero)
+ << rex->getSourceRange());
+
+ return compType;
}
-inline QualType Sema::CheckRemainderOperands(
+QualType Sema::CheckRemainderOperands(
Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType())
@@ -4801,12 +4906,18 @@ inline QualType Sema::CheckRemainderOperands(
QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
- if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType())
- return compType;
- return InvalidOperands(Loc, lex, rex);
+ if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType())
+ return InvalidOperands(Loc, lex, rex);
+
+ // Check for remainder by zero.
+ if (rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
+ DiagRuntimeBehavior(Loc, PDiag(diag::warn_remainder_by_zero)
+ << rex->getSourceRange());
+
+ return compType;
}
-inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
+QualType Sema::CheckAdditionOperands( // C99 6.5.6
Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
QualType compType = CheckVectorOperands(Loc, lex, rex);
@@ -5072,80 +5183,6 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
return LHSTy;
}
-/// \brief Implements -Wsign-compare.
-///
-/// \param lex the left-hand expression
-/// \param rex the right-hand expression
-/// \param OpLoc the location of the joining operator
-/// \param Equality whether this is an "equality-like" join, which
-/// suppresses the warning in some cases
-void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc,
- const PartialDiagnostic &PD, bool Equality) {
- // Don't warn if we're in an unevaluated context.
- if (ExprEvalContexts.back().Context == Unevaluated)
- return;
-
- QualType lt = lex->getType(), rt = rex->getType();
-
- // Only warn if both operands are integral.
- if (!lt->isIntegerType() || !rt->isIntegerType())
- return;
-
- // If either expression is value-dependent, don't warn. We'll get another
- // chance at instantiation time.
- if (lex->isValueDependent() || rex->isValueDependent())
- return;
-
- // The rule is that the signed operand becomes unsigned, so isolate the
- // signed operand.
- Expr *signedOperand, *unsignedOperand;
- if (lt->isSignedIntegerType()) {
- if (rt->isSignedIntegerType()) return;
- signedOperand = lex;
- unsignedOperand = rex;
- } else {
- if (!rt->isSignedIntegerType()) return;
- signedOperand = rex;
- unsignedOperand = lex;
- }
-
- // If the unsigned type is strictly smaller than the signed type,
- // then (1) the result type will be signed and (2) the unsigned
- // value will fit fully within the signed type, and thus the result
- // of the comparison will be exact.
- if (Context.getIntWidth(signedOperand->getType()) >
- Context.getIntWidth(unsignedOperand->getType()))
- return;
-
- // If the value is a non-negative integer constant, then the
- // signed->unsigned conversion won't change it.
- llvm::APSInt value;
- if (signedOperand->isIntegerConstantExpr(value, Context)) {
- assert(value.isSigned() && "result of signed expression not signed");
-
- if (value.isNonNegative())
- return;
- }
-
- if (Equality) {
- // For (in)equality comparisons, if the unsigned operand is a
- // constant which cannot collide with a overflowed signed operand,
- // then reinterpreting the signed operand as unsigned will not
- // change the result of the comparison.
- if (unsignedOperand->isIntegerConstantExpr(value, Context)) {
- assert(!value.isSigned() && "result of unsigned expression is signed");
-
- // 2's complement: test the top bit.
- if (value.isNonNegative())
- return;
- }
- }
-
- Diag(OpLoc, PD)
- << lex->getType() << rex->getType()
- << lex->getSourceRange() << rex->getSourceRange();
-}
-
// C99 6.5.8, C++ [expr.rel]
QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
unsigned OpaqueOpc, bool isRelational) {
@@ -5181,7 +5218,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped))
if (DRL->getDecl() == DRR->getDecl() &&
!isa<EnumConstantDecl>(DRL->getDecl()))
- Diag(Loc, diag::warn_selfcomparison);
+ DiagRuntimeBehavior(Loc, PDiag(diag::warn_selfcomparison));
if (isa<CastExpr>(LHSStripped))
LHSStripped = LHSStripped->IgnoreParenCasts();
@@ -5216,15 +5253,17 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
case BinaryOperator::NE: resultComparison = ") != 0"; break;
default: assert(false && "Invalid comparison operator");
}
- Diag(Loc, diag::warn_stringcompare)
- << isa<ObjCEncodeExpr>(literalStringStripped)
- << literalString->getSourceRange()
- << CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ")
- << CodeModificationHint::CreateInsertion(lex->getLocStart(),
- "strcmp(")
- << CodeModificationHint::CreateInsertion(
- PP.getLocForEndOfToken(rex->getLocEnd()),
- resultComparison);
+
+ DiagRuntimeBehavior(Loc,
+ PDiag(diag::warn_stringcompare)
+ << isa<ObjCEncodeExpr>(literalStringStripped)
+ << literalString->getSourceRange()
+ << CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ")
+ << CodeModificationHint::CreateInsertion(lex->getLocStart(),
+ "strcmp(")
+ << CodeModificationHint::CreateInsertion(
+ PP.getLocForEndOfToken(rex->getLocEnd()),
+ resultComparison));
}
}
@@ -5488,7 +5527,7 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex,
if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex->IgnoreParens()))
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex->IgnoreParens()))
if (DRL->getDecl() == DRR->getDecl())
- Diag(Loc, diag::warn_selfcomparison);
+ DiagRuntimeBehavior(Loc, PDiag(diag::warn_selfcomparison));
}
// Check for comparisons of floating point operands using != and ==.
@@ -5776,7 +5815,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
<< PointeeTy << Op->getSourceRange();
return QualType();
}
- } else if (ResType->isComplexType()) {
+ } else if (ResType->isAnyComplexType()) {
// C99 does not support ++/-- on complex types, we allow as an extension.
Diag(OpLoc, diag::ext_integer_increment_complex)
<< ResType << Op->getSourceRange();
@@ -5877,7 +5916,22 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
NamedDecl *dcl = getPrimaryDecl(op);
Expr::isLvalueResult lval = op->isLvalue(Context);
- if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) {
+ MemberExpr *ME = dyn_cast<MemberExpr>(op);
+ if (lval == Expr::LV_MemberFunction && ME &&
+ isa<CXXMethodDecl>(ME->getMemberDecl())) {
+ ValueDecl *dcl = cast<MemberExpr>(op)->getMemberDecl();
+ // &f where f is a member of the current object, or &o.f, or &p->f
+ // All these are not allowed, and we need to catch them before the dcl
+ // branch of the if, below.
+ Diag(OpLoc, diag::err_unqualified_pointer_member_function)
+ << dcl;
+ // FIXME: Improve this diagnostic and provide a fixit.
+
+ // Now recover by acting as if the function had been accessed qualified.
+ return Context.getMemberPointerType(op->getType(),
+ Context.getTypeDeclType(cast<RecordDecl>(dcl->getDeclContext()))
+ .getTypePtr());
+ } else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) {
// C99 6.5.3.2p1
// The operand must be either an l-value or a function designator
if (!op->getType()->isFunctionType()) {
@@ -6065,7 +6119,8 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BinaryOperator::Mul:
case BinaryOperator::Div:
- ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc);
+ ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, false,
+ Opc == BinaryOperator::Div);
break;
case BinaryOperator::Rem:
ResultTy = CheckRemainderOperands(lhs, rhs, OpLoc);
@@ -6101,7 +6156,8 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BinaryOperator::MulAssign:
case BinaryOperator::DivAssign:
- CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true);
+ CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true,
+ Opc == BinaryOperator::DivAssign);
CompLHSTy = CompResultTy;
if (!CompResultTy.isNull())
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
@@ -6155,8 +6211,9 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
/// ParenRange in parentheses.
static void SuggestParentheses(Sema &Self, SourceLocation Loc,
const PartialDiagnostic &PD,
- SourceRange ParenRange)
-{
+ SourceRange ParenRange,
+ const PartialDiagnostic &SecondPD = PartialDiagnostic(0),
+ SourceRange SecondParenRange = SourceRange()) {
SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd());
if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
// We can't display the parentheses, so just dig the
@@ -6168,6 +6225,21 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc,
Self.Diag(Loc, PD)
<< CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(")
<< CodeModificationHint::CreateInsertion(EndLoc, ")");
+
+ if (!SecondPD.getDiagID())
+ return;
+
+ EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd());
+ if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
+ // We can't display the parentheses, so just dig the
+ // warning/error and return.
+ Self.Diag(Loc, SecondPD);
+ return;
+ }
+
+ Self.Diag(Loc, SecondPD)
+ << CodeModificationHint::CreateInsertion(SecondParenRange.getBegin(), "(")
+ << CodeModificationHint::CreateInsertion(EndLoc, ")");
}
/// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
@@ -6199,12 +6271,18 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc,
PDiag(diag::warn_precedence_bitwise_rel)
<< SourceRange(lhs->getLocStart(), OpLoc)
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc),
+ lhs->getSourceRange(),
+ PDiag(diag::note_precedence_bitwise_first)
+ << BinOp::getOpcodeStr(Opc),
SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()));
else if (BinOp::isComparisonOp(rhsopc))
SuggestParentheses(Self, OpLoc,
PDiag(diag::warn_precedence_bitwise_rel)
<< SourceRange(OpLoc, rhs->getLocEnd())
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc),
+ rhs->getSourceRange(),
+ PDiag(diag::note_precedence_bitwise_first)
+ << BinOp::getOpcodeStr(Opc),
SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()));
}
@@ -6790,7 +6868,9 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking;
BSI->TheDecl->setBody(body.takeAs<CompoundStmt>());
- CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody());
+ AnalysisContext AC(BSI->TheDecl);
+ CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC);
+ CheckUnreachable(AC);
return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy,
BSI->hasBlockDeclRefExprs));
}
@@ -7256,6 +7336,8 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
<< E->getSourceRange()
<< CodeModificationHint::CreateInsertion(Open, "(")
<< CodeModificationHint::CreateInsertion(Close, ")");
+ Diag(Loc, diag::note_condition_assign_to_comparison)
+ << CodeModificationHint::CreateReplacement(Loc, "==");
}
bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) {
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 5f723f9..d10e11f 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -179,7 +179,8 @@ Action::OwningExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) {
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext))
if (MD->isInstance())
return Owned(new (Context) CXXThisExpr(ThisLoc,
- MD->getThisType(Context)));
+ MD->getThisType(Context),
+ /*isImplicit=*/false));
return ExprError(Diag(ThisLoc, diag::err_invalid_this_use));
}
@@ -672,20 +673,20 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
case OR_No_Viable_Function:
Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
<< Name << Range;
- PrintOverloadCandidates(Candidates, /*OnlyViable=*/false);
+ PrintOverloadCandidates(Candidates, OCD_AllCandidates, Args, NumArgs);
return true;
case OR_Ambiguous:
Diag(StartLoc, diag::err_ovl_ambiguous_call)
<< Name << Range;
- PrintOverloadCandidates(Candidates, /*OnlyViable=*/true);
+ PrintOverloadCandidates(Candidates, OCD_ViableCandidates, Args, NumArgs);
return true;
case OR_Deleted:
Diag(StartLoc, diag::err_ovl_deleted_call)
<< Best->Function->isDeleted()
<< Name << Range;
- PrintOverloadCandidates(Candidates, /*OnlyViable=*/true);
+ PrintOverloadCandidates(Candidates, OCD_AllCandidates, Args, NumArgs);
return true;
}
assert(false && "Unreachable, bad result from BestViableFunction");
@@ -921,7 +922,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
<< Type << Ex->getSourceRange();
for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) {
CXXConversionDecl *Conv = ObjectPtrConversions[i];
- Diag(Conv->getLocation(), diag::err_ovl_candidate);
+ NoteOverloadCandidate(Conv);
}
return ExprError();
}
@@ -1074,7 +1075,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
AssignmentAction Action, bool AllowExplicit,
bool Elidable,
ImplicitConversionSequence& ICS) {
- ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+ ICS.setBad();
+ ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
if (Elidable && getLangOptions().CPlusPlus0x) {
ICS = TryImplicitConversion(From, ToType,
/*SuppressUserConversions=*/false,
@@ -1082,7 +1084,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
/*ForceRValue=*/true,
/*InOverloadResolution=*/false);
}
- if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) {
+ if (ICS.isBad()) {
ICS = TryImplicitConversion(From, ToType,
/*SuppressUserConversions=*/false,
AllowExplicit,
@@ -1092,39 +1094,6 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
return PerformImplicitConversion(From, ToType, ICS, Action);
}
-/// BuildCXXDerivedToBaseExpr - This routine generates the suitable AST
-/// for the derived to base conversion of the expression 'From'. All
-/// necessary information is passed in ICS.
-bool
-Sema::BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind,
- const ImplicitConversionSequence& ICS) {
- QualType BaseType =
- QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr);
- // Must do additional defined to base conversion.
- QualType DerivedType =
- QualType::getFromOpaquePtr(ICS.UserDefined.After.FromTypePtr);
-
- From = new (Context) ImplicitCastExpr(
- DerivedType.getNonReferenceType(),
- CastKind,
- From,
- DerivedType->isLValueReferenceType());
- From = new (Context) ImplicitCastExpr(BaseType.getNonReferenceType(),
- CastExpr::CK_DerivedToBase, From,
- BaseType->isLValueReferenceType());
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
- OwningExprResult FromResult =
- BuildCXXConstructExpr(
- ICS.UserDefined.After.CopyConstructor->getLocation(),
- BaseType,
- ICS.UserDefined.After.CopyConstructor,
- MultiExprArg(*this, (void **)&From, 1));
- if (FromResult.isInvalid())
- return true;
- From = FromResult.takeAs<Expr>();
- return false;
-}
-
/// PerformImplicitConversion - Perform an implicit conversion of the
/// expression From to the type ToType using the pre-computed implicit
/// conversion sequence ICS. Returns true if there was an error, false
@@ -1135,7 +1104,7 @@ bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
const ImplicitConversionSequence &ICS,
AssignmentAction Action, bool IgnoreBaseAccess) {
- switch (ICS.ConversionKind) {
+ switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
if (PerformImplicitConversion(From, ToType, ICS.Standard, Action,
IgnoreBaseAccess))
@@ -1186,23 +1155,15 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
From = CastArg.takeAs<Expr>();
- // FIXME: This and the following if statement shouldn't be necessary, but
- // 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);
- }
-
- if (ICS.UserDefined.After.CopyConstructor) {
- From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(),
- CastKind, From,
- ToType->isLValueReferenceType());
- return false;
- }
-
return PerformImplicitConversion(From, ToType, ICS.UserDefined.After,
AA_Converting, IgnoreBaseAccess);
}
+
+ case ImplicitConversionSequence::AmbiguousConversion:
+ DiagnoseAmbiguousConversion(ICS, From->getExprLoc(),
+ PDiag(diag::err_typecheck_ambiguous_condition)
+ << From->getSourceRange());
+ return true;
case ImplicitConversionSequence::EllipsisConversion:
assert(false && "Cannot perform an ellipsis conversion");
@@ -1520,14 +1481,18 @@ QualType Sema::CheckPointerToMemberOperands(
/// \brief Get the target type of a standard or user-defined conversion.
static QualType TargetType(const ImplicitConversionSequence &ICS) {
- assert((ICS.ConversionKind ==
- ImplicitConversionSequence::StandardConversion ||
- ICS.ConversionKind ==
- ImplicitConversionSequence::UserDefinedConversion) &&
- "function only valid for standard or user-defined conversions");
- if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion)
- return QualType::getFromOpaquePtr(ICS.Standard.ToTypePtr);
- return QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr);
+ switch (ICS.getKind()) {
+ case ImplicitConversionSequence::StandardConversion:
+ return ICS.Standard.getToType();
+ case ImplicitConversionSequence::UserDefinedConversion:
+ return ICS.UserDefined.After.getToType();
+ case ImplicitConversionSequence::AmbiguousConversion:
+ return ICS.Ambiguous.getToType();
+ case ImplicitConversionSequence::EllipsisConversion:
+ case ImplicitConversionSequence::BadConversion:
+ llvm_unreachable("function not valid for ellipsis or bad conversions");
+ }
+ return QualType(); // silence warnings
}
/// \brief Try to convert a type to another according to C++0x 5.16p3.
@@ -1557,19 +1522,16 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
/*ForceRValue=*/false,
&ICS))
{
- assert((ICS.ConversionKind ==
- ImplicitConversionSequence::StandardConversion ||
- ICS.ConversionKind ==
- ImplicitConversionSequence::UserDefinedConversion) &&
+ assert((ICS.isStandard() || ICS.isUserDefined()) &&
"expected a definite conversion");
bool DirectBinding =
- ICS.ConversionKind == ImplicitConversionSequence::StandardConversion ?
- ICS.Standard.DirectBinding : ICS.UserDefined.After.DirectBinding;
+ ICS.isStandard() ? ICS.Standard.DirectBinding
+ : ICS.UserDefined.After.DirectBinding;
if (DirectBinding)
return false;
}
}
- ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+ ICS.setBad();
// -- If E2 is an rvalue, or if the conversion above cannot be done:
// -- if E1 and E2 have class type, and the underlying class types are
// the same or one is a base class of the other:
@@ -1665,8 +1627,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
/// handles the reference binding specially.
static bool ConvertForConditional(Sema &Self, Expr *&E,
const ImplicitConversionSequence &ICS) {
- if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion &&
- ICS.Standard.ReferenceBinding) {
+ if (ICS.isStandard() && ICS.Standard.ReferenceBinding) {
assert(ICS.Standard.DirectBinding &&
"TryClassUnification should never generate indirect ref bindings");
// FIXME: CheckReferenceInit should be able to reuse the ICS instead of
@@ -1678,8 +1639,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E,
/*AllowExplicit=*/false,
/*ForceRValue=*/false);
}
- if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion &&
- ICS.UserDefined.After.ReferenceBinding) {
+ if (ICS.isUserDefined() && ICS.UserDefined.After.ReferenceBinding) {
assert(ICS.UserDefined.After.DirectBinding &&
"TryClassUnification should never generate indirect ref bindings");
return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType(
@@ -1767,10 +1727,8 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (TryClassUnification(*this, RHS, LHS, QuestionLoc, ICSRightToLeft))
return QualType();
- bool HaveL2R = ICSLeftToRight.ConversionKind !=
- ImplicitConversionSequence::BadConversion;
- bool HaveR2L = ICSRightToLeft.ConversionKind !=
- ImplicitConversionSequence::BadConversion;
+ bool HaveL2R = !ICSLeftToRight.isBad();
+ bool HaveR2L = !ICSRightToLeft.isBad();
// If both can be converted, [...] the program is ill-formed.
if (HaveL2R && HaveR2L) {
Diag(QuestionLoc, diag::err_conditional_ambiguous)
@@ -1837,6 +1795,12 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// type and the other is a null pointer constant; pointer conversions
// and qualification conversions are performed to bring them to their
// composite pointer type. The result is of the composite pointer type.
+ // -- The second and third operands have pointer to member type, or one has
+ // pointer to member type and the other is a null pointer constant;
+ // pointer to member conversions and qualification conversions are
+ // performed to bring them to a common type, whose cv-qualification
+ // shall match the cv-qualification of either the second or the third
+ // operand. The result is of the common type.
QualType Composite = FindCompositePointerType(LHS, RHS);
if (!Composite.isNull())
return Composite;
@@ -1846,83 +1810,6 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (!Composite.isNull())
return Composite;
- // Fourth bullet is same for pointers-to-member. However, the possible
- // conversions are far more limited: we have null-to-pointer, upcast of
- // containing class, and second-level cv-ness.
- // cv-ness is not a union, but must match one of the two operands. (Which,
- // frankly, is stupid.)
- const MemberPointerType *LMemPtr = LTy->getAs<MemberPointerType>();
- const MemberPointerType *RMemPtr = RTy->getAs<MemberPointerType>();
- if (LMemPtr &&
- RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
- ImpCastExprToType(RHS, LTy, CastExpr::CK_NullToMemberPointer);
- return LTy;
- }
- if (RMemPtr &&
- LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
- ImpCastExprToType(LHS, RTy, CastExpr::CK_NullToMemberPointer);
- return RTy;
- }
- if (LMemPtr && RMemPtr) {
- QualType LPointee = LMemPtr->getPointeeType();
- QualType RPointee = RMemPtr->getPointeeType();
-
- QualifierCollector LPQuals, RPQuals;
- const Type *LPCan = LPQuals.strip(Context.getCanonicalType(LPointee));
- const Type *RPCan = RPQuals.strip(Context.getCanonicalType(RPointee));
-
- // First, we check that the unqualified pointee type is the same. If it's
- // not, there's no conversion that will unify the two pointers.
- if (LPCan == RPCan) {
-
- // Second, we take the greater of the two qualifications. If neither
- // is greater than the other, the conversion is not possible.
-
- Qualifiers MergedQuals = LPQuals + RPQuals;
-
- bool CompatibleQuals = true;
- if (MergedQuals.getCVRQualifiers() != LPQuals.getCVRQualifiers() &&
- MergedQuals.getCVRQualifiers() != RPQuals.getCVRQualifiers())
- CompatibleQuals = false;
- else if (LPQuals.getAddressSpace() != RPQuals.getAddressSpace())
- // FIXME:
- // C99 6.5.15 as modified by TR 18037:
- // If the second and third operands are pointers into different
- // address spaces, the address spaces must overlap.
- CompatibleQuals = false;
- // FIXME: GC qualifiers?
-
- if (CompatibleQuals) {
- // Third, we check if either of the container classes is derived from
- // the other.
- QualType LContainer(LMemPtr->getClass(), 0);
- QualType RContainer(RMemPtr->getClass(), 0);
- QualType MoreDerived;
- if (Context.getCanonicalType(LContainer) ==
- Context.getCanonicalType(RContainer))
- MoreDerived = LContainer;
- else if (IsDerivedFrom(LContainer, RContainer))
- MoreDerived = LContainer;
- else if (IsDerivedFrom(RContainer, LContainer))
- MoreDerived = RContainer;
-
- if (!MoreDerived.isNull()) {
- // The type 'Q Pointee (MoreDerived::*)' is the common type.
- // We don't use ImpCastExprToType here because this could still fail
- // for ambiguous or inaccessible conversions.
- LPointee = Context.getQualifiedType(LPointee, MergedQuals);
- QualType Common
- = Context.getMemberPointerType(LPointee, MoreDerived.getTypePtr());
- if (PerformImplicitConversion(LHS, Common, Sema::AA_Converting))
- return QualType();
- if (PerformImplicitConversion(RHS, Common, Sema::AA_Converting))
- return QualType();
- return Common;
- }
- }
- }
- }
-
Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
<< LHS->getType() << RHS->getType()
<< LHS->getSourceRange() << RHS->getSourceRange();
@@ -2055,8 +1942,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
/*InOverloadResolution=*/false);
ImplicitConversionSequence E1ToC2, E2ToC2;
- E1ToC2.ConversionKind = ImplicitConversionSequence::BadConversion;
- E2ToC2.ConversionKind = ImplicitConversionSequence::BadConversion;
+ E1ToC2.setBad();
+ E2ToC2.setBad();
if (Context.getCanonicalType(Composite1) !=
Context.getCanonicalType(Composite2)) {
E1ToC2 = TryImplicitConversion(E1, Composite2,
@@ -2071,14 +1958,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
/*InOverloadResolution=*/false);
}
- bool ToC1Viable = E1ToC1.ConversionKind !=
- ImplicitConversionSequence::BadConversion
- && E2ToC1.ConversionKind !=
- ImplicitConversionSequence::BadConversion;
- bool ToC2Viable = E1ToC2.ConversionKind !=
- ImplicitConversionSequence::BadConversion
- && E2ToC2.ConversionKind !=
- ImplicitConversionSequence::BadConversion;
+ bool ToC1Viable = !E1ToC1.isBad() && !E2ToC1.isBad();
+ bool ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad();
if (ToC1Viable && !ToC2Viable) {
if (!PerformImplicitConversion(E1, Composite1, E1ToC1, Sema::AA_Converting) &&
!PerformImplicitConversion(E2, Composite1, E2ToC1, Sema::AA_Converting))
@@ -2305,71 +2186,3 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
return Owned(FullExpr);
}
-
-/// \brief Determine whether a reference to the given declaration in the
-/// current context is an implicit member access
-/// (C++ [class.mfct.non-static]p2).
-///
-/// FIXME: Should Objective-C also use this approach?
-///
-/// \param D the declaration being referenced from the current scope.
-///
-/// \param NameLoc the location of the name in the source.
-///
-/// \param ThisType if the reference to this declaration is an implicit member
-/// access, will be set to the type of the "this" pointer to be used when
-/// building that implicit member access.
-///
-/// \returns true if this is an implicit member reference (in which case
-/// \p ThisType and \p MemberType will be set), or false if it is not an
-/// implicit member reference.
-bool Sema::isImplicitMemberReference(const LookupResult &R,
- QualType &ThisType) {
- // If this isn't a C++ method, then it isn't an implicit member reference.
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext);
- if (!MD || MD->isStatic())
- return false;
-
- // C++ [class.mfct.nonstatic]p2:
- // [...] if name lookup (3.4.1) resolves the name in the
- // id-expression to a nonstatic nontype member of class X or of
- // a base class of X, the id-expression is transformed into a
- // class member access expression (5.2.5) using (*this) (9.3.2)
- // as the postfix-expression to the left of the '.' operator.
- DeclContext *Ctx = 0;
- if (R.isUnresolvableResult()) {
- // FIXME: this is just picking one at random
- Ctx = R.getRepresentativeDecl()->getDeclContext();
- } else if (FieldDecl *FD = R.getAsSingle<FieldDecl>()) {
- Ctx = FD->getDeclContext();
- } else {
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*I);
- FunctionTemplateDecl *FunTmpl = 0;
- if (!Method && (FunTmpl = dyn_cast<FunctionTemplateDecl>(*I)))
- Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
-
- // FIXME: Do we have to know if there are explicit template arguments?
- if (Method && !Method->isStatic()) {
- Ctx = Method->getParent();
- break;
- }
- }
- }
-
- if (!Ctx || !Ctx->isRecord())
- return false;
-
- // Determine whether the declaration(s) we found are actually in a base
- // class. If not, this isn't an implicit member reference.
- ThisType = MD->getThisType(Context);
-
- // FIXME: this doesn't really work for overloaded lookups.
-
- QualType CtxType = Context.getTypeDeclType(cast<CXXRecordDecl>(Ctx));
- QualType ClassType
- = Context.getTypeDeclType(cast<CXXRecordDecl>(MD->getParent()));
- return Context.hasSameType(CtxType, ClassType) ||
- IsDerivedFrom(ClassType, CtxType);
-}
-
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 2e31e47..85889fa 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -287,7 +287,8 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
SourceLocation &receiverNameLoc,
SourceLocation &propertyNameLoc) {
- ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(&receiverName);
+ IdentifierInfo *receiverNamePtr = &receiverName;
+ ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr);
// Search for a declared property first.
@@ -400,7 +401,7 @@ Sema::ExprResult Sema::ActOnClassMessage(
return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName;
}
} else
- ClassDecl = getObjCInterfaceDecl(receiverName);
+ ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc);
// The following code allows for the following GCC-ism:
//
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 3ef5156..1970f56 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -88,7 +88,7 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType,
S.Diag(Init->getSourceRange().getBegin(),
diag::err_typecheck_convert_ambiguous)
<< DeclType << Init->getType() << Init->getSourceRange();
- S.PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ S.PrintOverloadCandidates(CandidateSet, Sema::OCD_AllCandidates, &Init, 1);
return true;
}
return false;
@@ -670,7 +670,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
/*ForceRValue=*/false,
/*InOverloadResolution=*/false);
- if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion) {
+ if (!ICS.isBad()) {
if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS,
Sema::AA_Initializing))
hadError = true;
@@ -1136,7 +1136,7 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
// Expand the current designator into the set of replacement
// designators, so we have a full subobject path down to where the
// member of the anonymous struct/union is actually stored.
- DIE->ExpandDesignator(DesigIdx, &Replacements[0],
+ DIE->ExpandDesignator(SemaRef.Context, DesigIdx, &Replacements[0],
&Replacements[0] + Replacements.size());
// Update FieldIter/FieldIndex;
@@ -1302,6 +1302,9 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
<< FieldName << CurrentObjectType << R.getLookupName()
<< CodeModificationHint::CreateReplacement(D->getFieldLoc(),
R.getLookupName().getAsString());
+ SemaRef.Diag(ReplacementField->getLocation(),
+ diag::note_previous_decl)
+ << ReplacementField->getDeclName();
} else {
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
<< FieldName << CurrentObjectType;
@@ -2224,9 +2227,11 @@ static void TryReferenceInitialization(Sema &S,
QualType DestType = Entity.getType();
QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
- QualType T1 = cv1T1.getUnqualifiedType();
+ Qualifiers T1Quals;
+ QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals);
QualType cv2T2 = Initializer->getType();
- QualType T2 = cv2T2.getUnqualifiedType();
+ Qualifiers T2Quals;
+ QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals);
SourceLocation DeclLoc = Initializer->getLocStart();
// If the initializer is the address of an overloaded function, try
@@ -2276,9 +2281,9 @@ static void TryReferenceInitialization(Sema &S,
// can occur. This property will be checked by PerformInitialization.
if (DerivedToBase)
Sequence.AddDerivedToBaseCastStep(
- S.Context.getQualifiedType(T1, cv2T2.getQualifiers()),
+ S.Context.getQualifiedType(T1, T2Quals),
/*isLValue=*/true);
- if (cv1T1.getQualifiers() != cv2T2.getQualifiers())
+ if (T1Quals != T2Quals)
Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/true);
Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/false);
return;
@@ -2297,6 +2302,11 @@ static void TryReferenceInitialization(Sema &S,
Sequence);
if (ConvOvlResult == OR_Success)
return;
+ if (ConvOvlResult != OR_No_Viable_Function) {
+ Sequence.SetOverloadFailure(
+ InitializationSequence::FK_ReferenceInitOverloadFailed,
+ ConvOvlResult);
+ }
}
}
@@ -2304,7 +2314,7 @@ static void TryReferenceInitialization(Sema &S,
// non-volatile const type (i.e., cv1 shall be const), or the reference
// shall be an rvalue reference and the initializer expression shall
// be an rvalue.
- if (!((isLValueRef && cv1T1.getCVRQualifiers() == Qualifiers::Const) ||
+ if (!((isLValueRef && T1Quals.hasConst()) ||
(isRValueRef && InitLvalue != Expr::LV_Valid))) {
if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty())
Sequence.SetOverloadFailure(
@@ -2331,9 +2341,9 @@ static void TryReferenceInitialization(Sema &S,
RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
if (DerivedToBase)
Sequence.AddDerivedToBaseCastStep(
- S.Context.getQualifiedType(T1, cv2T2.getQualifiers()),
+ S.Context.getQualifiedType(T1, T2Quals),
/*isLValue=*/false);
- if (cv1T1.getQualifiers() != cv2T2.getQualifiers())
+ if (T1Quals != T2Quals)
Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/false);
Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true);
return;
@@ -2381,7 +2391,7 @@ static void TryReferenceInitialization(Sema &S,
/*FIXME:InOverloadResolution=*/false,
/*UserCast=*/Kind.isExplicitCast());
- if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) {
+ if (ICS.isBad()) {
// FIXME: Use the conversion function set stored in ICS to turn
// this into an overloading ambiguity diagnostic. However, we need
// to keep that set as an OverloadCandidateSet rather than as some
@@ -2398,8 +2408,10 @@ static void TryReferenceInitialization(Sema &S,
// [...] If T1 is reference-related to T2, cv1 must be the
// same cv-qualification as, or greater cv-qualification
// than, cv2; otherwise, the program is ill-formed.
+ unsigned T1CVRQuals = T1Quals.getCVRQualifiers();
+ unsigned T2CVRQuals = T2Quals.getCVRQualifiers();
if (RefRelationship == Sema::Ref_Related &&
- !cv1T1.isAtLeastAsQualifiedAs(cv2T2)) {
+ (T1CVRQuals | T2CVRQuals) != T1CVRQuals) {
Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers);
return;
}
@@ -2682,14 +2694,14 @@ static void TryUserDefinedConversion(Sema &S,
// Perform overload resolution. If it fails, return the failed result.
OverloadCandidateSet::iterator Best;
- if (OverloadingResult Result
+ if (OverloadingResult Result
= S.BestViableFunction(CandidateSet, DeclLoc, Best)) {
Sequence.SetOverloadFailure(
InitializationSequence::FK_UserConversionOverloadFailed,
Result);
return;
}
-
+
FunctionDecl *Function = Best->Function;
if (isa<CXXConstructorDecl>(Function)) {
@@ -2708,7 +2720,7 @@ static void TryUserDefinedConversion(Sema &S,
if (Best->FinalConversion.First || Best->FinalConversion.Second ||
Best->FinalConversion.Third) {
ImplicitConversionSequence ICS;
- ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
+ ICS.setStandard();
ICS.Standard = Best->FinalConversion;
Sequence.AddConversionSequenceStep(ICS, DestType);
}
@@ -2729,7 +2741,7 @@ static void TryImplicitConversion(Sema &S,
/*FIXME:InOverloadResolution=*/false,
/*UserCast=*/Kind.isExplicitCast());
- if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) {
+ if (ICS.isBad()) {
Sequence.SetFailed(InitializationSequence::FK_ConversionFailed);
return;
}
@@ -3007,14 +3019,16 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
S.Diag(Loc, diag::err_temp_copy_no_viable)
<< (int)Entity.getKind() << CurInitExpr->getType()
<< CurInitExpr->getSourceRange();
- S.PrintOverloadCandidates(CandidateSet, false);
+ S.PrintOverloadCandidates(CandidateSet, Sema::OCD_AllCandidates,
+ &CurInitExpr, 1);
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);
+ S.PrintOverloadCandidates(CandidateSet, Sema::OCD_ViableCandidates,
+ &CurInitExpr, 1);
return S.ExprError();
case OR_Deleted:
@@ -3429,14 +3443,16 @@ bool InitializationSequence::Diagnose(Sema &S,
<< DestType << Args[0]->getType()
<< Args[0]->getSourceRange();
- S.PrintOverloadCandidates(FailedCandidateSet, true);
+ S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_ViableCandidates,
+ Args, NumArgs);
break;
case OR_No_Viable_Function:
S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition)
<< Args[0]->getType() << DestType.getNonReferenceType()
<< Args[0]->getSourceRange();
- S.PrintOverloadCandidates(FailedCandidateSet, false);
+ S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_AllCandidates,
+ Args, NumArgs);
break;
case OR_Deleted: {
@@ -3538,13 +3554,15 @@ bool InitializationSequence::Diagnose(Sema &S,
case OR_Ambiguous:
S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init)
<< DestType << ArgsRange;
- S.PrintOverloadCandidates(FailedCandidateSet, true);
+ S.PrintOverloadCandidates(FailedCandidateSet,
+ Sema::OCD_ViableCandidates, Args, NumArgs);
break;
case OR_No_Viable_Function:
S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init)
<< DestType << ArgsRange;
- S.PrintOverloadCandidates(FailedCandidateSet, false);
+ S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_AllCandidates,
+ Args, NumArgs);
break;
case OR_Deleted: {
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 1419ceb..cda245d 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -444,10 +444,83 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) {
bool Found = false;
DeclContext::lookup_const_iterator I, E;
- for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I)
- if (R.isAcceptableDecl(*I))
- R.addDecl(*I), Found = true;
+ for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) {
+ if (R.isAcceptableDecl(*I)) {
+ R.addDecl(*I);
+ Found = true;
+ }
+ }
+ if (R.getLookupName().getNameKind()
+ == DeclarationName::CXXConversionFunctionName &&
+ !R.getLookupName().getCXXNameType()->isDependentType() &&
+ isa<CXXRecordDecl>(DC)) {
+ // C++ [temp.mem]p6:
+ // A specialization of a conversion function template is not found by
+ // name lookup. Instead, any conversion function templates visible in the
+ // context of the use are considered. [...]
+ const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+ if (!Record->isDefinition())
+ return Found;
+
+ const UnresolvedSet *Unresolved = Record->getConversionFunctions();
+ for (UnresolvedSet::iterator U = Unresolved->begin(),
+ UEnd = Unresolved->end();
+ U != UEnd; ++U) {
+ FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U);
+ if (!ConvTemplate)
+ continue;
+
+ // When we're performing lookup for the purposes of redeclaration, just
+ // add the conversion function template. When we deduce template
+ // arguments for specializations, we'll end up unifying the return
+ // type of the new declaration with the type of the function template.
+ if (R.isForRedeclaration()) {
+ R.addDecl(ConvTemplate);
+ Found = true;
+ continue;
+ }
+
+ // C++ [temp.mem]p6:
+ // [...] For each such operator, if argument deduction succeeds
+ // (14.9.2.3), the resulting specialization is used as if found by
+ // name lookup.
+ //
+ // When referencing a conversion function for any purpose other than
+ // a redeclaration (such that we'll be building an expression with the
+ // result), perform template argument deduction and place the
+ // specialization into the result set. We do this to avoid forcing all
+ // callers to perform special deduction for conversion functions.
+ Sema::TemplateDeductionInfo Info(R.getSema().Context);
+ FunctionDecl *Specialization = 0;
+
+ const FunctionProtoType *ConvProto
+ = ConvTemplate->getTemplatedDecl()->getType()
+ ->getAs<FunctionProtoType>();
+ assert(ConvProto && "Nonsensical conversion function template type");
+
+ // Compute the type of the function that we would expect the conversion
+ // function to have, if it were to match the name given.
+ // FIXME: Calling convention!
+ QualType ExpectedType
+ = R.getSema().Context.getFunctionType(
+ R.getLookupName().getCXXNameType(),
+ 0, 0, ConvProto->isVariadic(),
+ ConvProto->getTypeQuals(),
+ false, false, 0, 0,
+ ConvProto->getNoReturnAttr());
+
+ // Perform template argument deduction against the type that we would
+ // expect the function to have.
+ if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType,
+ Specialization, Info)
+ == Sema::TDK_Success) {
+ R.addDecl(Specialization);
+ Found = true;
+ }
+ }
+ }
+
return Found;
}
@@ -550,7 +623,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// example, inside a class without any base classes, we never need to
// perform qualified lookup because all of the members are on top of the
// identifier chain.
- if (LookupQualifiedName(R, Ctx))
+ if (LookupQualifiedName(R, Ctx, /*InUnqualifiedLookup=*/true))
return true;
}
}
@@ -577,7 +650,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
for (; S; S = S->getParent()) {
DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
- if (Ctx->isTransparentContext())
+ if (!Ctx || Ctx->isTransparentContext())
continue;
assert(Ctx && Ctx->isFileContext() &&
@@ -854,11 +927,11 @@ static bool LookupQualifiedNameInUsingDirectives(LookupResult &R,
return Found;
}
-/// @brief Perform qualified name lookup into a given context.
+/// \brief Perform qualified name lookup into a given context.
///
/// Qualified name lookup (C++ [basic.lookup.qual]) is used to find
/// names when the context of those names is explicit specified, e.g.,
-/// "std::vector" or "x->member".
+/// "std::vector" or "x->member", or as part of unqualified name lookup.
///
/// Different lookup criteria can find different names. For example, a
/// particular scope can have both a struct and a function of the same
@@ -866,25 +939,18 @@ static bool LookupQualifiedNameInUsingDirectives(LookupResult &R,
/// information about lookup criteria, see the documentation for the
/// class LookupCriteria.
///
-/// @param LookupCtx The context in which qualified name lookup will
+/// \param R captures both the lookup criteria and any lookup results found.
+///
+/// \param LookupCtx The context in which qualified name lookup will
/// search. If the lookup criteria permits, name lookup may also search
/// in the parent contexts or (for C++ classes) base classes.
///
-/// @param Name The name of the entity that we are searching for.
+/// \param InUnqualifiedLookup true if this is qualified name lookup that
+/// occurs as part of unqualified name lookup.
///
-/// @param Criteria The criteria that this routine will use to
-/// determine which names are visible and which names will be
-/// found. Note that name lookup will find a name that is visible by
-/// the given criteria, but the entity itself may not be semantically
-/// correct or even the kind of entity expected based on the
-/// lookup. For example, searching for a nested-name-specifier name
-/// might result in an EnumDecl, which is visible but is not permitted
-/// as a nested-name-specifier in C++03.
-///
-/// @returns The result of name lookup, which includes zero or more
-/// declarations and possibly additional information used to diagnose
-/// ambiguities.
-bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) {
+/// \returns true if lookup succeeded, false if it failed.
+bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
+ bool InUnqualifiedLookup) {
assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context");
if (!R.getLookupName())
@@ -922,11 +988,22 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) {
// If this isn't a C++ class, we aren't allowed to look into base
// classes, we're done.
- if (!isa<CXXRecordDecl>(LookupCtx))
+ CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx);
+ if (!LookupRec)
return false;
+ // If we're performing qualified name lookup into a dependent class,
+ // then we are actually looking into a current instantiation. If we have any
+ // dependent base classes, then we either have to delay lookup until
+ // template instantiation time (at which point all bases will be available)
+ // or we have to fail.
+ if (!InUnqualifiedLookup && LookupRec->isDependentContext() &&
+ LookupRec->hasAnyDependentBases()) {
+ R.setNotFoundInCurrentInstantiation();
+ return false;
+ }
+
// Perform lookup into our base classes.
- CXXRecordDecl *LookupRec = cast<CXXRecordDecl>(LookupCtx);
CXXBasePaths Paths;
Paths.setOrigin(LookupRec);
@@ -1843,6 +1920,9 @@ VisibleDeclsRecord::ShadowMapEntry::end() {
}
NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
+ // Look through using declarations.
+ ND = ND->getUnderlyingDecl();
+
unsigned IDNS = ND->getIdentifierNamespace();
std::list<ShadowMap>::reverse_iterator SM = ShadowMaps.rbegin();
for (std::list<ShadowMap>::reverse_iterator SMEnd = ShadowMaps.rend();
@@ -1866,6 +1946,14 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
(*I)->getIdentifierNamespace() != IDNS)
continue;
+ // Functions and function templates in the same scope overload
+ // rather than hide. FIXME: Look for hiding based on function
+ // signatures!
+ if ((*I)->isFunctionOrFunctionTemplate() &&
+ ND->isFunctionOrFunctionTemplate() &&
+ SM == ShadowMaps.rbegin())
+ continue;
+
// We've found a declaration that hides this one.
return *I;
}
@@ -1876,6 +1964,7 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
bool QualifiedNameLookup,
+ bool InBaseClass,
VisibleDeclConsumer &Consumer,
VisibleDeclsRecord &Visited) {
// Make sure we don't visit the same context twice.
@@ -1890,14 +1979,14 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
D != DEnd; ++D) {
if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
if (Result.isAcceptableDecl(ND)) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND));
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND), InBaseClass);
Visited.add(ND);
}
// Visit transparent contexts inside this context.
if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) {
if (InnerCtx->isTransparentContext())
- LookupVisibleDecls(InnerCtx, Result, QualifiedNameLookup,
+ LookupVisibleDecls(InnerCtx, Result, QualifiedNameLookup, InBaseClass,
Consumer, Visited);
}
}
@@ -1909,11 +1998,11 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
DeclContext::udir_iterator I, E;
for (llvm::tie(I, E) = Ctx->getUsingDirectives(); I != E; ++I) {
LookupVisibleDecls((*I)->getNominatedNamespace(), Result,
- QualifiedNameLookup, Consumer, Visited);
+ QualifiedNameLookup, InBaseClass, Consumer, Visited);
}
}
- // Traverse the contexts of inherited classes.
+ // Traverse the contexts of inherited C++ classes.
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(),
BEnd = Record->bases_end();
@@ -1951,11 +2040,49 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
// Find results in this base class (and its bases).
ShadowContextRAII Shadow(Visited);
LookupVisibleDecls(Record->getDecl(), Result, QualifiedNameLookup,
- Consumer, Visited);
+ true, Consumer, Visited);
}
}
- // FIXME: Look into base classes in Objective-C!
+ // Traverse the contexts of Objective-C classes.
+ if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) {
+ // Traverse categories.
+ for (ObjCCategoryDecl *Category = IFace->getCategoryList();
+ Category; Category = Category->getNextClassCategory()) {
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(Category, Result, QualifiedNameLookup, false,
+ Consumer, Visited);
+ }
+
+ // Traverse protocols.
+ for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(),
+ E = IFace->protocol_end(); I != E; ++I) {
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
+ Visited);
+ }
+
+ // Traverse the superclass.
+ if (IFace->getSuperClass()) {
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup,
+ true, Consumer, Visited);
+ }
+ } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) {
+ for (ObjCProtocolDecl::protocol_iterator I = Protocol->protocol_begin(),
+ E = Protocol->protocol_end(); I != E; ++I) {
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
+ Visited);
+ }
+ } else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) {
+ for (ObjCCategoryDecl::protocol_iterator I = Category->protocol_begin(),
+ E = Category->protocol_end(); I != E; ++I) {
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
+ Visited);
+ }
+ }
}
static void LookupVisibleDecls(Scope *S, LookupResult &Result,
@@ -1965,9 +2092,21 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
if (!S)
return;
+ if (!S->getEntity() || !S->getParent() ||
+ ((DeclContext *)S->getEntity())->isFunctionOrMethod()) {
+ // 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), false);
+ Visited.add(ND);
+ }
+ }
+ }
+
DeclContext *Entity = 0;
- if (S->getEntity() &&
- !((DeclContext *)S->getEntity())->isFunctionOrMethod()) {
+ if (S->getEntity()) {
// 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.
@@ -1976,11 +2115,27 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
for (DeclContext *Ctx = Entity; Ctx && Ctx->getPrimaryContext() != OuterCtx;
Ctx = Ctx->getLookupParent()) {
+ if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) {
+ if (Method->isInstanceMethod()) {
+ // For instance methods, look for ivars in the method's interface.
+ LookupResult IvarResult(Result.getSema(), Result.getLookupName(),
+ Result.getNameLoc(), Sema::LookupMemberName);
+ ObjCInterfaceDecl *IFace = Method->getClassInterface();
+ LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false,
+ /*InBaseClass=*/false, Consumer, Visited);
+ }
+
+ // We've already performed all of the name lookup that we need
+ // to for Objective-C methods; the next context will be the
+ // outer scope.
+ break;
+ }
+
if (Ctx->isFunctionOrMethod())
continue;
LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false,
- Consumer, Visited);
+ /*InBaseClass=*/false, Consumer, Visited);
}
} else if (!S->getParent()) {
// Look into the translation unit scope. We walk through the translation
@@ -1991,22 +2146,11 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
// 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.
+ // in DeclContexts unless we have to" optimization), we can eliminate this.
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);
- }
- }
- }
+ /*InBaseClass=*/false, Consumer, Visited);
+ }
if (Entity) {
// Lookup visible declarations in any namespaces found by using
@@ -2015,8 +2159,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity);
for (; UI != UEnd; ++UI)
LookupVisibleDecls(const_cast<DeclContext *>(UI->getNominatedNamespace()),
- Result, /*QualifiedNameLookup=*/false, Consumer,
- Visited);
+ Result, /*QualifiedNameLookup=*/false,
+ /*InBaseClass=*/false, Consumer, Visited);
}
// Lookup names in the parent scope.
@@ -2051,8 +2195,8 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind);
VisibleDeclsRecord Visited;
ShadowContextRAII Shadow(Visited);
- ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, Consumer,
- Visited);
+ ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true,
+ /*InBaseClass=*/false, Consumer, Visited);
}
//----------------------------------------------------------------------------
@@ -2075,7 +2219,7 @@ public:
explicit TypoCorrectionConsumer(IdentifierInfo *Typo)
: Typo(Typo->getName()) { }
- virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding);
+ virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass);
typedef llvm::SmallVector<NamedDecl *, 4>::const_iterator iterator;
iterator begin() const { return BestResults.begin(); }
@@ -2087,7 +2231,8 @@ public:
}
-void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding) {
+void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
+ bool InBaseClass) {
// Don't consider hidden names for typo correction.
if (Hiding)
return;
@@ -2140,11 +2285,19 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding) {
/// \param EnteringContext whether we're entering the context described by
/// the nested-name-specifier SS.
///
+/// \param OPT when non-NULL, the search for visible declarations will
+/// also walk the protocols in the qualified interfaces of \p OPT.
+///
/// \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) {
+ DeclContext *MemberContext, bool EnteringContext,
+ const ObjCObjectPointerType *OPT) {
+
+ if (Diags.hasFatalErrorOccurred())
+ return false;
+
// We only attempt to correct typos for identifiers.
IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo();
if (!Typo)
@@ -2161,9 +2314,17 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
return false;
TypoCorrectionConsumer Consumer(Typo);
- if (MemberContext)
+ if (MemberContext) {
LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer);
- else if (SS && SS->isSet()) {
+
+ // Look in qualified interfaces.
+ if (OPT) {
+ for (ObjCObjectPointerType::qual_iterator
+ I = OPT->qual_begin(), E = OPT->qual_end();
+ I != E; ++I)
+ LookupVisibleDecls(*I, Res.getLookupKind(), Consumer);
+ }
+ } else if (SS && SS->isSet()) {
DeclContext *DC = computeDeclContext(*SS, EnteringContext);
if (!DC)
return false;
@@ -2180,10 +2341,22 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
// have overloads of that name, though).
TypoCorrectionConsumer::iterator I = Consumer.begin();
DeclarationName BestName = (*I)->getDeclName();
+
+ // If we've found an Objective-C ivar or property, don't perform
+ // name lookup again; we'll just return the result directly.
+ NamedDecl *FoundBest = 0;
+ if (isa<ObjCIvarDecl>(*I) || isa<ObjCPropertyDecl>(*I))
+ FoundBest = *I;
++I;
for(TypoCorrectionConsumer::iterator IEnd = Consumer.end(); I != IEnd; ++I) {
if (BestName != (*I)->getDeclName())
return false;
+
+ // FIXME: If there are both ivars and properties of the same name,
+ // don't return both because the callee can't handle two
+ // results. We really need to separate ivar lookup from property
+ // lookup to avoid this problem.
+ FoundBest = 0;
}
// BestName is the closest viable name to what the user
@@ -2198,8 +2371,16 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
// success if we found something that was not ambiguous.
Res.clear();
Res.setLookupName(BestName);
- if (MemberContext)
+
+ // If we found an ivar or property, add that result; no further
+ // lookup is required.
+ if (FoundBest)
+ Res.addDecl(FoundBest);
+ // If we're looking into the context of a member, perform qualified
+ // name lookup on the best name.
+ else if (MemberContext)
LookupQualifiedName(Res, MemberContext);
+ // Perform lookup as if we had just parsed the best name.
else
LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false,
EnteringContext);
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 5892081..6ec4d1b 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -145,15 +145,12 @@ ImplicitConversionRank StandardConversionSequence::getRank() const {
/// used as part of the ranking of standard conversion sequences
/// (C++ 13.3.3.2p4).
bool StandardConversionSequence::isPointerConversionToBool() const {
- QualType FromType = QualType::getFromOpaquePtr(FromTypePtr);
- QualType ToType = QualType::getFromOpaquePtr(ToTypePtr);
-
// Note that FromType has not necessarily been transformed by the
// array-to-pointer or function-to-pointer implicit conversions, so
// check for their presence as well as checking whether FromType is
// a pointer.
- if (ToType->isBooleanType() &&
- (FromType->isPointerType() || FromType->isBlockPointerType() ||
+ if (getToType()->isBooleanType() &&
+ (getFromType()->isPointerType() || getFromType()->isBlockPointerType() ||
First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer))
return true;
@@ -167,8 +164,8 @@ bool StandardConversionSequence::isPointerConversionToBool() const {
bool
StandardConversionSequence::
isPointerConversionToVoidPointer(ASTContext& Context) const {
- QualType FromType = QualType::getFromOpaquePtr(FromTypePtr);
- QualType ToType = QualType::getFromOpaquePtr(ToTypePtr);
+ QualType FromType = getFromType();
+ QualType ToType = getToType();
// Note that FromType has not necessarily been transformed by the
// array-to-pointer implicit conversion, so check for its presence
@@ -250,6 +247,9 @@ void ImplicitConversionSequence::DebugPrint() const {
case EllipsisConversion:
fprintf(stderr, "Ellipsis conversion");
break;
+ case AmbiguousConversion:
+ fprintf(stderr, "Ambiguous conversion");
+ break;
case BadConversion:
fprintf(stderr, "Bad conversion");
break;
@@ -258,6 +258,22 @@ void ImplicitConversionSequence::DebugPrint() const {
fprintf(stderr, "\n");
}
+void AmbiguousConversionSequence::construct() {
+ new (&conversions()) ConversionSet();
+}
+
+void AmbiguousConversionSequence::destruct() {
+ conversions().~ConversionSet();
+}
+
+void
+AmbiguousConversionSequence::copyFrom(const AmbiguousConversionSequence &O) {
+ FromTypePtr = O.FromTypePtr;
+ ToTypePtr = O.ToTypePtr;
+ new (&conversions()) ConversionSet(O.conversions());
+}
+
+
// IsOverload - Determine whether the given New declaration is an
// overload of the declarations in Old. This routine returns false if
// New and Old cannot be overloaded, e.g., if New has the same
@@ -432,14 +448,14 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
OverloadCandidateSet Conversions;
OverloadingResult UserDefResult = OR_Success;
if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard))
- ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
+ ICS.setStandard();
else if (getLangOptions().CPlusPlus &&
(UserDefResult = IsUserDefinedConversion(From, ToType,
ICS.UserDefined,
Conversions,
!SuppressUserConversions, AllowExplicit,
ForceRValue, UserCast)) == OR_Success) {
- ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
+ ICS.setUserDefined();
// C++ [over.ics.user]p4:
// A conversion of an expression of class type to the same class
// type is given Exact Match rank, and a conversion of an
@@ -456,10 +472,10 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
(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;
+ ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
- ICS.Standard.FromTypePtr = From->getType().getAsOpaquePtr();
- ICS.Standard.ToTypePtr = ToType.getAsOpaquePtr();
+ ICS.Standard.setFromType(From->getType());
+ ICS.Standard.setToType(ToType);
ICS.Standard.CopyConstructor = Constructor;
if (ToCanon != FromCanon)
ICS.Standard.Second = ICK_Derived_To_Base;
@@ -473,17 +489,21 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
// of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or
// 13.3.1.6 in all cases, only standard conversion sequences and
// ellipsis conversion sequences are allowed.
- if (SuppressUserConversions &&
- ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion)
- ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
- } else {
- ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
- if (UserDefResult == OR_Ambiguous) {
- for (OverloadCandidateSet::iterator Cand = Conversions.begin();
- Cand != Conversions.end(); ++Cand)
- if (Cand->Viable)
- ICS.ConversionFunctionSet.push_back(Cand->Function);
+ if (SuppressUserConversions && ICS.isUserDefined()) {
+ ICS.setBad();
+ ICS.Bad.init(BadConversionSequence::suppressed_user, From, ToType);
}
+ } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) {
+ ICS.setAmbiguous();
+ ICS.Ambiguous.setFromType(From->getType());
+ ICS.Ambiguous.setToType(ToType);
+ for (OverloadCandidateSet::iterator Cand = Conversions.begin();
+ Cand != Conversions.end(); ++Cand)
+ if (Cand->Viable)
+ ICS.Ambiguous.addConversion(Cand->Function);
+ } else {
+ ICS.setBad();
+ ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
}
return ICS;
@@ -524,7 +544,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
SCS.setAsIdentityConversion();
SCS.Deprecated = false;
SCS.IncompatibleObjC = false;
- SCS.FromTypePtr = FromType.getAsOpaquePtr();
+ SCS.setFromType(FromType);
SCS.CopyConstructor = 0;
// There are no standard conversions for class types in C++, so
@@ -573,7 +593,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// conversion (4.4). (C++ 4.2p2)
SCS.Second = ICK_Identity;
SCS.Third = ICK_Qualification;
- SCS.ToTypePtr = ToType.getAsOpaquePtr();
+ SCS.setToType(ToType);
return true;
}
} else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) {
@@ -639,7 +659,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
} else if ((FromType->isIntegralType() || FromType->isEnumeralType()) &&
(ToType->isIntegralType() && !ToType->isEnumeralType())) {
// Integral conversions (C++ 4.7).
- // FIXME: isIntegralType shouldn't be true for enums in C++.
SCS.Second = ICK_Integral_Conversion;
FromType = ToType.getUnqualifiedType();
} else if (FromType->isFloatingType() && ToType->isFloatingType()) {
@@ -656,7 +675,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
((FromType->isIntegralType() || FromType->isEnumeralType()) &&
ToType->isFloatingType())) {
// Floating-integral conversions (C++ 4.9).
- // FIXME: isIntegralType shouldn't be true for enums in C++.
SCS.Second = ICK_Floating_Integral;
FromType = ToType.getUnqualifiedType();
} else if ((FromType->isComplexType() && ToType->isArithmeticType()) ||
@@ -726,7 +744,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
if (CanonFrom != CanonTo)
return false;
- SCS.ToTypePtr = FromType.getAsOpaquePtr();
+ SCS.setToType(FromType);
return true;
}
@@ -1546,8 +1564,7 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
// the argument of the constructor.
//
QualType ThisType = Constructor->getThisType(Context);
- if (Best->Conversions[0].ConversionKind ==
- ImplicitConversionSequence::EllipsisConversion)
+ if (Best->Conversions[0].isEllipsis())
User.EllipsisConversion = true;
else {
User.Before = Best->Conversions[0].Standard;
@@ -1555,9 +1572,9 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
}
User.ConversionFunction = Constructor;
User.After.setAsIdentityConversion();
- User.After.FromTypePtr
- = ThisType->getAs<PointerType>()->getPointeeType().getAsOpaquePtr();
- User.After.ToTypePtr = ToType.getAsOpaquePtr();
+ User.After.setFromType(
+ ThisType->getAs<PointerType>()->getPointeeType());
+ User.After.setToType(ToType);
return OR_Success;
} else if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(Best->Function)) {
@@ -1617,7 +1634,7 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
<< From->getType() << ToType << From->getSourceRange();
else
return false;
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, &From, 1);
return true;
}
@@ -1637,18 +1654,28 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
// conversion sequence than an ellipsis conversion sequence
// (13.3.3.1.3).
//
- if (ICS1.ConversionKind < ICS2.ConversionKind)
- return ImplicitConversionSequence::Better;
- else if (ICS2.ConversionKind < ICS1.ConversionKind)
- return ImplicitConversionSequence::Worse;
+ // C++0x [over.best.ics]p10:
+ // For the purpose of ranking implicit conversion sequences as
+ // described in 13.3.3.2, the ambiguous conversion sequence is
+ // treated as a user-defined sequence that is indistinguishable
+ // from any other user-defined conversion sequence.
+ if (ICS1.getKind() < ICS2.getKind()) {
+ if (!(ICS1.isUserDefined() && ICS2.isAmbiguous()))
+ return ImplicitConversionSequence::Better;
+ } else if (ICS2.getKind() < ICS1.getKind()) {
+ if (!(ICS2.isUserDefined() && ICS1.isAmbiguous()))
+ return ImplicitConversionSequence::Worse;
+ }
+
+ if (ICS1.isAmbiguous() || ICS2.isAmbiguous())
+ return ImplicitConversionSequence::Indistinguishable;
// Two implicit conversion sequences of the same form are
// indistinguishable conversion sequences unless one of the
// following rules apply: (C++ 13.3.3.2p3):
- if (ICS1.ConversionKind == ImplicitConversionSequence::StandardConversion)
+ if (ICS1.isStandard())
return CompareStandardConversionSequences(ICS1.Standard, ICS2.Standard);
- else if (ICS1.ConversionKind ==
- ImplicitConversionSequence::UserDefinedConversion) {
+ else if (ICS1.isUserDefined()) {
// User-defined conversion sequence U1 is a better conversion
// sequence than another user-defined conversion sequence U2 if
// they contain the same user-defined conversion function or
@@ -1741,8 +1768,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// Both conversion sequences are conversions to void
// pointers. Compare the source types to determine if there's an
// inheritance relationship in their sources.
- QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr);
- QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr);
+ QualType FromType1 = SCS1.getFromType();
+ QualType FromType2 = SCS2.getFromType();
// Adjust the types we're converting from via the array-to-pointer
// conversion, if we need to.
@@ -1798,8 +1825,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// top-level cv-qualifiers, and the type to which the reference
// initialized by S2 refers is more cv-qualified than the type
// to which the reference initialized by S1 refers.
- QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr);
- QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
+ QualType T1 = SCS1.getToType();
+ QualType T2 = SCS2.getToType();
T1 = Context.getCanonicalType(T1);
T2 = Context.getCanonicalType(T2);
Qualifiers T1Quals, T2Quals;
@@ -1929,10 +1956,10 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
ImplicitConversionSequence::CompareKind
Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2) {
- QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr);
- QualType ToType1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr);
- QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr);
- QualType ToType2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
+ QualType FromType1 = SCS1.getFromType();
+ QualType ToType1 = SCS1.getToType();
+ QualType FromType2 = SCS2.getFromType();
+ QualType ToType2 = SCS2.getToType();
// Adjust the types we're converting from via the array-to-pointer
// conversion, if we need to.
@@ -2105,6 +2132,7 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType,
bool InOverloadResolution) {
if (ToType->isReferenceType()) {
ImplicitConversionSequence ICS;
+ ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
CheckReferenceInit(From, ToType,
/*FIXME:*/From->getLocStart(),
SuppressUserConversions,
@@ -2163,7 +2191,7 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
/// parameter of the given member function (@c Method) from the
/// expression @p From.
ImplicitConversionSequence
-Sema::TryObjectArgumentInitialization(QualType FromType,
+Sema::TryObjectArgumentInitialization(QualType OrigFromType,
CXXMethodDecl *Method,
CXXRecordDecl *ActingContext) {
QualType ClassType = Context.getTypeDeclType(ActingContext);
@@ -2177,9 +2205,10 @@ Sema::TryObjectArgumentInitialization(QualType FromType,
// to exit early.
ImplicitConversionSequence ICS;
ICS.Standard.setAsIdentityConversion();
- ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+ ICS.setBad();
// We need to have an object of class type.
+ QualType FromType = OrigFromType;
if (const PointerType *PT = FromType->getAs<PointerType>())
FromType = PT->getPointeeType();
@@ -2199,8 +2228,11 @@ Sema::TryObjectArgumentInitialization(QualType FromType,
QualType FromTypeCanon = Context.getCanonicalType(FromType);
if (ImplicitParamType.getCVRQualifiers()
!= FromTypeCanon.getLocalCVRQualifiers() &&
- !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon))
+ !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) {
+ ICS.Bad.init(BadConversionSequence::bad_qualifiers,
+ OrigFromType, ImplicitParamType);
return ICS;
+ }
// Check that we have either the same type or a derived type. It
// affects the conversion rank.
@@ -2209,13 +2241,15 @@ Sema::TryObjectArgumentInitialization(QualType FromType,
ICS.Standard.Second = ICK_Identity;
else if (IsDerivedFrom(FromType, ClassType))
ICS.Standard.Second = ICK_Derived_To_Base;
- else
+ else {
+ ICS.Bad.init(BadConversionSequence::unrelated_class, FromType, ImplicitParamType);
return ICS;
+ }
// Success. Mark this as a reference binding.
- ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
- ICS.Standard.FromTypePtr = FromType.getAsOpaquePtr();
- ICS.Standard.ToTypePtr = ImplicitParamType.getAsOpaquePtr();
+ ICS.setStandard();
+ ICS.Standard.setFromType(FromType);
+ ICS.Standard.setToType(ImplicitParamType);
ICS.Standard.ReferenceBinding = true;
ICS.Standard.DirectBinding = true;
ICS.Standard.RRefBinding = false;
@@ -2244,7 +2278,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) {
ImplicitConversionSequence ICS
= TryObjectArgumentInitialization(From->getType(), Method,
Method->getParent());
- if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion)
+ if (ICS.isBad())
return Diag(From->getSourceRange().getBegin(),
diag::err_implicit_object_parameter_init)
<< ImplicitParamRecordType << FromRecordType << From->getSourceRange();
@@ -2276,8 +2310,8 @@ 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, AA_Converting))
- return false;
+ if (!ICS.isBad())
+ return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting);
if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy))
return Diag(From->getSourceRange().getBegin(),
@@ -2307,8 +2341,6 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
const FunctionProtoType* Proto
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
assert(Proto && "Functions without a prototype cannot be overloaded");
- assert(!isa<CXXConversionDecl>(Function) &&
- "Use AddConversionCandidate for conversion functions");
assert(!Function->getDescribedFunctionTemplate() &&
"Use AddTemplateOverloadCandidate for function templates");
@@ -2363,6 +2395,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
if ((NumArgs + (PartialOverloading && NumArgs)) > NumArgsInProto &&
!Proto->isVariadic()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
}
@@ -2375,6 +2408,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
if (NumArgs < MinRequiredArgs && !PartialOverloading) {
// Not enough arguments.
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_few_arguments;
return;
}
@@ -2392,35 +2426,16 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
= TryCopyInitialization(Args[ArgIdx], ParamType,
SuppressUserConversions, ForceRValue,
/*InOverloadResolution=*/true);
- if (Candidate.Conversions[ArgIdx].ConversionKind
- == ImplicitConversionSequence::BadConversion) {
- // 13.3.3.1-p10 If several different sequences of conversions exist that
- // each convert the argument to the parameter type, the implicit conversion
- // sequence associated with the parameter is defined to be the unique conversion
- // sequence designated the ambiguous conversion sequence. For the purpose of
- // ranking implicit conversion sequences as described in 13.3.3.2, the ambiguous
- // conversion sequence is treated as a user-defined sequence that is
- // indistinguishable from any other user-defined conversion sequence
- if (!Candidate.Conversions[ArgIdx].ConversionFunctionSet.empty()) {
- Candidate.Conversions[ArgIdx].ConversionKind =
- ImplicitConversionSequence::UserDefinedConversion;
- // Set the conversion function to one of them. As due to ambiguity,
- // they carry the same weight and is needed for overload resolution
- // later.
- Candidate.Conversions[ArgIdx].UserDefined.ConversionFunction =
- Candidate.Conversions[ArgIdx].ConversionFunctionSet[0];
- }
- else {
- Candidate.Viable = false;
- break;
- }
+ if (Candidate.Conversions[ArgIdx].isBad()) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
+ break;
}
} else {
// (C++ 13.3.2p2): For the purposes of overload resolution, any
// argument for which there is no corresponding parameter is
// considered to ""match the ellipsis" (C+ 13.3.3.1.3).
- Candidate.Conversions[ArgIdx].ConversionKind
- = ImplicitConversionSequence::EllipsisConversion;
+ Candidate.Conversions[ArgIdx].setEllipsis();
}
}
}
@@ -2470,8 +2485,6 @@ void Sema::AddMethodCandidate(NamedDecl *Decl,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions, bool ForceRValue) {
-
- // FIXME: use this
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext());
if (isa<UsingShadowDecl>(Decl))
@@ -2509,8 +2522,6 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
const FunctionProtoType* Proto
= dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
assert(Proto && "Methods without a prototype cannot be overloaded");
- assert(!isa<CXXConversionDecl>(Method) &&
- "Use AddConversionCandidate for conversion functions");
assert(!isa<CXXConstructorDecl>(Method) &&
"Use AddOverloadCandidate for constructors");
@@ -2534,6 +2545,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
// list (8.3.5).
if (NumArgs > NumArgsInProto && !Proto->isVariadic()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
}
@@ -2546,6 +2558,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
if (NumArgs < MinRequiredArgs) {
// Not enough arguments.
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_few_arguments;
return;
}
@@ -2560,9 +2573,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
// parameter.
Candidate.Conversions[0]
= TryObjectArgumentInitialization(ObjectType, Method, ActingContext);
- if (Candidate.Conversions[0].ConversionKind
- == ImplicitConversionSequence::BadConversion) {
+ if (Candidate.Conversions[0].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
}
@@ -2580,17 +2593,16 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
= TryCopyInitialization(Args[ArgIdx], ParamType,
SuppressUserConversions, ForceRValue,
/*InOverloadResolution=*/true);
- if (Candidate.Conversions[ArgIdx + 1].ConversionKind
- == ImplicitConversionSequence::BadConversion) {
+ if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
break;
}
} else {
// (C++ 13.3.2p2): For the purposes of overload resolution, any
// argument for which there is no corresponding parameter is
// considered to ""match the ellipsis" (C+ 13.3.3.1.3).
- Candidate.Conversions[ArgIdx + 1].ConversionKind
- = ImplicitConversionSequence::EllipsisConversion;
+ Candidate.Conversions[ArgIdx + 1].setEllipsis();
}
}
}
@@ -2675,6 +2687,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
OverloadCandidate &Candidate = CandidateSet.back();
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
return;
@@ -2714,9 +2727,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.FinalConversion.setAsIdentityConversion();
- Candidate.FinalConversion.FromTypePtr
- = Conversion->getConversionType().getAsOpaquePtr();
- Candidate.FinalConversion.ToTypePtr = ToType.getAsOpaquePtr();
+ Candidate.FinalConversion.setFromType(Conversion->getConversionType());
+ Candidate.FinalConversion.setToType(ToType);
// Determine the implicit conversion sequence for the implicit
// object parameter.
@@ -2730,9 +2742,9 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
// in overload resolution.
if (Candidate.Conversions[0].Standard.Second == ICK_Derived_To_Base)
Candidate.Conversions[0].Standard.Second = ICK_Identity;
- if (Candidate.Conversions[0].ConversionKind
- == ImplicitConversionSequence::BadConversion) {
+ if (Candidate.Conversions[0].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
@@ -2744,6 +2756,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType();
if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
@@ -2774,13 +2787,14 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
/*ForceRValue=*/false,
/*InOverloadResolution=*/false);
- switch (ICS.ConversionKind) {
+ switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
Candidate.FinalConversion = ICS.Standard;
break;
case ImplicitConversionSequence::BadConversion:
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
break;
default:
@@ -2852,16 +2866,16 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// object parameter.
ImplicitConversionSequence ObjectInit
= TryObjectArgumentInitialization(ObjectType, Conversion, ActingContext);
- if (ObjectInit.ConversionKind == ImplicitConversionSequence::BadConversion) {
+ if (ObjectInit.isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
// The first conversion is actually a user-defined conversion whose
// first conversion is ObjectInit's standard conversion (which is
// effectively a reference binding). Record it as such.
- Candidate.Conversions[0].ConversionKind
- = ImplicitConversionSequence::UserDefinedConversion;
+ Candidate.Conversions[0].setUserDefined();
Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard;
Candidate.Conversions[0].UserDefined.EllipsisConversion = false;
Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion;
@@ -2877,6 +2891,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// list (8.3.5).
if (NumArgs > NumArgsInProto && !Proto->isVariadic()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
}
@@ -2885,6 +2900,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
if (NumArgs < NumArgsInProto) {
// Not enough arguments.
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_few_arguments;
return;
}
@@ -2902,17 +2918,16 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
/*SuppressUserConversions=*/false,
/*ForceRValue=*/false,
/*InOverloadResolution=*/false);
- if (Candidate.Conversions[ArgIdx + 1].ConversionKind
- == ImplicitConversionSequence::BadConversion) {
+ if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
break;
}
} else {
// (C++ 13.3.2p2): For the purposes of overload resolution, any
// argument for which there is no corresponding parameter is
// considered to ""match the ellipsis" (C+ 13.3.3.1.3).
- Candidate.Conversions[ArgIdx + 1].ConversionKind
- = ImplicitConversionSequence::EllipsisConversion;
+ Candidate.Conversions[ArgIdx + 1].setEllipsis();
}
}
}
@@ -3046,9 +3061,9 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
/*ForceRValue=*/false,
/*InOverloadResolution=*/false);
}
- if (Candidate.Conversions[ArgIdx].ConversionKind
- == ImplicitConversionSequence::BadConversion) {
+ if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
break;
}
}
@@ -4274,130 +4289,386 @@ OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
return OR_Success;
}
+namespace {
+
+enum OverloadCandidateKind {
+ oc_function,
+ oc_method,
+ oc_constructor,
+ oc_function_template,
+ oc_method_template,
+ oc_constructor_template,
+ oc_implicit_default_constructor,
+ oc_implicit_copy_constructor,
+ oc_implicit_copy_assignment
+};
+
+OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
+ FunctionDecl *Fn,
+ std::string &Description) {
+ bool isTemplate = false;
+
+ if (FunctionTemplateDecl *FunTmpl = Fn->getPrimaryTemplate()) {
+ isTemplate = true;
+ Description = S.getTemplateArgumentBindingsText(
+ FunTmpl->getTemplateParameters(), *Fn->getTemplateSpecializationArgs());
+ }
+
+ if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) {
+ if (!Ctor->isImplicit())
+ return isTemplate ? oc_constructor_template : oc_constructor;
+
+ return Ctor->isCopyConstructor() ? oc_implicit_copy_constructor
+ : oc_implicit_default_constructor;
+ }
+
+ if (CXXMethodDecl *Meth = dyn_cast<CXXMethodDecl>(Fn)) {
+ // This actually gets spelled 'candidate function' for now, but
+ // it doesn't hurt to split it out.
+ if (!Meth->isImplicit())
+ return isTemplate ? oc_method_template : oc_method;
+
+ assert(Meth->isCopyAssignment()
+ && "implicit method is not copy assignment operator?");
+ return oc_implicit_copy_assignment;
+ }
+
+ return isTemplate ? oc_function_template : oc_function;
+}
+
+} // end anonymous namespace
+
+// Notes the location of an overload candidate.
+void Sema::NoteOverloadCandidate(FunctionDecl *Fn) {
+ std::string FnDesc;
+ OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc);
+ Diag(Fn->getLocation(), diag::note_ovl_candidate)
+ << (unsigned) K << FnDesc;
+}
+
+/// Diagnoses an ambiguous conversion. The partial diagnostic is the
+/// "lead" diagnostic; it will be given two arguments, the source and
+/// target types of the conversion.
+void Sema::DiagnoseAmbiguousConversion(const ImplicitConversionSequence &ICS,
+ SourceLocation CaretLoc,
+ const PartialDiagnostic &PDiag) {
+ Diag(CaretLoc, PDiag)
+ << ICS.Ambiguous.getFromType() << ICS.Ambiguous.getToType();
+ for (AmbiguousConversionSequence::const_iterator
+ I = ICS.Ambiguous.begin(), E = ICS.Ambiguous.end(); I != E; ++I) {
+ NoteOverloadCandidate(*I);
+ }
+}
+
+namespace {
+
+void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
+ const ImplicitConversionSequence &Conv = Cand->Conversions[I];
+ assert(Conv.isBad());
+ assert(Cand->Function && "for now, candidate must be a function");
+ FunctionDecl *Fn = Cand->Function;
+
+ // There's a conversion slot for the object argument if this is a
+ // non-constructor method. Note that 'I' corresponds the
+ // conversion-slot index.
+ bool isObjectArgument = false;
+ if (isa<CXXMethodDecl>(Fn) && !isa<CXXConstructorDecl>(Fn)) {
+ if (I == 0)
+ isObjectArgument = true;
+ else
+ I--;
+ }
+
+ std::string FnDesc;
+ OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc);
+
+ Expr *FromExpr = Conv.Bad.FromExpr;
+ QualType FromTy = Conv.Bad.getFromType();
+ QualType ToTy = Conv.Bad.getToType();
+
+ // Do some hand-waving analysis to see if the non-viability is due to a
+ CanQualType CFromTy = S.Context.getCanonicalType(FromTy);
+ CanQualType CToTy = S.Context.getCanonicalType(ToTy);
+ if (CanQual<ReferenceType> RT = CToTy->getAs<ReferenceType>())
+ CToTy = RT->getPointeeType();
+ else {
+ // TODO: detect and diagnose the full richness of const mismatches.
+ if (CanQual<PointerType> FromPT = CFromTy->getAs<PointerType>())
+ if (CanQual<PointerType> ToPT = CToTy->getAs<PointerType>())
+ CFromTy = FromPT->getPointeeType(), CToTy = ToPT->getPointeeType();
+ }
+
+ if (CToTy.getUnqualifiedType() == CFromTy.getUnqualifiedType() &&
+ !CToTy.isAtLeastAsQualifiedAs(CFromTy)) {
+ // It is dumb that we have to do this here.
+ while (isa<ArrayType>(CFromTy))
+ CFromTy = CFromTy->getAs<ArrayType>()->getElementType();
+ while (isa<ArrayType>(CToTy))
+ CToTy = CFromTy->getAs<ArrayType>()->getElementType();
+
+ Qualifiers FromQs = CFromTy.getQualifiers();
+ Qualifiers ToQs = CToTy.getQualifiers();
+
+ if (FromQs.getAddressSpace() != ToQs.getAddressSpace()) {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy
+ << FromQs.getAddressSpace() << ToQs.getAddressSpace()
+ << (unsigned) isObjectArgument << I+1;
+ return;
+ }
+
+ unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers();
+ assert(CVR && "unexpected qualifiers mismatch");
+
+ if (isObjectArgument) {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr_this)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy << (CVR - 1);
+ } else {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy << (CVR - 1) << I+1;
+ }
+ return;
+ }
+
+ // TODO: specialize more based on the kind of mismatch
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy << ToTy << (unsigned) isObjectArgument << I+1;
+}
+
+void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
+ unsigned NumFormalArgs) {
+ // TODO: treat calls to a missing default constructor as a special case
+
+ FunctionDecl *Fn = Cand->Function;
+ const FunctionProtoType *FnTy = Fn->getType()->getAs<FunctionProtoType>();
+
+ unsigned MinParams = Fn->getMinRequiredArguments();
+
+ // at least / at most / exactly
+ unsigned mode, modeCount;
+ if (NumFormalArgs < MinParams) {
+ assert(Cand->FailureKind == ovl_fail_too_few_arguments);
+ if (MinParams != FnTy->getNumArgs() || FnTy->isVariadic())
+ mode = 0; // "at least"
+ else
+ mode = 2; // "exactly"
+ modeCount = MinParams;
+ } else {
+ assert(Cand->FailureKind == ovl_fail_too_many_arguments);
+ if (MinParams != FnTy->getNumArgs())
+ mode = 1; // "at most"
+ else
+ mode = 2; // "exactly"
+ modeCount = FnTy->getNumArgs();
+ }
+
+ std::string Description;
+ OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description);
+
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity)
+ << (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs;
+}
+
+void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
+ Expr **Args, unsigned NumArgs) {
+ FunctionDecl *Fn = Cand->Function;
+
+ // Note deleted candidates, but only if they're viable.
+ if (Cand->Viable && (Fn->isDeleted() || Fn->hasAttr<UnavailableAttr>())) {
+ std::string FnDesc;
+ OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc);
+
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)
+ << FnKind << FnDesc << Fn->isDeleted();
+ return;
+ }
+
+ // We don't really have anything else to say about viable candidates.
+ if (Cand->Viable) {
+ S.NoteOverloadCandidate(Fn);
+ return;
+ }
+
+ switch (Cand->FailureKind) {
+ case ovl_fail_too_many_arguments:
+ case ovl_fail_too_few_arguments:
+ return DiagnoseArityMismatch(S, Cand, NumArgs);
+
+ case ovl_fail_bad_deduction:
+ return S.NoteOverloadCandidate(Fn);
+
+ case ovl_fail_bad_conversion:
+ for (unsigned I = 0, N = Cand->Conversions.size(); I != N; ++I)
+ if (Cand->Conversions[I].isBad())
+ return DiagnoseBadConversion(S, Cand, I);
+
+ // FIXME: this currently happens when we're called from SemaInit
+ // when user-conversion overload fails. Figure out how to handle
+ // those conditions and diagnose them well.
+ return S.NoteOverloadCandidate(Fn);
+ }
+}
+
+void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
+ // Desugar the type of the surrogate down to a function type,
+ // retaining as many typedefs as possible while still showing
+ // the function type (and, therefore, its parameter types).
+ QualType FnType = Cand->Surrogate->getConversionType();
+ bool isLValueReference = false;
+ bool isRValueReference = false;
+ bool isPointer = false;
+ if (const LValueReferenceType *FnTypeRef =
+ FnType->getAs<LValueReferenceType>()) {
+ FnType = FnTypeRef->getPointeeType();
+ isLValueReference = true;
+ } else if (const RValueReferenceType *FnTypeRef =
+ FnType->getAs<RValueReferenceType>()) {
+ FnType = FnTypeRef->getPointeeType();
+ isRValueReference = true;
+ }
+ if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) {
+ FnType = FnTypePtr->getPointeeType();
+ isPointer = true;
+ }
+ // Desugar down to a function type.
+ FnType = QualType(FnType->getAs<FunctionType>(), 0);
+ // Reconstruct the pointer/reference as appropriate.
+ if (isPointer) FnType = S.Context.getPointerType(FnType);
+ if (isRValueReference) FnType = S.Context.getRValueReferenceType(FnType);
+ if (isLValueReference) FnType = S.Context.getLValueReferenceType(FnType);
+
+ S.Diag(Cand->Surrogate->getLocation(), diag::note_ovl_surrogate_cand)
+ << FnType;
+}
+
+void NoteBuiltinOperatorCandidate(Sema &S,
+ const char *Opc,
+ SourceLocation OpLoc,
+ OverloadCandidate *Cand) {
+ assert(Cand->Conversions.size() <= 2 && "builtin operator is not binary");
+ std::string TypeStr("operator");
+ TypeStr += Opc;
+ TypeStr += "(";
+ TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString();
+ if (Cand->Conversions.size() == 1) {
+ TypeStr += ")";
+ S.Diag(OpLoc, diag::note_ovl_builtin_unary_candidate) << TypeStr;
+ } else {
+ TypeStr += ", ";
+ TypeStr += Cand->BuiltinTypes.ParamTypes[1].getAsString();
+ TypeStr += ")";
+ S.Diag(OpLoc, diag::note_ovl_builtin_binary_candidate) << TypeStr;
+ }
+}
+
+void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
+ OverloadCandidate *Cand) {
+ unsigned NoOperands = Cand->Conversions.size();
+ for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) {
+ const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx];
+ if (ICS.isBad()) break; // all meaningless after first invalid
+ if (!ICS.isAmbiguous()) continue;
+
+ S.DiagnoseAmbiguousConversion(ICS, OpLoc,
+ PDiag(diag::note_ambiguous_type_conversion));
+ }
+}
+
+struct CompareOverloadCandidatesForDisplay {
+ Sema &S;
+ CompareOverloadCandidatesForDisplay(Sema &S) : S(S) {}
+
+ bool operator()(const OverloadCandidate *L,
+ const OverloadCandidate *R) {
+ // Order first by viability.
+ if (L->Viable) {
+ if (!R->Viable) return true;
+
+ // TODO: introduce a tri-valued comparison for overload
+ // candidates. Would be more worthwhile if we had a sort
+ // that could exploit it.
+ if (S.isBetterOverloadCandidate(*L, *R)) return true;
+ if (S.isBetterOverloadCandidate(*R, *L)) return false;
+ } else if (R->Viable)
+ return false;
+
+ // Put declared functions first.
+ if (L->Function) {
+ if (!R->Function) return true;
+ return S.SourceMgr.isBeforeInTranslationUnit(L->Function->getLocation(),
+ R->Function->getLocation());
+ } else if (R->Function) return false;
+
+ // Then surrogates.
+ if (L->IsSurrogate) {
+ if (!R->IsSurrogate) return true;
+ return S.SourceMgr.isBeforeInTranslationUnit(L->Surrogate->getLocation(),
+ R->Surrogate->getLocation());
+ } else if (R->IsSurrogate) return false;
+
+ // And builtins just come in a jumble.
+ return false;
+ }
+};
+
+} // end anonymous namespace
+
/// PrintOverloadCandidates - When overload resolution fails, prints
/// diagnostic messages containing the candidates in the candidate
-/// set. If OnlyViable is true, only viable candidates will be printed.
+/// set.
void
Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
- bool OnlyViable,
+ OverloadCandidateDisplayKind OCD,
+ Expr **Args, unsigned NumArgs,
const char *Opc,
SourceLocation OpLoc) {
- OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
- LastCand = CandidateSet.end();
- bool Reported = false;
- for (; Cand != LastCand; ++Cand) {
- if (Cand->Viable || !OnlyViable) {
- if (Cand->Function) {
- if (Cand->Function->isDeleted() ||
- Cand->Function->getAttr<UnavailableAttr>()) {
- // Deleted or "unavailable" function.
- Diag(Cand->Function->getLocation(), diag::err_ovl_candidate_deleted)
- << Cand->Function->isDeleted();
- } else if (FunctionTemplateDecl *FunTmpl
- = Cand->Function->getPrimaryTemplate()) {
- // Function template specialization
- // FIXME: Give a better reason!
- Diag(Cand->Function->getLocation(), diag::err_ovl_template_candidate)
- << getTemplateArgumentBindingsText(FunTmpl->getTemplateParameters(),
- *Cand->Function->getTemplateSpecializationArgs());
- } else {
- // Normal function
- bool errReported = false;
- if (!Cand->Viable && Cand->Conversions.size() > 0) {
- for (int i = Cand->Conversions.size()-1; i >= 0; i--) {
- const ImplicitConversionSequence &Conversion =
- Cand->Conversions[i];
- if ((Conversion.ConversionKind !=
- ImplicitConversionSequence::BadConversion) ||
- Conversion.ConversionFunctionSet.size() == 0)
- continue;
- Diag(Cand->Function->getLocation(),
- diag::err_ovl_candidate_not_viable) << (i+1);
- errReported = true;
- for (int j = Conversion.ConversionFunctionSet.size()-1;
- j >= 0; j--) {
- FunctionDecl *Func = Conversion.ConversionFunctionSet[j];
- Diag(Func->getLocation(), diag::err_ovl_candidate);
- }
- }
- }
- if (!errReported)
- Diag(Cand->Function->getLocation(), diag::err_ovl_candidate);
- }
- } else if (Cand->IsSurrogate) {
- // Desugar the type of the surrogate down to a function type,
- // retaining as many typedefs as possible while still showing
- // the function type (and, therefore, its parameter types).
- QualType FnType = Cand->Surrogate->getConversionType();
- bool isLValueReference = false;
- bool isRValueReference = false;
- bool isPointer = false;
- if (const LValueReferenceType *FnTypeRef =
- FnType->getAs<LValueReferenceType>()) {
- FnType = FnTypeRef->getPointeeType();
- isLValueReference = true;
- } else if (const RValueReferenceType *FnTypeRef =
- FnType->getAs<RValueReferenceType>()) {
- FnType = FnTypeRef->getPointeeType();
- isRValueReference = true;
- }
- if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) {
- FnType = FnTypePtr->getPointeeType();
- isPointer = true;
- }
- // Desugar down to a function type.
- FnType = QualType(FnType->getAs<FunctionType>(), 0);
- // Reconstruct the pointer/reference as appropriate.
- if (isPointer) FnType = Context.getPointerType(FnType);
- if (isRValueReference) FnType = Context.getRValueReferenceType(FnType);
- if (isLValueReference) FnType = Context.getLValueReferenceType(FnType);
-
- Diag(Cand->Surrogate->getLocation(), diag::err_ovl_surrogate_cand)
- << FnType;
- } else if (OnlyViable) {
- assert(Cand->Conversions.size() <= 2 &&
- "builtin-binary-operator-not-binary");
- std::string TypeStr("operator");
- TypeStr += Opc;
- TypeStr += "(";
- TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString();
- if (Cand->Conversions.size() == 1) {
- TypeStr += ")";
- Diag(OpLoc, diag::err_ovl_builtin_unary_candidate) << TypeStr;
- }
- else {
- TypeStr += ", ";
- TypeStr += Cand->BuiltinTypes.ParamTypes[1].getAsString();
- TypeStr += ")";
- Diag(OpLoc, diag::err_ovl_builtin_binary_candidate) << TypeStr;
- }
- }
- else if (!Cand->Viable && !Reported) {
- // Non-viability might be due to ambiguous user-defined conversions,
- // needed for built-in operators. Report them as well, but only once
- // as we have typically many built-in candidates.
- unsigned NoOperands = Cand->Conversions.size();
- for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) {
- const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx];
- if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion ||
- ICS.ConversionFunctionSet.empty())
- continue;
- if (CXXConversionDecl *Func = dyn_cast<CXXConversionDecl>(
- Cand->Conversions[ArgIdx].ConversionFunctionSet[0])) {
- QualType FromTy =
- QualType(
- static_cast<Type*>(ICS.UserDefined.Before.FromTypePtr),0);
- Diag(OpLoc,diag::note_ambiguous_type_conversion)
- << FromTy << Func->getConversionType();
- }
- for (unsigned j = 0; j < ICS.ConversionFunctionSet.size(); j++) {
- FunctionDecl *Func =
- Cand->Conversions[ArgIdx].ConversionFunctionSet[j];
- Diag(Func->getLocation(),diag::err_ovl_candidate);
- }
- }
- Reported = true;
+ // Sort the candidates by viability and position. Sorting directly would
+ // be prohibitive, so we make a set of pointers and sort those.
+ llvm::SmallVector<OverloadCandidate*, 32> Cands;
+ if (OCD == OCD_AllCandidates) Cands.reserve(CandidateSet.size());
+ for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
+ LastCand = CandidateSet.end();
+ Cand != LastCand; ++Cand)
+ if (Cand->Viable || OCD == OCD_AllCandidates)
+ Cands.push_back(Cand);
+ std::sort(Cands.begin(), Cands.end(),
+ CompareOverloadCandidatesForDisplay(*this));
+
+ bool ReportedAmbiguousConversions = false;
+
+ llvm::SmallVectorImpl<OverloadCandidate*>::iterator I, E;
+ for (I = Cands.begin(), E = Cands.end(); I != E; ++I) {
+ OverloadCandidate *Cand = *I;
+
+ if (Cand->Function)
+ NoteFunctionCandidate(*this, Cand, Args, NumArgs);
+ else if (Cand->IsSurrogate)
+ NoteSurrogateCandidate(*this, Cand);
+
+ // This a builtin candidate. We do not, in general, want to list
+ // every possible builtin candidate.
+ else if (Cand->Viable) {
+ // Generally we only see ambiguities including viable builtin
+ // operators if overload resolution got screwed up by an
+ // ambiguous user-defined conversion.
+ //
+ // FIXME: It's quite possible for different conversions to see
+ // different ambiguities, though.
+ if (!ReportedAmbiguousConversions) {
+ NoteAmbiguousUserConversions(*this, OpLoc, Cand);
+ ReportedAmbiguousConversions = true;
}
+
+ // If this is a viable builtin, print it.
+ NoteBuiltinOperatorCandidate(*this, Opc, OpLoc, Cand);
}
}
}
@@ -4586,7 +4857,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
PDiag(),
PDiag(diag::err_addr_ovl_ambiguous)
<< TemplateMatches[0]->getDeclName(),
- PDiag(diag::err_ovl_template_candidate));
+ PDiag(diag::note_ovl_candidate)
+ << (unsigned) oc_function_template);
MarkDeclarationReferenced(From->getLocStart(), Result);
return Result;
}
@@ -4611,7 +4883,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
<< RemainingMatches[0]->getDeclName();
for (unsigned I = 0, N = RemainingMatches.size(); I != N; ++I)
- Diag(RemainingMatches[I]->getLocation(), diag::err_ovl_candidate);
+ NoteOverloadCandidate(RemainingMatches[I]);
return 0;
}
@@ -4681,7 +4953,6 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) {
// 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
@@ -4906,13 +5177,13 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
Diag(Fn->getSourceRange().getBegin(),
diag::err_ovl_no_viable_function_in_call)
<< ULE->getName() << Fn->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
break;
case OR_Ambiguous:
Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call)
<< ULE->getName() << Fn->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs);
break;
case OR_Deleted:
@@ -4920,7 +5191,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
<< Best->Function->isDeleted()
<< ULE->getName()
<< Fn->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
break;
}
@@ -5075,7 +5346,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
<< UnaryOperator::getOpcodeStr(Opc)
<< Input->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true,
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs,
UnaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
@@ -5084,7 +5355,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
<< Best->Function->isDeleted()
<< UnaryOperator::getOpcodeStr(Opc)
<< Input->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
return ExprError();
}
@@ -5291,7 +5562,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
assert(Result.isInvalid() &&
"C++ binary operator overloading is missing candidates!");
if (Result.isInvalid())
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false,
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2,
BinaryOperator::getOpcodeStr(Opc), OpLoc);
return move(Result);
}
@@ -5300,7 +5571,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
<< BinaryOperator::getOpcodeStr(Opc)
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true,
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, 2,
BinaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
@@ -5309,9 +5580,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
<< Best->Function->isDeleted()
<< BinaryOperator::getOpcodeStr(Opc)
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2);
return ExprError();
- }
+ }
// We matched a built-in operator; build it.
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
@@ -5411,22 +5682,23 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
}
case OR_No_Viable_Function: {
- // No viable function; try to create a built-in operation, which will
- // produce an error. Then, show the non-viable candidates.
- OwningExprResult Result =
- CreateBuiltinArraySubscriptExpr(move(Base), LLoc, move(Idx), RLoc);
- assert(Result.isInvalid() &&
- "C++ subscript operator overloading is missing candidates!");
- if (Result.isInvalid())
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false,
- "[]", LLoc);
- return move(Result);
+ if (CandidateSet.empty())
+ Diag(LLoc, diag::err_ovl_no_oper)
+ << Args[0]->getType() << /*subscript*/ 0
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ else
+ Diag(LLoc, diag::err_ovl_no_viable_subscript)
+ << Args[0]->getType()
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2,
+ "[]", LLoc);
+ return ExprError();
}
case OR_Ambiguous:
Diag(LLoc, diag::err_ovl_ambiguous_oper)
<< "[]" << Args[0]->getSourceRange() << Args[1]->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true,
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, 2,
"[]", LLoc);
return ExprError();
@@ -5434,7 +5706,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
Diag(LLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted() << "[]"
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2,
+ "[]", LLoc);
return ExprError();
}
@@ -5518,14 +5791,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Diag(UnresExpr->getMemberLoc(),
diag::err_ovl_no_viable_member_function_in_call)
<< DeclName << MemExprE->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
// FIXME: Leaking incoming expressions!
return ExprError();
case OR_Ambiguous:
Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call)
<< DeclName << MemExprE->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
// FIXME: Leaking incoming expressions!
return ExprError();
@@ -5533,7 +5806,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call)
<< Best->Function->isDeleted()
<< DeclName << MemExprE->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
// FIXME: Leaking incoming expressions!
return ExprError();
}
@@ -5636,9 +5909,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// functions for each conversion function declared in an
// accessible base class provided the function is not hidden
// within T by another intervening declaration.
- // FIXME: Look in base classes for more conversion operators!
const UnresolvedSet *Conversions
- = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
+ = cast<CXXRecordDecl>(Record->getDecl())->getVisibleConversionFunctions();
for (UnresolvedSet::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
NamedDecl *D = *I;
@@ -5674,17 +5946,22 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
break;
case OR_No_Viable_Function:
- Diag(Object->getSourceRange().getBegin(),
- diag::err_ovl_no_viable_object_call)
- << Object->getType() << Object->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ if (CandidateSet.empty())
+ Diag(Object->getSourceRange().getBegin(), diag::err_ovl_no_oper)
+ << Object->getType() << /*call*/ 1
+ << Object->getSourceRange();
+ else
+ Diag(Object->getSourceRange().getBegin(),
+ diag::err_ovl_no_viable_object_call)
+ << Object->getType() << Object->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
break;
case OR_Ambiguous:
Diag(Object->getSourceRange().getBegin(),
diag::err_ovl_ambiguous_object_call)
<< Object->getType() << Object->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs);
break;
case OR_Deleted:
@@ -5692,7 +5969,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
diag::err_ovl_deleted_object_call)
<< Best->Function->isDeleted()
<< Object->getType() << Object->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
break;
}
@@ -5873,20 +6150,20 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
else
Diag(OpLoc, diag::err_ovl_no_viable_oper)
<< "operator->" << Base->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, &Base, 1);
return ExprError();
case OR_Ambiguous:
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
<< "->" << Base->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, &Base, 1);
return ExprError();
case OR_Deleted:
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
<< "->" << Base->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, &Base, 1);
return ExprError();
}
@@ -6020,9 +6297,14 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
MemExpr->getMemberLoc(),
Fn->getType(),
TemplateArgs);
- } else
- Base = new (Context) CXXThisExpr(SourceLocation(),
- MemExpr->getBaseType());
+ } else {
+ SourceLocation Loc = MemExpr->getMemberLoc();
+ if (MemExpr->getQualifier())
+ Loc = MemExpr->getQualifierRange().getBegin();
+ Base = new (Context) CXXThisExpr(Loc,
+ MemExpr->getBaseType(),
+ /*isImplicit=*/true);
+ }
} else
Base = MemExpr->getBase()->Retain();
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 3613d60..20add00 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_SEMA_OVERLOAD_H
#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -149,6 +150,15 @@ namespace clang {
/// conversions.
CXXConstructorDecl *CopyConstructor;
+ void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); }
+ void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); }
+ QualType getFromType() const {
+ return QualType::getFromOpaquePtr(FromTypePtr);
+ }
+ QualType getToType() const {
+ return QualType::getFromOpaquePtr(ToTypePtr);
+ }
+
void setAsIdentityConversion();
ImplicitConversionRank getRank() const;
bool isPointerConversionToBool() const;
@@ -190,6 +200,93 @@ namespace clang {
void DebugPrint() const;
};
+ /// Represents an ambiguous user-defined conversion sequence.
+ struct AmbiguousConversionSequence {
+ typedef llvm::SmallVector<FunctionDecl*, 4> ConversionSet;
+
+ void *FromTypePtr;
+ void *ToTypePtr;
+ char Buffer[sizeof(ConversionSet)];
+
+ QualType getFromType() const {
+ return QualType::getFromOpaquePtr(FromTypePtr);
+ }
+ QualType getToType() const {
+ return QualType::getFromOpaquePtr(ToTypePtr);
+ }
+ void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); }
+ void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); }
+
+ ConversionSet &conversions() {
+ return *reinterpret_cast<ConversionSet*>(Buffer);
+ }
+
+ const ConversionSet &conversions() const {
+ return *reinterpret_cast<const ConversionSet*>(Buffer);
+ }
+
+ void addConversion(FunctionDecl *D) {
+ conversions().push_back(D);
+ }
+
+ typedef ConversionSet::iterator iterator;
+ iterator begin() { return conversions().begin(); }
+ iterator end() { return conversions().end(); }
+
+ typedef ConversionSet::const_iterator const_iterator;
+ const_iterator begin() const { return conversions().begin(); }
+ const_iterator end() const { return conversions().end(); }
+
+ void construct();
+ void destruct();
+ void copyFrom(const AmbiguousConversionSequence &);
+ };
+
+ /// BadConversionSequence - Records information about an invalid
+ /// conversion sequence.
+ struct BadConversionSequence {
+ enum FailureKind {
+ no_conversion,
+ unrelated_class,
+ suppressed_user,
+ bad_qualifiers
+ };
+
+ // This can be null, e.g. for implicit object arguments.
+ Expr *FromExpr;
+
+ FailureKind Kind;
+
+ private:
+ // The type we're converting from (an opaque QualType).
+ void *FromTy;
+
+ // The type we're converting to (an opaque QualType).
+ void *ToTy;
+
+ public:
+ void init(FailureKind K, Expr *From, QualType To) {
+ init(K, From->getType(), To);
+ FromExpr = From;
+ }
+ void init(FailureKind K, QualType From, QualType To) {
+ Kind = K;
+ FromExpr = 0;
+ setFromType(From);
+ setToType(To);
+ }
+
+ QualType getFromType() const { return QualType::getFromOpaquePtr(FromTy); }
+ QualType getToType() const { return QualType::getFromOpaquePtr(ToTy); }
+
+ void setFromExpr(Expr *E) {
+ FromExpr = E;
+ setFromType(E->getType());
+ }
+ void setFromType(QualType T) { FromTy = T.getAsOpaquePtr(); }
+ void setToType(QualType T) { ToTy = T.getAsOpaquePtr(); }
+ };
+
/// ImplicitConversionSequence - Represents an implicit conversion
/// sequence, which may be a standard conversion sequence
/// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2),
@@ -197,18 +294,26 @@ namespace clang {
struct ImplicitConversionSequence {
/// Kind - The kind of implicit conversion sequence. BadConversion
/// specifies that there is no conversion from the source type to
- /// the target type. The enumerator values are ordered such that
- /// better implicit conversions have smaller values.
+ /// the target type. AmbiguousConversion represents the unique
+ /// ambiguous conversion (C++0x [over.best.ics]p10).
enum Kind {
StandardConversion = 0,
UserDefinedConversion,
+ AmbiguousConversion,
EllipsisConversion,
BadConversion
};
+ private:
/// ConversionKind - The kind of implicit conversion sequence.
Kind ConversionKind;
+ void setKind(Kind K) {
+ if (isAmbiguous()) Ambiguous.destruct();
+ ConversionKind = K;
+ }
+
+ public:
union {
/// When ConversionKind == StandardConversion, provides the
/// details of the standard conversion sequence.
@@ -217,12 +322,58 @@ namespace clang {
/// When ConversionKind == UserDefinedConversion, provides the
/// details of the user-defined conversion sequence.
UserDefinedConversionSequence UserDefined;
+
+ /// When ConversionKind == AmbiguousConversion, provides the
+ /// details of the ambiguous conversion.
+ AmbiguousConversionSequence Ambiguous;
+
+ /// When ConversionKind == BadConversion, provides the details
+ /// of the bad conversion.
+ BadConversionSequence Bad;
};
+
+ ImplicitConversionSequence() : ConversionKind(BadConversion) {}
+ ~ImplicitConversionSequence() {
+ if (isAmbiguous()) Ambiguous.destruct();
+ }
+ ImplicitConversionSequence(const ImplicitConversionSequence &Other)
+ : ConversionKind(Other.ConversionKind)
+ {
+ switch (ConversionKind) {
+ case StandardConversion: Standard = Other.Standard; break;
+ case UserDefinedConversion: UserDefined = Other.UserDefined; break;
+ case AmbiguousConversion: Ambiguous.copyFrom(Other.Ambiguous); break;
+ case EllipsisConversion: break;
+ case BadConversion: Bad = Other.Bad; break;
+ }
+ }
+
+ ImplicitConversionSequence &
+ operator=(const ImplicitConversionSequence &Other) {
+ if (isAmbiguous()) Ambiguous.destruct();
+ new (this) ImplicitConversionSequence(Other);
+ return *this;
+ }
- /// When ConversionKind == BadConversion due to multiple conversion
- /// functions, this will list those functions.
- llvm::SmallVector<FunctionDecl*, 4> ConversionFunctionSet;
-
+ Kind getKind() const { return ConversionKind; }
+ bool isBad() const { return ConversionKind == BadConversion; }
+ bool isStandard() const { return ConversionKind == StandardConversion; }
+ bool isEllipsis() const { return ConversionKind == EllipsisConversion; }
+ bool isAmbiguous() const { return ConversionKind == AmbiguousConversion; }
+ bool isUserDefined() const {
+ return ConversionKind == UserDefinedConversion;
+ }
+
+ void setBad() { setKind(BadConversion); }
+ void setStandard() { setKind(StandardConversion); }
+ void setEllipsis() { setKind(EllipsisConversion); }
+ void setUserDefined() { setKind(UserDefinedConversion); }
+ void setAmbiguous() {
+ if (isAmbiguous()) return;
+ ConversionKind = AmbiguousConversion;
+ Ambiguous.construct();
+ }
+
// The result of a comparison between implicit conversion
// sequences. Use Sema::CompareImplicitConversionSequences to
// actually perform the comparison.
@@ -235,6 +386,13 @@ namespace clang {
void DebugPrint() const;
};
+ enum OverloadFailureKind {
+ ovl_fail_too_many_arguments,
+ ovl_fail_too_few_arguments,
+ ovl_fail_bad_conversion,
+ ovl_fail_bad_deduction
+ };
+
/// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
struct OverloadCandidate {
/// Function - The actual function that this candidate
@@ -275,11 +433,25 @@ namespace clang {
/// object argument.
bool IgnoreObjectArgument;
+ /// FailureKind - The reason why this candidate is not viable.
+ /// Actually an OverloadFailureKind.
+ unsigned char FailureKind;
+
/// FinalConversion - For a conversion function (where Function is
/// a CXXConversionDecl), the standard conversion that occurs
/// after the call to the overload candidate to convert the result
/// of calling the conversion function to the required type.
StandardConversionSequence FinalConversion;
+
+ /// hasAmbiguousConversion - Returns whether this overload
+ /// candidate requires an ambiguous conversion or not.
+ bool hasAmbiguousConversion() const {
+ for (llvm::SmallVectorImpl<ImplicitConversionSequence>::const_iterator
+ I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
+ if (I->isAmbiguous()) return true;
+ }
+ return false;
+ }
};
/// OverloadCandidateSet - A set of overload candidates, used in C++
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index b8928c3..7855a7f 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -1157,7 +1157,8 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
MultiExprArg exprs,
ExprArg asmString,
MultiExprArg clobbers,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ bool MSAsm) {
unsigned NumClobbers = clobbers.size();
StringLiteral **Constraints =
reinterpret_cast<StringLiteral**>(constraints.get());
@@ -1261,9 +1262,9 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
asmString.release();
clobbers.release();
AsmStmt *NS =
- new (Context) AsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs,
- Names, Constraints, Exprs, AsmString, NumClobbers,
- Clobbers, RParenLoc);
+ new (Context) AsmStmt(AsmLoc, IsSimple, IsVolatile, MSAsm, NumOutputs,
+ NumInputs, Names, Constraints, Exprs, AsmString,
+ NumClobbers, Clobbers, RParenLoc);
// Validate the asm string, ensuring it makes sense given the operands we
// have.
llvm::SmallVector<AsmStmt::AsmStringPiece, 8> Pieces;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 8c6aa6a..2fad832 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -80,6 +80,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
TypeTy *ObjectTypePtr,
bool EnteringContext,
TemplateTy &TemplateResult) {
+ assert(getLangOptions().CPlusPlus && "No template names in C!");
+
DeclarationName TName;
switch (Name.getKind()) {
@@ -141,6 +143,30 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
return TemplateKind;
}
+bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
+ SourceLocation IILoc,
+ Scope *S,
+ const CXXScopeSpec *SS,
+ TemplateTy &SuggestedTemplate,
+ TemplateNameKind &SuggestedKind) {
+ // We can't recover unless there's a dependent scope specifier preceding the
+ // template name.
+ if (!SS || !SS->isSet() || !isDependentScopeSpecifier(*SS) ||
+ computeDeclContext(*SS))
+ return false;
+
+ // The code is missing a 'template' keyword prior to the dependent template
+ // name.
+ NestedNameSpecifier *Qualifier = (NestedNameSpecifier*)SS->getScopeRep();
+ Diag(IILoc, diag::err_template_kw_missing)
+ << Qualifier << II.getName()
+ << CodeModificationHint::CreateInsertion(IILoc, "template ");
+ SuggestedTemplate
+ = TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II));
+ SuggestedKind = TNK_Dependent_template_name;
+ return true;
+}
+
void Sema::LookupTemplateName(LookupResult &Found,
Scope *S, const CXXScopeSpec &SS,
QualType ObjectType,
@@ -192,7 +218,8 @@ void Sema::LookupTemplateName(LookupResult &Found,
ObjectTypeSearchedInScope = true;
}
} else if (isDependent) {
- // We cannot look into a dependent object type or
+ // We cannot look into a dependent object type or nested nme
+ // specifier.
return;
} else {
// Perform unqualified name lookup in the current scope.
@@ -203,7 +230,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
assert(!Found.isAmbiguous() &&
"Cannot handle template name-lookup ambiguities");
- if (Found.empty()) {
+ if (Found.empty() && !isDependent) {
// If we did not find any names, attempt to correct any typos.
DeclarationName Name = Found.getLookupName();
if (CorrectTypo(Found, S, &SS, LookupCtx)) {
@@ -219,6 +246,9 @@ void Sema::LookupTemplateName(LookupResult &Found,
<< Name << Found.getLookupName()
<< CodeModificationHint::CreateReplacement(Found.getNameLoc(),
Found.getLookupName().getAsString());
+ if (TemplateDecl *Template = Found.getAsSingle<TemplateDecl>())
+ Diag(Template->getLocation(), diag::note_previous_decl)
+ << Template->getDeclName();
} else
Found.clear();
} else {
@@ -1578,15 +1608,19 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
TemplateTy Template;
TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType,
EnteringContext, Template);
- if (TNK == TNK_Non_template) {
+ if (TNK == TNK_Non_template &&
+ isCurrentInstantiationWithDependentBases(SS)) {
+ // This is a dependent template.
+ } else if (TNK == TNK_Non_template) {
Diag(Name.getSourceRange().getBegin(),
diag::err_template_kw_refers_to_non_template)
<< GetNameFromUnqualifiedId(Name)
<< Name.getSourceRange();
return TemplateTy();
+ } else {
+ // We found something; return it.
+ return Template;
}
-
- return Template;
}
NestedNameSpecifier *Qualifier
@@ -4537,8 +4571,10 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Prev)) {
if (Context.hasSameUnqualifiedType(Method->getType(), R)) {
Matches.clear();
+
Matches.push_back(Method);
- break;
+ if (Method->getTemplateSpecializationKind() == TSK_Undeclared)
+ break;
}
}
}
@@ -4550,7 +4586,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
TemplateDeductionInfo Info(Context);
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult TDK
- = DeduceTemplateArguments(FunTmpl,
+ = DeduceTemplateArguments(FunTmpl,
(HasExplicitTemplateArgs ? &TemplateArgs : 0),
R, Specialization, Info)) {
// FIXME: Keep track of almost-matches?
@@ -4735,6 +4771,10 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
case LookupResult::NotFound:
DiagID = diag::err_typename_nested_not_found;
break;
+
+ case LookupResult::NotFoundInCurrentInstantiation:
+ // Okay, it's a member of an unknown instantiation.
+ return Context.getTypenameType(NNS, &II);
case LookupResult::Found:
if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 21f7996..7b433e9 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -542,13 +542,13 @@ DeduceTemplateArguments(ASTContext &Context,
// type [i]
case Type::DependentSizedArray: {
- const ArrayType *ArrayArg = dyn_cast<ArrayType>(Arg);
+ const ArrayType *ArrayArg = Context.getAsArrayType(Arg);
if (!ArrayArg)
return Sema::TDK_NonDeducedMismatch;
// Check the element type of the arrays
const DependentSizedArrayType *DependentArrayParm
- = cast<DependentSizedArrayType>(Param);
+ = Context.getAsDependentSizedArrayType(Param);
if (Sema::TemplateDeductionResult Result
= DeduceTemplateArguments(Context, TemplateParams,
DependentArrayParm->getElementType(),
@@ -1312,20 +1312,18 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
/// \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 explicit template arguments provided
+/// for this call.
///
/// \param Args the function call arguments
///
/// \param NumArgs the number of arguments in Args
///
+/// \param Name the name of the function being called. This is only significant
+/// when the function template is a conversion function template, in which
+/// case this routine will also perform template argument deduction based on
+/// the function to which
+///
/// \param Specialization if template argument deduction was successful,
/// this will be set to the function template specialization produced by
/// template argument deduction.
@@ -1336,7 +1334,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
/// \returns the result of template argument deduction.
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
@@ -1475,8 +1473,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
return TDK_FailedOverloadResolution;
}
- // Get the type of the resolved argument.
+ // Get the type of the resolved argument, and adjust it per
+ // C++0x [temp.deduct.call]p3.
ArgType = ResolvedArg->getType();
+ if (!ParamWasReference && ArgType->isFunctionType())
+ ArgType = Context.getPointerType(ArgType);
if (ArgType->isPointerType() || ArgType->isMemberPointerType())
TDF |= TDF_IgnoreQualifiers;
@@ -2173,7 +2174,7 @@ MarkUsedTemplateParameters(Sema &SemaRef,
// FIXME: if !OnlyDeduced, we have to walk the whole subexpression to
// find other occurrences of template parameters.
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
- if (!E)
+ if (!DRE)
return;
const NonTypeTemplateParmDecl *NTTP
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index d974f89..2db0deb 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1060,6 +1060,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Exit the scope of this instantiation.
CurContext = PreviousContext;
+ // If this is a polymorphic C++ class without a key function, we'll
+ // have to mark all of the virtual members to allow emission of a vtable
+ // in this translation unit.
+ if (Instantiation->isDynamicClass() && !Context.getKeyFunction(Instantiation))
+ ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Instantiation,
+ PointOfInstantiation));
+
if (!Invalid)
Consumer.HandleTagDeclDefinition(Instantiation);
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index ed30229..9515834 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -743,7 +743,8 @@ QualType Sema::BuildFunctionType(QualType T,
bool Variadic, unsigned Quals,
SourceLocation Loc, DeclarationName Entity) {
if (T->isArrayType() || T->isFunctionType()) {
- Diag(Loc, diag::err_func_returning_array_function) << T;
+ Diag(Loc, diag::err_func_returning_array_function)
+ << T->isFunctionType() << T;
return QualType();
}
@@ -896,13 +897,18 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
break;
case UnqualifiedId::IK_ConstructorName:
+ case UnqualifiedId::IK_ConstructorTemplateId:
case UnqualifiedId::IK_DestructorName:
- case UnqualifiedId::IK_ConversionFunctionId:
// Constructors and destructors don't have return types. Use
- // "void" instead. Conversion operators will check their return
- // types separately.
+ // "void" instead.
T = Context.VoidTy;
break;
+
+ case UnqualifiedId::IK_ConversionFunctionId:
+ // The result type of a conversion function is the type that it
+ // converts to.
+ T = GetTypeFromParser(D.getName().ConversionFunctionId);
+ break;
}
if (T.isNull())
@@ -1041,8 +1047,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
// C99 6.7.5.3p1: The return type may not be a function or array type.
- if (T->isArrayType() || T->isFunctionType()) {
- Diag(DeclType.Loc, diag::err_func_returning_array_function) << T;
+ // For conversion functions, we'll diagnose this particular error later.
+ if ((T->isArrayType() || T->isFunctionType()) &&
+ (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) {
+ Diag(DeclType.Loc, diag::err_func_returning_array_function)
+ << T->isFunctionType() << T;
T = Context.IntTy;
D.setInvalidType(true);
}
@@ -1351,6 +1360,20 @@ namespace {
cast<TemplateSpecializationTypeLoc>(TInfo->getTypeLoc());
TL.copy(OldTL);
}
+ void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
+ assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr);
+ TL.setTypeofLoc(DS.getTypeSpecTypeLoc());
+ TL.setParensRange(DS.getTypeofParensRange());
+ }
+ void VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
+ assert(DS.getTypeSpecType() == DeclSpec::TST_typeofType);
+ TL.setTypeofLoc(DS.getTypeSpecTypeLoc());
+ TL.setParensRange(DS.getTypeofParensRange());
+ assert(DS.getTypeRep());
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo);
+ TL.setUnderlyingTInfo(TInfo);
+ }
void VisitTypeLoc(TypeLoc TL) {
// FIXME: add other typespec types and change this to an assert.
TL.initialize(DS.getTypeSpecTypeLoc());
@@ -1461,34 +1484,6 @@ void LocInfoType::getAsStringInternal(std::string &Str,
" GetTypeFromParser");
}
-/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition
-/// declarator
-QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) {
- ObjCMethodDecl *MDecl = cast<ObjCMethodDecl>(D.getAs<Decl>());
- QualType T = MDecl->getResultType();
- llvm::SmallVector<QualType, 16> ArgTys;
-
- // Add the first two invisible argument types for self and _cmd.
- if (MDecl->isInstanceMethod()) {
- QualType selfTy = Context.getObjCInterfaceType(MDecl->getClassInterface());
- selfTy = Context.getPointerType(selfTy);
- ArgTys.push_back(selfTy);
- } else
- ArgTys.push_back(Context.getObjCIdType());
- ArgTys.push_back(Context.getObjCSelType());
-
- for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(),
- E = MDecl->param_end(); PI != E; ++PI) {
- QualType ArgTy = (*PI)->getType();
- assert(!ArgTy.isNull() && "Couldn't parse type?");
- ArgTy = adjustParameterType(ArgTy);
- ArgTys.push_back(ArgTy);
- }
- T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(),
- MDecl->isVariadic(), 0);
- return T;
-}
-
/// UnwrapSimilarPointerTypes - If T1 and T2 are pointer types that
/// may be similar (C++ 4.4), replaces T1 and T2 with the type that
/// they point to and return true. If T1 and T2 aren't pointer types
diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp
new file mode 100644
index 0000000..7c19bf6
--- /dev/null
+++ b/lib/Sema/TargetAttributesSema.cpp
@@ -0,0 +1,86 @@
+//===-- TargetAttributesSema.cpp - Encapsulate target attributes-*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains semantic analysis implementation for target-specific
+// attributes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "TargetAttributesSema.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/Triple.h"
+
+using namespace clang;
+
+TargetAttributesSema::~TargetAttributesSema() {}
+bool TargetAttributesSema::ProcessDeclAttribute(Scope *scope, Decl *D,
+ const AttributeList &Attr, Sema &S) const {
+ return false;
+}
+
+static void HandleMSP430InterruptAttr(Decl *d,
+ const AttributeList &Attr, Sema &S) {
+ // Check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ // FIXME: Check for decl - it should be void ()(void).
+
+ Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt NumParams(32);
+ if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << "interrupt" << NumParamsExpr->getSourceRange();
+ return;
+ }
+
+ unsigned Num = NumParams.getLimitedValue(255);
+ if ((Num & 1) || Num > 30) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << "interrupt" << (int)NumParams.getSExtValue()
+ << NumParamsExpr->getSourceRange();
+ return;
+ }
+
+ d->addAttr(::new (S.Context) MSP430InterruptAttr(Num));
+ d->addAttr(::new (S.Context) UsedAttr());
+ }
+
+namespace {
+ class MSP430AttributesSema : public TargetAttributesSema {
+ public:
+ MSP430AttributesSema() { }
+ bool ProcessDeclAttribute(Scope *scope, Decl *D,
+ const AttributeList &Attr, Sema &S) const {
+ if (Attr.getName()->getName() == "interrupt") {
+ HandleMSP430InterruptAttr(D, Attr, S);
+ return true;
+ }
+ return false;
+ }
+ };
+}
+
+const TargetAttributesSema &Sema::getTargetAttributesSema() const {
+ if (TheTargetAttributesSema)
+ return *TheTargetAttributesSema;
+
+ const llvm::Triple &Triple(Context.Target.getTriple());
+ switch (Triple.getArch()) {
+ default:
+ return *(TheTargetAttributesSema = new TargetAttributesSema);
+
+ case llvm::Triple::msp430:
+ return *(TheTargetAttributesSema = new MSP430AttributesSema);
+ }
+}
+
diff --git a/lib/Sema/TargetAttributesSema.h b/lib/Sema/TargetAttributesSema.h
new file mode 100644
index 0000000..8794e40
--- /dev/null
+++ b/lib/Sema/TargetAttributesSema.h
@@ -0,0 +1,27 @@
+//===--- TargetAttributesSema.h - Semantic Analysis For Target Attributes -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_SEMA_TARGETSEMA_H
+#define CLANG_SEMA_TARGETSEMA_H
+
+namespace clang {
+ class Scope;
+ class Decl;
+ class Attr;
+ class Sema;
+
+ class TargetAttributesSema {
+ public:
+ virtual ~TargetAttributesSema();
+ virtual bool ProcessDeclAttribute(Scope *scope, Decl *D,
+ const AttributeList &Attr, Sema &S) const;
+ };
+}
+
+#endif
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 208c885..445ef0d 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -975,12 +975,15 @@ public:
QualType BaseType = ((Expr*) Base.get())->getType();
- // FIXME: wait, this is re-performing lookup?
+ LookupResult R(getSema(), Member->getDeclName(), MemberLoc,
+ Sema::LookupMemberName);
+ R.addDecl(Member);
+ R.resolveKind();
+
return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
OpLoc, isArrow,
SS, FirstQualifierInScope,
- Member->getDeclName(), MemberLoc,
- ExplicitTemplateArgs);
+ R, ExplicitTemplateArgs);
}
/// \brief Build a new binary operator expression.
@@ -1344,9 +1347,11 @@ public:
/// semantic analysis. Subclasses may override this routine to provide
/// different behavior.
OwningExprResult RebuildCXXThisExpr(SourceLocation ThisLoc,
- QualType ThisType) {
+ QualType ThisType,
+ bool isImplicit) {
return getSema().Owned(
- new (getSema().Context) CXXThisExpr(ThisLoc, ThisType));
+ new (getSema().Context) CXXThisExpr(ThisLoc, ThisType,
+ isImplicit));
}
/// \brief Build a new C++ throw expression.
@@ -1559,6 +1564,7 @@ public:
bool IsArrow,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
+ NamedDecl *FirstQualifierInScope,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
@@ -1567,7 +1573,8 @@ public:
return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType,
OperatorLoc, IsArrow,
- SS, R, TemplateArgs);
+ SS, FirstQualifierInScope,
+ R, TemplateArgs);
}
/// \brief Build a new Objective-C @encode expression.
@@ -2617,18 +2624,16 @@ QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
TypeOfExprTypeLoc TL) {
- TypeOfExprType *T = TL.getTypePtr();
-
// typeof expressions are not potentially evaluated contexts
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
- Sema::OwningExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr());
+ Sema::OwningExprResult E = getDerived().TransformExpr(TL.getUnderlyingExpr());
if (E.isInvalid())
return QualType();
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
- E.get() != T->getUnderlyingExpr()) {
+ E.get() != TL.getUnderlyingExpr()) {
Result = getDerived().RebuildTypeOfExprType(move(E));
if (Result.isNull())
return QualType();
@@ -2636,7 +2641,9 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
else E.take();
TypeOfExprTypeLoc NewTL = TLB.push<TypeOfExprTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
+ NewTL.setTypeofLoc(TL.getTypeofLoc());
+ NewTL.setLParenLoc(TL.getLParenLoc());
+ NewTL.setRParenLoc(TL.getRParenLoc());
return Result;
}
@@ -2644,23 +2651,23 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB,
TypeOfTypeLoc TL) {
- TypeOfType *T = TL.getTypePtr();
-
- // FIXME: should be an inner type, or at least have a TypeSourceInfo.
- QualType Underlying = getDerived().TransformType(T->getUnderlyingType());
- if (Underlying.isNull())
+ TypeSourceInfo* Old_Under_TI = TL.getUnderlyingTInfo();
+ TypeSourceInfo* New_Under_TI = getDerived().TransformType(Old_Under_TI);
+ if (!New_Under_TI)
return QualType();
QualType Result = TL.getType();
- if (getDerived().AlwaysRebuild() ||
- Underlying != T->getUnderlyingType()) {
- Result = getDerived().RebuildTypeOfType(Underlying);
+ if (getDerived().AlwaysRebuild() || New_Under_TI != Old_Under_TI) {
+ Result = getDerived().RebuildTypeOfType(New_Under_TI->getType());
if (Result.isNull())
return QualType();
}
TypeOfTypeLoc NewTL = TLB.push<TypeOfTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
+ NewTL.setTypeofLoc(TL.getTypeofLoc());
+ NewTL.setLParenLoc(TL.getLParenLoc());
+ NewTL.setRParenLoc(TL.getRParenLoc());
+ NewTL.setUnderlyingTInfo(New_Under_TI);
return Result;
}
@@ -3711,6 +3718,12 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
SourceLocation FakeOperatorLoc
= SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd());
+ // FIXME: to do this check properly, we will need to preserve the
+ // first-qualifier-in-scope here, just in case we had a dependent
+ // base (and therefore couldn't do the check) and a
+ // nested-name-qualifier (and therefore could do the lookup).
+ NamedDecl *FirstQualifierInScope = 0;
+
return getDerived().RebuildMemberExpr(move(Base), FakeOperatorLoc,
E->isArrow(),
Qualifier,
@@ -3719,7 +3732,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
Member,
(E->hasExplicitTemplateArgumentList()
? &TransArgs : 0),
- 0);
+ FirstQualifierInScope);
}
template<typename Derived>
@@ -4386,7 +4399,7 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
T == E->getType())
return SemaRef.Owned(E->Retain());
- return getDerived().RebuildCXXThisExpr(E->getLocStart(), T);
+ return getDerived().RebuildCXXThisExpr(E->getLocStart(), T, E->isImplicit());
}
template<typename Derived>
@@ -5027,6 +5040,12 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
TransArgs.addArgument(Loc);
}
}
+
+ // FIXME: to do this check properly, we will need to preserve the
+ // first-qualifier-in-scope here, just in case we had a dependent
+ // base (and therefore couldn't do the check) and a
+ // nested-name-qualifier (and therefore could do the lookup).
+ NamedDecl *FirstQualifierInScope = 0;
return getDerived().RebuildUnresolvedMemberExpr(move(Base),
BaseType,
@@ -5034,6 +5053,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
Old->isArrow(),
Qualifier,
Old->getQualifierRange(),
+ FirstQualifierInScope,
R,
(Old->hasExplicitTemplateArgs()
? &TransArgs : 0));
OpenPOWER on IntegriCloud