summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2010-05-04 16:12:48 +0000
committerrdivacky <rdivacky@FreeBSD.org>2010-05-04 16:12:48 +0000
commit8aaf5818a64e9f7687798852af5945b053c68a54 (patch)
treed6a70c3518b8dea8be7062438d7e8676820ed17f /lib
parent71438373cd57f0d5d8c93bb5cf690844a0fbc9d0 (diff)
downloadFreeBSD-src-8aaf5818a64e9f7687798852af5945b053c68a54.zip
FreeBSD-src-8aaf5818a64e9f7687798852af5945b053c68a54.tar.gz
Update clang to r103004.
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/APValue.cpp3
-rw-r--r--lib/AST/ASTContext.cpp211
-rw-r--r--lib/AST/ASTDiagnostic.cpp6
-rw-r--r--lib/AST/ASTImporter.cpp28
-rw-r--r--lib/AST/Decl.cpp193
-rw-r--r--lib/AST/DeclBase.cpp38
-rw-r--r--lib/AST/DeclCXX.cpp48
-rw-r--r--lib/AST/DeclObjC.cpp18
-rw-r--r--lib/AST/DeclPrinter.cpp69
-rw-r--r--lib/AST/DeclTemplate.cpp22
-rw-r--r--lib/AST/DeclarationName.cpp59
-rw-r--r--lib/AST/Expr.cpp444
-rw-r--r--lib/AST/ExprCXX.cpp53
-rw-r--r--lib/AST/ExprConstant.cpp112
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp568
-rw-r--r--lib/AST/RecordLayoutBuilder.h8
-rw-r--r--lib/AST/Stmt.cpp89
-rw-r--r--lib/AST/StmtDumper.cpp78
-rw-r--r--lib/AST/StmtPrinter.cpp73
-rw-r--r--lib/AST/StmtProfile.cpp28
-rw-r--r--lib/AST/TemplateName.cpp18
-rw-r--r--lib/AST/Type.cpp20
-rw-r--r--lib/AST/TypePrinter.cpp4
-rw-r--r--lib/Analysis/CFG.cpp68
-rw-r--r--lib/Basic/Diagnostic.cpp70
-rw-r--r--lib/Basic/IdentifierTable.cpp6
-rw-r--r--lib/Basic/SourceManager.cpp100
-rw-r--r--lib/Basic/TargetInfo.cpp12
-rw-r--r--lib/Basic/Targets.cpp33
-rw-r--r--lib/Checker/BasicObjCFoundationChecks.cpp41
-rw-r--r--lib/Checker/BasicStore.cpp2
-rw-r--r--lib/Checker/BugReporter.cpp2
-rw-r--r--lib/Checker/BugReporterVisitors.cpp14
-rw-r--r--lib/Checker/CFRefCount.cpp115
-rw-r--r--lib/Checker/CMakeLists.txt1
-rw-r--r--lib/Checker/CallAndMessageChecker.cpp19
-rw-r--r--lib/Checker/CastToStructChecker.cpp2
-rw-r--r--lib/Checker/CheckObjCDealloc.cpp30
-rw-r--r--lib/Checker/CheckObjCInstMethSignature.cpp6
-rw-r--r--lib/Checker/CheckSecuritySyntaxOnly.cpp12
-rw-r--r--lib/Checker/Environment.cpp7
-rw-r--r--lib/Checker/GRCXXExprEngine.cpp246
-rw-r--r--lib/Checker/GRCoreEngine.cpp27
-rw-r--r--lib/Checker/GRExprEngine.cpp369
-rw-r--r--lib/Checker/MemRegion.cpp21
-rw-r--r--lib/Checker/NSAutoreleasePoolChecker.cpp2
-rw-r--r--lib/Checker/NSErrorChecker.cpp2
-rw-r--r--lib/Checker/ObjCUnusedIVarsChecker.cpp3
-rw-r--r--lib/Checker/RegionStore.cpp44
-rw-r--r--lib/Checker/SVals.cpp3
-rw-r--r--lib/Checker/SimpleSValuator.cpp22
-rw-r--r--lib/Checker/Store.cpp22
-rw-r--r--lib/Checker/UnixAPIChecker.cpp85
-rw-r--r--lib/CodeGen/CGBlocks.cpp24
-rw-r--r--lib/CodeGen/CGBlocks.h3
-rw-r--r--lib/CodeGen/CGBuiltin.cpp91
-rw-r--r--lib/CodeGen/CGCXX.cpp12
-rw-r--r--lib/CodeGen/CGCall.cpp11
-rw-r--r--lib/CodeGen/CGClass.cpp664
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp209
-rw-r--r--lib/CodeGen/CGDebugInfo.h10
-rw-r--r--lib/CodeGen/CGDecl.cpp62
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp11
-rw-r--r--lib/CodeGen/CGException.cpp235
-rw-r--r--lib/CodeGen/CGExpr.cpp335
-rw-r--r--lib/CodeGen/CGExprAgg.cpp25
-rw-r--r--lib/CodeGen/CGExprCXX.cpp50
-rw-r--r--lib/CodeGen/CGExprConstant.cpp579
-rw-r--r--lib/CodeGen/CGExprScalar.cpp133
-rw-r--r--lib/CodeGen/CGObjC.cpp216
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp230
-rw-r--r--lib/CodeGen/CGObjCMac.cpp341
-rw-r--r--lib/CodeGen/CGObjCRuntime.h5
-rw-r--r--lib/CodeGen/CGRTTI.cpp101
-rw-r--r--lib/CodeGen/CGRecordLayout.h134
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp306
-rw-r--r--lib/CodeGen/CGStmt.cpp64
-rw-r--r--lib/CodeGen/CGTemporaries.cpp12
-rw-r--r--lib/CodeGen/CGVTT.cpp24
-rw-r--r--lib/CodeGen/CGVTables.cpp (renamed from lib/CodeGen/CGVtable.cpp)451
-rw-r--r--lib/CodeGen/CGVTables.h (renamed from lib/CodeGen/CGVtable.h)39
-rw-r--r--lib/CodeGen/CGValue.h67
-rw-r--r--lib/CodeGen/CMakeLists.txt2
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp24
-rw-r--r--lib/CodeGen/CodeGenFunction.h93
-rw-r--r--lib/CodeGen/CodeGenModule.cpp239
-rw-r--r--lib/CodeGen/CodeGenModule.h37
-rw-r--r--lib/CodeGen/CodeGenTypes.h5
-rw-r--r--lib/CodeGen/Mangle.cpp239
-rw-r--r--lib/CodeGen/Mangle.h12
-rw-r--r--lib/CodeGen/TargetInfo.cpp83
-rw-r--r--lib/Driver/Driver.cpp6
-rw-r--r--lib/Driver/ToolChains.cpp21
-rw-r--r--lib/Driver/ToolChains.h17
-rw-r--r--lib/Driver/Tools.cpp129
-rw-r--r--lib/Driver/Tools.h5
-rw-r--r--lib/Frontend/ASTConsumers.cpp191
-rw-r--r--lib/Frontend/ASTUnit.cpp18
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp209
-rw-r--r--lib/Frontend/CacheTokens.cpp5
-rw-r--r--lib/Frontend/CodeGenAction.cpp313
-rw-r--r--lib/Frontend/CompilerInstance.cpp19
-rw-r--r--lib/Frontend/CompilerInvocation.cpp135
-rw-r--r--lib/Frontend/FixItRewriter.cpp105
-rw-r--r--lib/Frontend/FrontendActions.cpp71
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp59
-rw-r--r--lib/Frontend/InitPreprocessor.cpp30
-rw-r--r--lib/Frontend/LangStandards.cpp2
-rw-r--r--lib/Frontend/PCHReader.cpp34
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp17
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp135
-rw-r--r--lib/Frontend/PCHWriter.cpp15
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp10
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp83
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp9
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp50
-rw-r--r--lib/Frontend/RewriteMacros.cpp3
-rw-r--r--lib/Frontend/RewriteObjC.cpp528
-rw-r--r--lib/Frontend/StmtXML.cpp5
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp24
-rw-r--r--lib/Frontend/VerifyDiagnosticsClient.cpp463
-rw-r--r--lib/Frontend/Warnings.cpp6
-rw-r--r--lib/Headers/CMakeLists.txt2
-rw-r--r--lib/Headers/altivec.h1483
-rw-r--r--lib/Headers/arm_neon.h537
-rw-r--r--lib/Headers/nmmintrin.h2
-rw-r--r--lib/Headers/stdint.h7
-rw-r--r--lib/Headers/tmmintrin.h2
-rw-r--r--lib/Index/ASTLocation.cpp4
-rw-r--r--lib/Index/Analyzer.cpp79
-rw-r--r--lib/Lex/Lexer.cpp6
-rw-r--r--lib/Lex/LiteralSupport.cpp5
-rw-r--r--lib/Lex/PPDirectives.cpp24
-rw-r--r--lib/Lex/PPLexerChange.cpp20
-rw-r--r--lib/Lex/PPMacroExpansion.cpp31
-rw-r--r--lib/Lex/Preprocessor.cpp8
-rw-r--r--lib/Lex/TokenConcatenation.cpp6
-rw-r--r--lib/Parse/AttributeList.cpp3
-rw-r--r--lib/Parse/DeclSpec.cpp1
-rw-r--r--lib/Parse/MinimalAction.cpp37
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp50
-rw-r--r--lib/Parse/ParseDecl.cpp112
-rw-r--r--lib/Parse/ParseDeclCXX.cpp16
-rw-r--r--lib/Parse/ParseExpr.cpp106
-rw-r--r--lib/Parse/ParseExprCXX.cpp33
-rw-r--r--lib/Parse/ParseInit.cpp132
-rw-r--r--lib/Parse/ParseObjc.cpp350
-rw-r--r--lib/Parse/ParseStmt.cpp13
-rw-r--r--lib/Parse/ParseTentative.cpp13
-rw-r--r--lib/Parse/Parser.cpp12
-rw-r--r--lib/Rewrite/HTMLRewrite.cpp4
-rw-r--r--lib/Rewrite/Rewriter.cpp8
-rw-r--r--lib/Runtime/Makefile2
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp93
-rw-r--r--lib/Sema/AnalysisBasedWarnings.h4
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp4
-rw-r--r--lib/Sema/JumpDiagnostics.cpp4
-rw-r--r--lib/Sema/Lookup.h25
-rw-r--r--lib/Sema/ParseAST.cpp27
-rw-r--r--lib/Sema/Sema.cpp22
-rw-r--r--lib/Sema/Sema.h807
-rw-r--r--lib/Sema/SemaAccess.cpp706
-rw-r--r--lib/Sema/SemaCXXCast.cpp239
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp110
-rw-r--r--lib/Sema/SemaChecking.cpp198
-rw-r--r--lib/Sema/SemaCodeComplete.cpp584
-rw-r--r--lib/Sema/SemaDecl.cpp868
-rw-r--r--lib/Sema/SemaDeclAttr.cpp58
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2088
-rw-r--r--lib/Sema/SemaDeclObjC.cpp237
-rw-r--r--lib/Sema/SemaExpr.cpp768
-rw-r--r--lib/Sema/SemaExprCXX.cpp537
-rw-r--r--lib/Sema/SemaExprObjC.cpp1004
-rw-r--r--lib/Sema/SemaInit.cpp428
-rw-r--r--lib/Sema/SemaInit.h60
-rw-r--r--lib/Sema/SemaLookup.cpp501
-rw-r--r--lib/Sema/SemaObjCProperty.cpp61
-rw-r--r--lib/Sema/SemaOverload.cpp798
-rw-r--r--lib/Sema/SemaOverload.h35
-rw-r--r--lib/Sema/SemaStmt.cpp214
-rw-r--r--lib/Sema/SemaTemplate.cpp496
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp160
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp274
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp336
-rw-r--r--lib/Sema/SemaType.cpp124
-rw-r--r--lib/Sema/TreeTransform.h817
186 files changed, 18136 insertions, 9130 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 50a6e0a..731d5e0 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -48,7 +48,8 @@ const APValue &APValue::operator=(const APValue &RHS) {
else if (isFloat())
setFloat(RHS.getFloat());
else if (isVector())
- setVector(((Vec*)(char*)RHS.Data)->Elts, RHS.getVectorLength());
+ setVector(((const Vec *)(const char *)RHS.Data)->Elts,
+ RHS.getVectorLength());
else if (isComplexInt())
setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag());
else if (isComplexFloat())
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index c77acce..eea727d 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -41,6 +41,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
Builtin::Context &builtins,
bool FreeMem, unsigned size_reserve) :
GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0),
+ NSConstantStringTypeDecl(0),
ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0),
sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0),
SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t),
@@ -325,55 +326,6 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst,
InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl;
}
-CXXMethodVector::iterator CXXMethodVector::begin() const {
- if ((Storage & 0x01) == 0)
- return reinterpret_cast<iterator>(&Storage);
-
- vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
- return &Vec->front();
-}
-
-CXXMethodVector::iterator CXXMethodVector::end() const {
- if ((Storage & 0x01) == 0) {
- if (Storage == 0)
- return reinterpret_cast<iterator>(&Storage);
-
- return reinterpret_cast<iterator>(&Storage) + 1;
- }
-
- vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
- return &Vec->front() + Vec->size();
-}
-
-void CXXMethodVector::push_back(const CXXMethodDecl *Method) {
- if (Storage == 0) {
- // 0 -> 1 element.
- Storage = reinterpret_cast<uintptr_t>(Method);
- return;
- }
-
- vector_type *Vec;
- if ((Storage & 0x01) == 0) {
- // 1 -> 2 elements. Allocate a new vector and push the element into that
- // vector.
- Vec = new vector_type;
- Vec->push_back(reinterpret_cast<const CXXMethodDecl *>(Storage));
- Storage = reinterpret_cast<uintptr_t>(Vec) | 0x01;
- } else
- Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
-
- // Add the new method to the vector.
- Vec->push_back(Method);
-}
-
-void CXXMethodVector::Destroy() {
- if (Storage & 0x01)
- delete reinterpret_cast<vector_type *>(Storage & ~0x01);
-
- Storage = 0;
-}
-
-
ASTContext::overridden_cxx_method_iterator
ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
@@ -515,7 +467,7 @@ ASTContext::getTypeInfo(const Type *T) {
Align = Width;
// If the alignment is not a power of 2, round up to the next power of 2.
// This happens for non-power-of-2 length vectors.
- if (VT->getNumElements() & (VT->getNumElements()-1)) {
+ if (Align & (Align-1)) {
Align = llvm::NextPowerOf2(Align);
Width = llvm::RoundUpToAlignment(Width, Align);
}
@@ -701,10 +653,6 @@ ASTContext::getTypeInfo(const Type *T) {
case Type::QualifiedName:
return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr());
- case Type::InjectedClassName:
- return getTypeInfo(cast<InjectedClassNameType>(T)
- ->getUnderlyingType().getTypePtr());
-
case Type::TemplateSpecialization:
assert(getCanonicalType(T) != T &&
"Cannot request the size of a dependent type");
@@ -833,9 +781,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
CollectInheritedProtocols(SD, Protocols);
SD = SD->getSuperClass();
}
- return;
- }
- if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) {
+ } else if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) {
for (ObjCInterfaceDecl::protocol_iterator P = OC->protocol_begin(),
PE = OC->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
@@ -844,9 +790,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
PE = Proto->protocol_end(); P != PE; ++P)
CollectInheritedProtocols(*P, Protocols);
}
- return;
- }
- if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) {
+ } else if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) {
for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(),
PE = OP->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
@@ -855,26 +799,20 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
PE = Proto->protocol_end(); P != PE; ++P)
CollectInheritedProtocols(*P, Protocols);
}
- return;
}
}
unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) {
unsigned count = 0;
// Count ivars declared in class extension.
- if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) {
- for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(),
- E = CDecl->ivar_end(); I != E; ++I) {
- ++count;
- }
- }
-
+ if (const ObjCCategoryDecl *CDecl = OI->getClassExtension())
+ count += CDecl->ivar_size();
+
// Count ivar defined in this class's implementation. This
// includes synthesized ivars.
if (ObjCImplementationDecl *ImplDecl = OI->getImplementation())
- for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
- E = ImplDecl->ivar_end(); I != E; ++I)
- ++count;
+ count += ImplDecl->ivar_size();
+
return count;
}
@@ -998,6 +936,11 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
ASTRecordLayoutBuilder::ComputeLayout(*this, D);
ASTRecordLayouts[D] = NewEntry;
+ if (getLangOptions().DumpRecordLayouts) {
+ llvm::errs() << "\n*** Dumping AST Record Layout\n";
+ DumpRecordLayout(D, llvm::errs());
+ }
+
return *NewEntry;
}
@@ -1735,8 +1678,8 @@ QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl,
Decl->TypeForDecl = PrevDecl->TypeForDecl;
assert(isa<InjectedClassNameType>(Decl->TypeForDecl));
} else {
- Decl->TypeForDecl = new (*this, TypeAlignment)
- InjectedClassNameType(Decl, TST, TST->getCanonicalTypeInternal());
+ Decl->TypeForDecl =
+ new (*this, TypeAlignment) InjectedClassNameType(Decl, TST);
Types.push_back(Decl->TypeForDecl);
}
return QualType(Decl->TypeForDecl, 0);
@@ -1867,7 +1810,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgumentListInfo &Args,
- QualType Canon) {
+ QualType Canon,
+ bool IsCurrentInstantiation) {
unsigned NumArgs = Args.size();
llvm::SmallVector<TemplateArgument, 4> ArgVec;
@@ -1875,17 +1819,23 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
for (unsigned i = 0; i != NumArgs; ++i)
ArgVec.push_back(Args[i].getArgument());
- return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, Canon);
+ return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs,
+ Canon, IsCurrentInstantiation);
}
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgument *Args,
unsigned NumArgs,
- QualType Canon) {
+ QualType Canon,
+ bool IsCurrentInstantiation) {
if (!Canon.isNull())
Canon = getCanonicalType(Canon);
else {
+ assert(!IsCurrentInstantiation &&
+ "current-instantiation specializations should always "
+ "have a canonical type");
+
// Build the canonical template specialization type.
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
llvm::SmallVector<TemplateArgument, 4> CanonArgs;
@@ -1896,7 +1846,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
// Determine whether this canonical template specialization type already
// exists.
llvm::FoldingSetNodeID ID;
- TemplateSpecializationType::Profile(ID, CanonTemplate,
+ TemplateSpecializationType::Profile(ID, CanonTemplate, false,
CanonArgs.data(), NumArgs, *this);
void *InsertPos = 0;
@@ -1908,7 +1858,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
void *Mem = Allocate((sizeof(TemplateSpecializationType) +
sizeof(TemplateArgument) * NumArgs),
TypeAlignment);
- Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate,
+ Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate, false,
CanonArgs.data(), NumArgs,
Canon);
Types.push_back(Spec);
@@ -1928,7 +1878,9 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
sizeof(TemplateArgument) * NumArgs),
TypeAlignment);
TemplateSpecializationType *Spec
- = new (Mem) TemplateSpecializationType(*this, Template, Args, NumArgs,
+ = new (Mem) TemplateSpecializationType(*this, Template,
+ IsCurrentInstantiation,
+ Args, NumArgs,
Canon);
Types.push_back(Spec);
@@ -2108,10 +2060,10 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT,
if (!InterfaceT.isCanonical() ||
!areSortedAndUniqued(Protocols, NumProtocols)) {
if (!areSortedAndUniqued(Protocols, NumProtocols)) {
- llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(NumProtocols);
+ llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols,
+ Protocols + NumProtocols);
unsigned UniqueCount = NumProtocols;
- std::copy(Protocols, Protocols + NumProtocols, Sorted.begin());
SortAndUniqueProtocols(&Sorted[0], UniqueCount);
Canonical = getObjCObjectPointerType(getCanonicalType(InterfaceT),
@@ -2154,8 +2106,8 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
// Sort the protocol list alphabetically to canonicalize it.
QualType Canonical;
if (NumProtocols && !areSortedAndUniqued(Protocols, NumProtocols)) {
- llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(NumProtocols);
- std::copy(Protocols, Protocols + NumProtocols, Sorted.begin());
+ llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols,
+ Protocols + NumProtocols);
unsigned UniqueCount = NumProtocols;
SortAndUniqueProtocols(&Sorted[0], UniqueCount);
@@ -2634,14 +2586,9 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) {
QualType ASTContext::getBaseElementType(QualType QT) {
QualifierCollector Qs;
- while (true) {
- const Type *UT = Qs.strip(QT);
- if (const ArrayType *AT = getAsArrayType(QualType(UT,0))) {
- QT = AT->getElementType();
- } else {
- return Qs.apply(QT);
- }
- }
+ while (const ArrayType *AT = getAsArrayType(QualType(Qs.strip(QT), 0)))
+ QT = AT->getElementType();
+ return Qs.apply(QT);
}
QualType ASTContext::getBaseElementType(const ArrayType *AT) {
@@ -2886,6 +2833,7 @@ QualType ASTContext::getCFConstantStringType() {
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
/*Mutable=*/false);
+ Field->setAccess(AS_public);
CFConstantStringTypeDecl->addDecl(Field);
}
@@ -2901,6 +2849,46 @@ void ASTContext::setCFConstantStringType(QualType T) {
CFConstantStringTypeDecl = Rec->getDecl();
}
+// getNSConstantStringType - Return the type used for constant NSStrings.
+QualType ASTContext::getNSConstantStringType() {
+ if (!NSConstantStringTypeDecl) {
+ NSConstantStringTypeDecl =
+ CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get("__builtin_NSString"));
+ NSConstantStringTypeDecl->startDefinition();
+
+ QualType FieldTypes[3];
+
+ // const int *isa;
+ FieldTypes[0] = getPointerType(IntTy.withConst());
+ // const char *str;
+ FieldTypes[1] = getPointerType(CharTy.withConst());
+ // unsigned int length;
+ FieldTypes[2] = UnsignedIntTy;
+
+ // Create fields
+ for (unsigned i = 0; i < 3; ++i) {
+ FieldDecl *Field = FieldDecl::Create(*this, NSConstantStringTypeDecl,
+ SourceLocation(), 0,
+ FieldTypes[i], /*TInfo=*/0,
+ /*BitWidth=*/0,
+ /*Mutable=*/false);
+ Field->setAccess(AS_public);
+ NSConstantStringTypeDecl->addDecl(Field);
+ }
+
+ NSConstantStringTypeDecl->completeDefinition();
+ }
+
+ return getTagDeclType(NSConstantStringTypeDecl);
+}
+
+void ASTContext::setNSConstantStringType(QualType T) {
+ const RecordType *Rec = T->getAs<RecordType>();
+ assert(Rec && "Invalid NSConstantStringType");
+ NSConstantStringTypeDecl = Rec->getDecl();
+}
+
QualType ASTContext::getObjCFastEnumerationStateType() {
if (!ObjCFastEnumerationStateTypeDecl) {
ObjCFastEnumerationStateTypeDecl =
@@ -2923,6 +2911,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() {
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
/*Mutable=*/false);
+ Field->setAccess(AS_public);
ObjCFastEnumerationStateTypeDecl->addDecl(Field);
}
@@ -2960,6 +2949,7 @@ QualType ASTContext::getBlockDescriptorType() {
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
/*Mutable=*/false);
+ Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3008,6 +2998,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() {
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
/*Mutable=*/false);
+ Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3085,6 +3076,7 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) {
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0, /*Mutable=*/false);
+ Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3129,6 +3121,7 @@ QualType ASTContext::getBlockParmType(
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0, /*Mutable=*/false);
+ Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3149,6 +3142,7 @@ QualType ASTContext::getBlockParmType(
FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
Name, FieldType, /*TInfo=*/0,
/*BitWidth=*/0, /*Mutable=*/false);
+ Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3192,7 +3186,7 @@ std::string charUnitsToString(const CharUnits &CU) {
return llvm::itostr(CU.getQuantity());
}
-/// getObjCEncodingForBlockDecl - Return the encoded type for this method
+/// getObjCEncodingForBlockDecl - Return the encoded type for this block
/// declaration.
void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
std::string& S) {
@@ -3207,7 +3201,7 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
SourceLocation Loc;
CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy);
CharUnits ParmOffset = PtrSize;
- for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
+ for (BlockDecl::param_const_iterator PI = Decl->param_begin(),
E = Decl->param_end(); PI != E; ++PI) {
QualType PType = (*PI)->getType();
CharUnits sz = getObjCEncodingTypeSize(PType);
@@ -3258,7 +3252,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
// their size.
CharUnits ParmOffset = 2 * PtrSize;
for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
- E = Decl->param_end(); PI != E; ++PI) {
+ E = Decl->sel_param_end(); PI != E; ++PI) {
QualType PType = (*PI)->getType();
CharUnits sz = getObjCEncodingTypeSize(PType);
assert (sz.isPositive() &&
@@ -3272,7 +3266,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
// Argument types.
ParmOffset = 2 * PtrSize;
for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
- E = Decl->param_end(); PI != E; ++PI) {
+ E = Decl->sel_param_end(); PI != E; ++PI) {
ParmVarDecl *PVDecl = *PI;
QualType PType = PVDecl->getOriginalType();
if (const ArrayType *AT =
@@ -3494,13 +3488,18 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
return;
}
+ // encoding for pointer or r3eference types.
+ QualType PointeeTy;
if (const PointerType *PT = T->getAs<PointerType>()) {
if (PT->isObjCSelType()) {
S += ':';
return;
}
- QualType PointeeTy = PT->getPointeeType();
-
+ PointeeTy = PT->getPointeeType();
+ }
+ else if (const ReferenceType *RT = T->getAs<ReferenceType>())
+ PointeeTy = RT->getPointeeType();
+ if (!PointeeTy.isNull()) {
bool isReadOnly = false;
// For historical/compatibility reasons, the read-only qualifier of the
// pointee gets emitted _before_ the '^'. The read-only qualifier of
@@ -3524,12 +3523,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
// Another legacy compatibility encoding. Some ObjC qualifier and type
// combinations need to be rearranged.
// Rewrite "in const" from "nr" to "rn"
- const char * s = S.c_str();
- int len = S.length();
- if (len >= 2 && s[len-2] == 'n' && s[len-1] == 'r') {
- std::string replace = "rn";
- S.replace(S.end()-2, S.end(), replace);
- }
+ if (llvm::StringRef(S).endswith("nr"))
+ S.replace(S.end()-2, S.end(), "rn");
}
if (PointeeTy->isCharType()) {
@@ -3559,7 +3554,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
NULL);
return;
}
-
+
if (const ArrayType *AT =
// Ignore type qualifiers etc.
dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) {
@@ -4136,15 +4131,14 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
bool ASTContext::canAssignObjCInterfacesInBlockPointer(
const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT) {
- if (RHSOPT->isObjCBuiltinType() ||
- LHSOPT->isObjCIdType() || LHSOPT->isObjCQualifiedIdType())
+ if (RHSOPT->isObjCBuiltinType() || LHSOPT->isObjCIdType())
return true;
if (LHSOPT->isObjCBuiltinType()) {
return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType();
}
- if (RHSOPT->isObjCQualifiedIdType())
+ if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
QualType(RHSOPT,0),
false);
@@ -4190,7 +4184,8 @@ void getIntersectionOfProtocols(ASTContext &Context,
unsigned RHSNumProtocols = RHS->getNumProtocols();
if (RHSNumProtocols > 0) {
- ObjCProtocolDecl **RHSProtocols = (ObjCProtocolDecl **)RHS->qual_begin();
+ ObjCProtocolDecl **RHSProtocols =
+ const_cast<ObjCProtocolDecl **>(RHS->qual_begin());
for (unsigned i = 0; i < RHSNumProtocols; ++i)
if (InheritedProtocolSet.count(RHSProtocols[i]))
IntersectionOfProtocols.push_back(RHSProtocols[i]);
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 866b7f7..e4cd2a9 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -57,12 +57,6 @@ static bool ShouldAKA(ASTContext &Context, QualType QT,
continue;
}
- // ...or an injected class name...
- if (isa<InjectedClassNameType>(Ty)) {
- QT = cast<InjectedClassNameType>(Ty)->desugar();
- continue;
- }
-
// ...or a substituted template type parameter.
if (isa<SubstTemplateTypeParmType>(Ty)) {
QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 5dfb99f..ae09d79 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -612,8 +612,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const InjectedClassNameType *Inj1 = cast<InjectedClassNameType>(T1);
const InjectedClassNameType *Inj2 = cast<InjectedClassNameType>(T2);
if (!IsStructurallyEquivalent(Context,
- Inj1->getUnderlyingType(),
- Inj2->getUnderlyingType()))
+ Inj1->getInjectedSpecializationType(),
+ Inj2->getInjectedSpecializationType()))
return false;
break;
}
@@ -1438,7 +1438,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
for (DeclContext::lookup_result Lookup = DC->lookup(Name);
Lookup.first != Lookup.second;
++Lookup.first) {
- if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Namespace))
continue;
if (NamespaceDecl *FoundNS = dyn_cast<NamespaceDecl>(*Lookup.first)) {
@@ -1451,7 +1451,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary,
+ Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Namespace,
ConflictingDecls.data(),
ConflictingDecls.size());
}
@@ -1905,6 +1905,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
} else {
ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, Loc,
Name, T, TInfo, D->getStorageClass(),
+ D->getStorageClassAsWritten(),
D->isInlineSpecified(),
D->hasWrittenPrototype());
}
@@ -2125,7 +2126,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc,
Name.getAsIdentifierInfo(), T, TInfo,
- D->getStorageClass());
+ D->getStorageClass(),
+ D->getStorageClassAsWritten());
// Import the qualifier, if any.
if (D->getQualifier()) {
NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
@@ -2197,6 +2199,7 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC,
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getStorageClass(),
+ D->getStorageClassAsWritten(),
/*FIXME: Default argument*/ 0);
ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg());
return Importer.Imported(D, ToParm);
@@ -2312,7 +2315,8 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
ToMethod->addDecl(ToParams[I]);
}
ToMethod->setMethodParams(Importer.getToContext(),
- ToParams.data(), ToParams.size());
+ ToParams.data(), ToParams.size(),
+ ToParams.size());
ToMethod->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToMethod);
@@ -2881,8 +2885,11 @@ Expr *ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
if (!SubExpr)
return 0;
+ // FIXME: Initialize the base path.
+ assert(E->getBasePath().empty() && "FIXME: Must copy base path!");
+ CXXBaseSpecifierArray BasePath;
return new (Importer.getToContext()) ImplicitCastExpr(T, E->getCastKind(),
- SubExpr,
+ SubExpr, BasePath,
E->isLvalueCast());
}
@@ -2899,8 +2906,11 @@ Expr *ASTNodeImporter::VisitCStyleCastExpr(CStyleCastExpr *E) {
if (!TInfo && E->getTypeInfoAsWritten())
return 0;
+ // FIXME: Initialize the base path.
+ assert(E->getBasePath().empty() && "FIXME: Must copy base path!");
+ CXXBaseSpecifierArray BasePath;
return new (Importer.getToContext()) CStyleCastExpr(T, E->getCastKind(),
- SubExpr, TInfo,
+ SubExpr, BasePath, TInfo,
Importer.Import(E->getLParenLoc()),
Importer.Import(E->getRParenLoc()));
}
@@ -3086,7 +3096,7 @@ FileID ASTImporter::Import(FileID FromID) {
FromSLoc.getFile().getFileCharacteristic());
} else {
// FIXME: We want to re-use the existing MemoryBuffer!
- const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(getDiags());
+ const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(getDiags(), FromSM);
llvm::MemoryBuffer *ToBuf
= llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(),
FromBuf->getBufferIdentifier());
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index dc9fb59..ffe4967 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -25,7 +25,6 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/Support/ErrorHandling.h"
-#include <vector>
using namespace clang;
@@ -286,6 +285,28 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
}
Linkage NamedDecl::getLinkage() const {
+
+ // Objective-C: treat all Objective-C declarations as having external
+ // linkage.
+ switch (getKind()) {
+ default:
+ break;
+ case Decl::ObjCAtDefsField:
+ case Decl::ObjCCategory:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCClass:
+ case Decl::ObjCCompatibleAlias:
+ case Decl::ObjCForwardProtocol:
+ case Decl::ObjCImplementation:
+ case Decl::ObjCInterface:
+ case Decl::ObjCIvar:
+ case Decl::ObjCMethod:
+ case Decl::ObjCProperty:
+ case Decl::ObjCPropertyImpl:
+ case Decl::ObjCProtocol:
+ return ExternalLinkage;
+ }
+
// Handle linkage for namespace-scope names.
if (getDeclContext()->getLookupContext()->isFileContext())
if (Linkage L = getLinkageForNamespaceScopeDecl(this))
@@ -354,88 +375,79 @@ std::string NamedDecl::getQualifiedNameAsString() const {
}
std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
- // FIXME: Collect contexts, then accumulate names to avoid unnecessary
- // std::string thrashing.
- std::vector<std::string> Names;
- std::string QualName;
const DeclContext *Ctx = getDeclContext();
if (Ctx->isFunctionOrMethod())
return getNameAsString();
- while (Ctx) {
+ typedef llvm::SmallVector<const DeclContext *, 8> ContextsTy;
+ ContextsTy Contexts;
+
+ // Collect contexts.
+ while (Ctx && isa<NamedDecl>(Ctx)) {
+ Contexts.push_back(Ctx);
+ Ctx = Ctx->getParent();
+ };
+
+ std::string QualName;
+ llvm::raw_string_ostream OS(QualName);
+
+ for (ContextsTy::reverse_iterator I = Contexts.rbegin(), E = Contexts.rend();
+ I != E; ++I) {
if (const ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
+ = dyn_cast<ClassTemplateSpecializationDecl>(*I)) {
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
std::string TemplateArgsStr
= TemplateSpecializationType::PrintTemplateArgumentList(
TemplateArgs.getFlatArgumentList(),
TemplateArgs.flat_size(),
P);
- Names.push_back(Spec->getIdentifier()->getNameStart() + TemplateArgsStr);
- } else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(Ctx)) {
+ OS << Spec->getName() << TemplateArgsStr;
+ } else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(*I)) {
if (ND->isAnonymousNamespace())
- Names.push_back("<anonymous namespace>");
+ OS << "<anonymous namespace>";
else
- Names.push_back(ND->getNameAsString());
- } else if (const RecordDecl *RD = dyn_cast<RecordDecl>(Ctx)) {
- if (!RD->getIdentifier()) {
- std::string RecordString = "<anonymous ";
- RecordString += RD->getKindName();
- RecordString += ">";
- Names.push_back(RecordString);
- } else {
- Names.push_back(RD->getNameAsString());
- }
- } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Ctx)) {
- std::string Proto = FD->getNameAsString();
-
+ OS << ND;
+ } else if (const RecordDecl *RD = dyn_cast<RecordDecl>(*I)) {
+ if (!RD->getIdentifier())
+ OS << "<anonymous " << RD->getKindName() << '>';
+ else
+ OS << RD;
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
const FunctionProtoType *FT = 0;
if (FD->hasWrittenPrototype())
FT = dyn_cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>());
- Proto += "(";
+ OS << FD << '(';
if (FT) {
- llvm::raw_string_ostream POut(Proto);
unsigned NumParams = FD->getNumParams();
for (unsigned i = 0; i < NumParams; ++i) {
if (i)
- POut << ", ";
+ OS << ", ";
std::string Param;
FD->getParamDecl(i)->getType().getAsStringInternal(Param, P);
- POut << Param;
+ OS << Param;
}
if (FT->isVariadic()) {
if (NumParams > 0)
- POut << ", ";
- POut << "...";
+ OS << ", ";
+ OS << "...";
}
}
- Proto += ")";
-
- Names.push_back(Proto);
- } else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx))
- Names.push_back(ND->getNameAsString());
- else
- break;
-
- Ctx = Ctx->getParent();
+ OS << ')';
+ } else {
+ OS << cast<NamedDecl>(*I);
+ }
+ OS << "::";
}
- std::vector<std::string>::reverse_iterator
- I = Names.rbegin(),
- End = Names.rend();
-
- for (; I!=End; ++I)
- QualName += *I + "::";
-
if (getDeclName())
- QualName += getNameAsString();
+ OS << this;
else
- QualName += "<anonymous>";
+ OS << "<anonymous>";
- return QualName;
+ return OS.str();
}
bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
@@ -494,6 +506,24 @@ NamedDecl *NamedDecl::getUnderlyingDecl() {
}
}
+bool NamedDecl::isCXXInstanceMember() const {
+ assert(isCXXClassMember() &&
+ "checking whether non-member is instance member");
+
+ const NamedDecl *D = this;
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+ if (isa<FieldDecl>(D))
+ return true;
+ if (isa<CXXMethodDecl>(D))
+ return cast<CXXMethodDecl>(D)->isInstance();
+ if (isa<FunctionTemplateDecl>(D))
+ return cast<CXXMethodDecl>(cast<FunctionTemplateDecl>(D)
+ ->getTemplatedDecl())->isInstance();
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// DeclaratorDecl Implementation
//===----------------------------------------------------------------------===//
@@ -568,8 +598,8 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
- StorageClass S) {
- return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S);
+ StorageClass S, StorageClass SCAsWritten) {
+ return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S, SCAsWritten);
}
void VarDecl::Destroy(ASTContext& C) {
@@ -793,8 +823,10 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
- StorageClass S, Expr *DefArg) {
- return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg);
+ StorageClass S, StorageClass SCAsWritten,
+ Expr *DefArg) {
+ return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo,
+ S, SCAsWritten, DefArg);
}
Expr *ParmVarDecl::getDefaultArg() {
@@ -874,6 +906,12 @@ void FunctionDecl::getNameForDiagnostic(std::string &S,
}
+bool FunctionDecl::isVariadic() const {
+ if (const FunctionProtoType *FT = getType()->getAs<FunctionProtoType>())
+ return FT->isVariadic();
+ return false;
+}
+
Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
if (I->Body) {
@@ -1291,6 +1329,40 @@ FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
}
}
+void
+FunctionDecl::setDependentTemplateSpecialization(ASTContext &Context,
+ const UnresolvedSetImpl &Templates,
+ const TemplateArgumentListInfo &TemplateArgs) {
+ assert(TemplateOrSpecialization.isNull());
+ size_t Size = sizeof(DependentFunctionTemplateSpecializationInfo);
+ Size += Templates.size() * sizeof(FunctionTemplateDecl*);
+ Size += TemplateArgs.size() * sizeof(TemplateArgumentLoc);
+ void *Buffer = Context.Allocate(Size);
+ DependentFunctionTemplateSpecializationInfo *Info =
+ new (Buffer) DependentFunctionTemplateSpecializationInfo(Templates,
+ TemplateArgs);
+ TemplateOrSpecialization = Info;
+}
+
+DependentFunctionTemplateSpecializationInfo::
+DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts,
+ const TemplateArgumentListInfo &TArgs)
+ : AngleLocs(TArgs.getLAngleLoc(), TArgs.getRAngleLoc()) {
+
+ d.NumTemplates = Ts.size();
+ d.NumArgs = TArgs.size();
+
+ FunctionTemplateDecl **TsArray =
+ const_cast<FunctionTemplateDecl**>(getTemplates());
+ for (unsigned I = 0, E = Ts.size(); I != E; ++I)
+ TsArray[I] = cast<FunctionTemplateDecl>(Ts[I]->getUnderlyingDecl());
+
+ TemplateArgumentLoc *ArgsArray =
+ const_cast<TemplateArgumentLoc*>(getTemplateArgs());
+ for (unsigned I = 0, E = TArgs.size(); I != E; ++I)
+ new (&ArgsArray[I]) TemplateArgumentLoc(TArgs[I]);
+}
+
TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const {
// For a function template specialization, query the specialization
// information object.
@@ -1407,6 +1479,10 @@ void TagDecl::startDefinition() {
if (TagType *TagT = const_cast<TagType *>(TypeForDecl->getAs<TagType>())) {
TagT->decl.setPointer(this);
TagT->decl.setInt(1);
+ } else if (InjectedClassNameType *Injected
+ = const_cast<InjectedClassNameType *>(
+ TypeForDecl->getAs<InjectedClassNameType>())) {
+ Injected->Decl = cast<CXXRecordDecl>(this);
}
if (isa<CXXRecordDecl>(this)) {
@@ -1428,6 +1504,11 @@ void TagDecl::completeDefinition() {
assert(TagT->decl.getPointer() == this &&
"Attempt to redefine a tag definition?");
TagT->decl.setInt(0);
+ } else if (InjectedClassNameType *Injected
+ = const_cast<InjectedClassNameType *>(
+ TypeForDecl->getAs<InjectedClassNameType>())) {
+ assert(Injected->Decl == this &&
+ "Attempt to redefine a class template definition?");
}
}
@@ -1606,10 +1687,10 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
DeclarationName N, QualType T,
TypeSourceInfo *TInfo,
- StorageClass S, bool isInline,
- bool hasWrittenPrototype) {
- FunctionDecl *New
- = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline);
+ StorageClass S, StorageClass SCAsWritten,
+ bool isInline, bool hasWrittenPrototype) {
+ FunctionDecl *New = new (C) FunctionDecl(Function, DC, L, N, T, TInfo,
+ S, SCAsWritten, isInline);
New->HasWrittenPrototype = hasWrittenPrototype;
return New;
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index c693e15..b5aec0c 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -231,24 +231,28 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case CXXConstructor:
case CXXDestructor:
case CXXConversion:
- case Typedef:
case EnumConstant:
case Var:
case ImplicitParam:
case ParmVar:
case NonTypeTemplateParm:
case ObjCMethod:
- case ObjCContainer:
- case ObjCInterface:
case ObjCProperty:
- case ObjCCompatibleAlias:
return IDNS_Ordinary;
+ case ObjCCompatibleAlias:
+ case ObjCInterface:
+ return IDNS_Ordinary | IDNS_Type;
+
+ case Typedef:
+ case UnresolvedUsingTypename:
+ case TemplateTypeParm:
+ return IDNS_Ordinary | IDNS_Type;
+
case UsingShadow:
return 0; // we'll actually overwrite this later
case UnresolvedUsingValue:
- case UnresolvedUsingTypename:
return IDNS_Ordinary | IDNS_Using;
case Using:
@@ -257,13 +261,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCProtocol:
return IDNS_ObjCProtocol;
- case ObjCImplementation:
- return IDNS_ObjCImplementation;
-
- case ObjCCategory:
- case ObjCCategoryImpl:
- return IDNS_ObjCCategoryName;
-
case Field:
case ObjCAtDefsField:
case ObjCIvar:
@@ -272,16 +269,18 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Record:
case CXXRecord:
case Enum:
- case TemplateTypeParm:
- return IDNS_Tag;
+ return IDNS_Tag | IDNS_Type;
case Namespace:
- case Template:
+ case NamespaceAlias:
+ return IDNS_Namespace;
+
case FunctionTemplate:
+ return IDNS_Ordinary;
+
case ClassTemplate:
case TemplateTemplateParm:
- case NamespaceAlias:
- return IDNS_Tag | IDNS_Ordinary;
+ return IDNS_Ordinary | IDNS_Tag | IDNS_Type;
// Never have names.
case Friend:
@@ -295,10 +294,13 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Block:
case TranslationUnit:
- // Aren't looked up?
case UsingDirective:
case ClassTemplateSpecialization:
case ClassTemplatePartialSpecialization:
+ case ObjCImplementation:
+ case ObjCCategory:
+ case ObjCCategoryImpl:
+ // Never looked up by name.
return 0;
}
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 94ed85c..68f4a82 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -587,9 +587,9 @@ CXXMethodDecl *
CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
QualType T, TypeSourceInfo *TInfo,
- bool isStatic, bool isInline) {
+ bool isStatic, StorageClass SCAsWritten, bool isInline) {
return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, TInfo,
- isStatic, isInline);
+ isStatic, SCAsWritten, isInline);
}
bool CXXMethodDecl::isUsualDeallocationFunction() const {
@@ -633,6 +633,27 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const {
return true;
}
+bool CXXMethodDecl::isCopyAssignmentOperator() const {
+ // C++0x [class.copy]p19:
+ // A user-declared copy assignment operator X::operator= is a non-static
+ // non-template member function of class X with exactly one parameter of
+ // type X, X&, const X&, volatile X& or const volatile X&.
+ if (/*operator=*/getOverloadedOperator() != OO_Equal ||
+ /*non-static*/ isStatic() ||
+ /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() ||
+ /*exactly one parameter*/getNumParams() != 1)
+ return false;
+
+ QualType ParamType = getParamDecl(0)->getType();
+ if (const LValueReferenceType *Ref = ParamType->getAs<LValueReferenceType>())
+ ParamType = Ref->getPointeeType();
+
+ ASTContext &Context = getASTContext();
+ QualType ClassType
+ = Context.getCanonicalType(Context.getTypeDeclType(getParent()));
+ return Context.hasSameUnqualifiedType(ClassType, ParamType);
+}
+
void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
assert(MD->isCanonicalDecl() && "Method is not canonical!");
assert(!MD->getParent()->isDependentContext() &&
@@ -659,15 +680,6 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const {
assert(isInstance() && "No 'this' for static methods!");
QualType ClassTy = C.getTypeDeclType(getParent());
-
- // Aesthetically we prefer not to synthesize a type as the
- // InjectedClassNameType of a template pattern: injected class names
- // are printed without template arguments, which might
- // surprise/confuse/distract our poor users if they didn't
- // explicitly write one.
- if (isa<InjectedClassNameType>(ClassTy))
- ClassTy = cast<InjectedClassNameType>(ClassTy)->getUnderlyingType();
-
ClassTy = C.getQualifiedType(ClassTy,
Qualifiers::fromCVRMask(getTypeQualifiers()));
return C.getPointerType(ClassTy);
@@ -686,9 +698,9 @@ bool CXXMethodDecl::hasInlineBody() const {
CXXBaseOrMemberInitializer::
CXXBaseOrMemberInitializer(ASTContext &Context,
- TypeSourceInfo *TInfo,
+ TypeSourceInfo *TInfo, bool IsVirtual,
SourceLocation L, Expr *Init, SourceLocation R)
- : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0),
+ : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), IsVirtual(IsVirtual),
LParenLoc(L), RParenLoc(R)
{
}
@@ -745,11 +757,12 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
QualType T, TypeSourceInfo *TInfo,
bool isExplicit,
- bool isInline, bool isImplicitlyDeclared) {
+ bool isInline,
+ bool isImplicitlyDeclared) {
assert(N.getNameKind() == DeclarationName::CXXConstructorName &&
"Name must refer to a constructor");
- return new (C) CXXConstructorDecl(RD, L, N, T, TInfo, isExplicit, isInline,
- isImplicitlyDeclared);
+ return new (C) CXXConstructorDecl(RD, L, N, T, TInfo, isExplicit,
+ isInline, isImplicitlyDeclared);
}
bool CXXConstructorDecl::isDefaultConstructor() const {
@@ -848,8 +861,7 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
bool isImplicitlyDeclared) {
assert(N.getNameKind() == DeclarationName::CXXDestructorName &&
"Name must refer to a destructor");
- return new (C) CXXDestructorDecl(RD, L, N, T, isInline,
- isImplicitlyDeclared);
+ return new (C) CXXDestructorDecl(RD, L, N, T, isInline, isImplicitlyDeclared);
}
void
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 821e38b..dc4aacd 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -330,11 +330,13 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C,
bool isInstance,
bool isVariadic,
bool isSynthesized,
- ImplementationControl impControl) {
+ ImplementationControl impControl,
+ unsigned numSelectorArgs) {
return new (C) ObjCMethodDecl(beginLoc, endLoc,
SelInfo, T, ResultTInfo, contextDecl,
isInstance,
- isVariadic, isSynthesized, impControl);
+ isVariadic, isSynthesized, impControl,
+ numSelectorArgs);
}
void ObjCMethodDecl::Destroy(ASTContext &C) {
@@ -841,6 +843,12 @@ FindPropertyImplDecl(IdentifierInfo *Id) const {
return 0;
}
+llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
+ const ObjCCategoryImplDecl *CID) {
+ OS << CID->getName();
+ return OS;
+}
+
//===----------------------------------------------------------------------===//
// ObjCImplementationDecl
//===----------------------------------------------------------------------===//
@@ -853,6 +861,12 @@ ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) ObjCImplementationDecl(DC, L, ClassInterface, SuperDecl);
}
+llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
+ const ObjCImplementationDecl *ID) {
+ OS << ID->getName();
+ return OS;
+}
+
//===----------------------------------------------------------------------===//
// ObjCCompatibleAliasDecl
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index a625865..53949247 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -301,17 +301,15 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
}
void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
- Out << "enum " << D->getNameAsString() << " {\n";
+ Out << "enum " << D << " {\n";
VisitDeclContext(D);
Indent() << "}";
}
void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
Out << D->getKindName();
- if (D->getIdentifier()) {
- Out << " ";
- Out << D->getNameAsString();
- }
+ if (D->getIdentifier())
+ Out << ' ' << D;
if (D->isDefinition()) {
Out << " {\n";
@@ -321,7 +319,7 @@ void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
}
void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
- Out << D->getNameAsString();
+ Out << D;
if (Expr *Init = D->getInitExpr()) {
Out << " = ";
Init->printPretty(Out, Context, 0, Policy, Indentation);
@@ -406,7 +404,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Out << ", ";
if (BMInitializer->isMemberInitializer()) {
FieldDecl *FD = BMInitializer->getMember();
- Out << FD->getNameAsString();
+ Out << FD;
} else {
Out << QualType(BMInitializer->getBaseClass(), 0).getAsString();
}
@@ -537,7 +535,7 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
// C++ declarations
//----------------------------------------------------------------------------
void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) {
- Out << "namespace " << D->getNameAsString() << " {\n";
+ Out << "namespace " << D << " {\n";
VisitDeclContext(D);
Indent() << "}";
}
@@ -546,22 +544,20 @@ void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
Out << "using namespace ";
if (D->getQualifier())
D->getQualifier()->print(Out, Policy);
- Out << D->getNominatedNamespaceAsWritten()->getNameAsString();
+ Out << D->getNominatedNamespaceAsWritten();
}
void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
- Out << "namespace " << D->getNameAsString() << " = ";
+ Out << "namespace " << D << " = ";
if (D->getQualifier())
D->getQualifier()->print(Out, Policy);
- Out << D->getAliasedNamespace()->getNameAsString();
+ Out << D->getAliasedNamespace();
}
void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
Out << D->getKindName();
- if (D->getIdentifier()) {
- Out << " ";
- Out << D->getNameAsString();
- }
+ if (D->getIdentifier())
+ Out << ' ' << D;
if (D->isDefinition()) {
// Print the base classes
@@ -669,7 +665,7 @@ void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) {
for (ObjCClassDecl::iterator I = D->begin(), E = D->end();
I != E; ++I) {
if (I != D->begin()) Out << ", ";
- Out << I->getInterface()->getNameAsString();
+ Out << I->getInterface();
}
}
@@ -688,8 +684,7 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
// FIXME: selector is missing here!
pos = name.find_first_of(":", lastPos);
Out << " " << name.substr(lastPos, pos - lastPos);
- Out << ":(" << (*PI)->getType().getAsString(Policy) << ")"
- << (*PI)->getNameAsString();
+ Out << ":(" << (*PI)->getType().getAsString(Policy) << ')' << *PI;
lastPos = pos + 1;
}
@@ -711,7 +706,7 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
ObjCInterfaceDecl *SID = OID->getSuperClass();
if (SID)
- Out << "@implementation " << I << " : " << SID->getNameAsString();
+ Out << "@implementation " << I << " : " << SID;
else
Out << "@implementation " << I;
Out << "\n";
@@ -724,7 +719,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
ObjCInterfaceDecl *SID = OID->getSuperClass();
if (SID)
- Out << "@interface " << I << " : " << SID->getNameAsString();
+ Out << "@interface " << I << " : " << SID;
else
Out << "@interface " << I;
@@ -733,7 +728,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
if (!Protocols.empty()) {
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end(); I != E; ++I)
- Out << (I == Protocols.begin() ? '<' : ',') << (*I)->getNameAsString();
+ Out << (I == Protocols.begin() ? '<' : ',') << *I;
}
if (!Protocols.empty())
@@ -744,8 +739,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
Indentation += Policy.Indentation;
for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(),
E = OID->ivar_end(); I != E; ++I) {
- Indent() << (*I)->getType().getAsString(Policy)
- << ' ' << (*I)->getNameAsString() << ";\n";
+ Indent() << (*I)->getType().getAsString(Policy) << ' ' << *I << ";\n";
}
Indentation -= Policy.Indentation;
Out << "}\n";
@@ -762,20 +756,18 @@ void DeclPrinter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
E = D->protocol_end();
I != E; ++I) {
if (I != D->protocol_begin()) Out << ", ";
- Out << (*I)->getNameAsString();
+ Out << *I;
}
}
void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
- Out << "@protocol " << PID->getNameAsString() << '\n';
+ Out << "@protocol " << PID << '\n';
VisitDeclContext(PID, false);
Out << "@end";
}
void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
- Out << "@implementation "
- << PID->getClassInterface()->getNameAsString()
- << '(' << PID->getNameAsString() << ")\n";
+ Out << "@implementation " << PID->getClassInterface() << '(' << PID << ")\n";
VisitDeclContext(PID, false);
Out << "@end";
@@ -783,9 +775,7 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
}
void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
- Out << "@interface "
- << PID->getClassInterface()->getNameAsString()
- << '(' << PID->getNameAsString() << ")\n";
+ Out << "@interface " << PID->getClassInterface() << '(' << PID << ")\n";
VisitDeclContext(PID, false);
Out << "@end";
@@ -793,8 +783,8 @@ void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
}
void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) {
- Out << "@compatibility_alias " << AID->getNameAsString()
- << ' ' << AID->getClassInterface()->getNameAsString() << ";\n";
+ Out << "@compatibility_alias " << AID
+ << ' ' << AID->getClassInterface() << ";\n";
}
/// PrintObjCPropertyDecl - print a property declaration.
@@ -854,8 +844,7 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
}
Out << " )";
}
- Out << ' ' << PDecl->getType().getAsString(Policy)
- << ' ' << PDecl->getNameAsString();
+ Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << PDecl;
}
void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
@@ -863,28 +852,28 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
Out << "@synthesize ";
else
Out << "@dynamic ";
- Out << PID->getPropertyDecl()->getNameAsString();
+ Out << PID->getPropertyDecl();
if (PID->getPropertyIvarDecl())
- Out << "=" << PID->getPropertyIvarDecl()->getNameAsString();
+ Out << '=' << PID->getPropertyIvarDecl();
}
void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
Out << "using ";
D->getTargetNestedNameDecl()->print(Out, Policy);
- Out << D->getNameAsString();
+ Out << D;
}
void
DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
Out << "using typename ";
D->getTargetNestedNameSpecifier()->print(Out, Policy);
- Out << D->getDeclName().getAsString();
+ Out << D->getDeclName();
}
void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
Out << "using ";
D->getTargetNestedNameSpecifier()->print(Out, Policy);
- Out << D->getDeclName().getAsString();
+ Out << D->getDeclName();
}
void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) {
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index b449398..c498dea 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -178,6 +178,20 @@ void ClassTemplateDecl::Destroy(ASTContext& C) {
C.Deallocate((void*)this);
}
+void ClassTemplateDecl::getPartialSpecializations(
+ llvm::SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS) {
+ llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &PartialSpecs
+ = CommonPtr->PartialSpecializations;
+ PS.clear();
+ PS.resize(PartialSpecs.size());
+ for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+ P = PartialSpecs.begin(), PEnd = PartialSpecs.end();
+ P != PEnd; ++P) {
+ assert(!PS[P->getSequenceNumber()]);
+ PS[P->getSequenceNumber()] = &*P;
+ }
+}
+
ClassTemplatePartialSpecializationDecl *
ClassTemplateDecl::findPartialSpecialization(QualType T) {
ASTContext &Context = getASTContext();
@@ -186,7 +200,7 @@ ClassTemplateDecl::findPartialSpecialization(QualType T) {
for (partial_spec_iterator P = getPartialSpecializations().begin(),
PEnd = getPartialSpecializations().end();
P != PEnd; ++P) {
- if (Context.hasSameType(Context.getTypeDeclType(&*P), T))
+ if (Context.hasSameType(P->getInjectedSpecializationType(), T))
return &*P;
}
@@ -456,7 +470,8 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
TemplateArgumentListBuilder &Builder,
const TemplateArgumentListInfo &ArgInfos,
QualType CanonInjectedType,
- ClassTemplatePartialSpecializationDecl *PrevDecl) {
+ ClassTemplatePartialSpecializationDecl *PrevDecl,
+ unsigned SequenceNumber) {
unsigned N = ArgInfos.size();
TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N];
for (unsigned I = 0; I != N; ++I)
@@ -468,7 +483,8 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
SpecializedTemplate,
Builder,
ClonedArgs, N,
- PrevDecl);
+ PrevDecl,
+ SequenceNumber);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
Context.getInjectedClassNameType(Result, CanonInjectedType);
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 19b58bc..4f85fca 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -18,7 +18,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
-#include <cstdio>
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace clang {
@@ -202,32 +202,42 @@ bool DeclarationName::isDependentName() const {
}
std::string DeclarationName::getAsString() const {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ printName(OS);
+ return OS.str();
+}
+
+void DeclarationName::printName(llvm::raw_ostream &OS) const {
switch (getNameKind()) {
case Identifier:
if (const IdentifierInfo *II = getAsIdentifierInfo())
- return II->getName();
- return "";
+ OS << II->getName();
+ return;
case ObjCZeroArgSelector:
case ObjCOneArgSelector:
case ObjCMultiArgSelector:
- return getObjCSelector().getAsString();
+ OS << getObjCSelector().getAsString();
+ return;
case CXXConstructorName: {
QualType ClassType = getCXXNameType();
if (const RecordType *ClassRec = ClassType->getAs<RecordType>())
- return ClassRec->getDecl()->getNameAsString();
- return ClassType.getAsString();
+ OS << ClassRec->getDecl();
+ else
+ OS << ClassType.getAsString();
+ return;
}
case CXXDestructorName: {
- std::string Result = "~";
+ OS << '~';
QualType Type = getCXXNameType();
if (const RecordType *Rec = Type->getAs<RecordType>())
- Result += Rec->getDecl()->getNameAsString();
+ OS << Rec->getDecl();
else
- Result += Type.getAsString();
- return Result;
+ OS << Type.getAsString();
+ return;
}
case CXXOperatorName: {
@@ -240,32 +250,32 @@ std::string DeclarationName::getAsString() const {
const char *OpName = OperatorNames[getCXXOverloadedOperator()];
assert(OpName && "not an overloaded operator");
- std::string Result = "operator";
+ OS << "operator";
if (OpName[0] >= 'a' && OpName[0] <= 'z')
- Result += ' ';
- Result += OpName;
- return Result;
+ OS << ' ';
+ OS << OpName;
+ return;
}
- case CXXLiteralOperatorName: {
- return "operator \"\" " + std::string(getCXXLiteralIdentifier()->getName());
- }
+ case CXXLiteralOperatorName:
+ OS << "operator \"\" " << getCXXLiteralIdentifier()->getName();
+ return;
case CXXConversionFunctionName: {
- std::string Result = "operator ";
+ OS << "operator ";
QualType Type = getCXXNameType();
if (const RecordType *Rec = Type->getAs<RecordType>())
- Result += Rec->getDecl()->getNameAsString();
+ OS << Rec->getDecl();
else
- Result += Type.getAsString();
- return Result;
+ OS << Type.getAsString();
+ return;
}
case CXXUsingDirective:
- return "<using-directive>";
+ OS << "<using-directive>";
+ return;
}
assert(false && "Unexpected declaration name kind");
- return "";
}
QualType DeclarationName::getCXXNameType() const {
@@ -369,7 +379,8 @@ DeclarationName DeclarationName::getUsingDirectiveName() {
}
void DeclarationName::dump() const {
- fprintf(stderr, "%s\n", getAsString().c_str());
+ printName(llvm::errs());
+ llvm::errs() << '\n';
}
DeclarationNameTable::DeclarationNameTable() {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index ae4bc8c..00662a5 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -27,6 +27,65 @@
#include <algorithm>
using namespace clang;
+/// isKnownToHaveBooleanValue - Return true if this is an integer expression
+/// that is known to return 0 or 1. This happens for _Bool/bool expressions
+/// but also int expressions which are produced by things like comparisons in
+/// C.
+bool Expr::isKnownToHaveBooleanValue() const {
+ // If this value has _Bool type, it is obvious 0/1.
+ if (getType()->isBooleanType()) return true;
+ // If this is a non-scalar-integer type, we don't care enough to try.
+ if (!getType()->isIntegralType()) return false;
+
+ if (const ParenExpr *PE = dyn_cast<ParenExpr>(this))
+ return PE->getSubExpr()->isKnownToHaveBooleanValue();
+
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(this)) {
+ switch (UO->getOpcode()) {
+ case UnaryOperator::Plus:
+ case UnaryOperator::Extension:
+ return UO->getSubExpr()->isKnownToHaveBooleanValue();
+ default:
+ return false;
+ }
+ }
+
+ if (const CastExpr *CE = dyn_cast<CastExpr>(this))
+ return CE->getSubExpr()->isKnownToHaveBooleanValue();
+
+ if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(this)) {
+ switch (BO->getOpcode()) {
+ default: return false;
+ case BinaryOperator::LT: // Relational operators.
+ case BinaryOperator::GT:
+ case BinaryOperator::LE:
+ case BinaryOperator::GE:
+ case BinaryOperator::EQ: // Equality operators.
+ case BinaryOperator::NE:
+ case BinaryOperator::LAnd: // AND operator.
+ case BinaryOperator::LOr: // Logical OR operator.
+ return true;
+
+ case BinaryOperator::And: // Bitwise AND operator.
+ case BinaryOperator::Xor: // Bitwise XOR operator.
+ case BinaryOperator::Or: // Bitwise OR operator.
+ // Handle things like (x==2)|(y==12).
+ return BO->getLHS()->isKnownToHaveBooleanValue() &&
+ BO->getRHS()->isKnownToHaveBooleanValue();
+
+ case BinaryOperator::Comma:
+ case BinaryOperator::Assign:
+ return BO->getRHS()->isKnownToHaveBooleanValue();
+ }
+ }
+
+ if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(this))
+ return CO->getTrueExpr()->isKnownToHaveBooleanValue() &&
+ CO->getFalseExpr()->isKnownToHaveBooleanValue();
+
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Primary Expressions.
//===----------------------------------------------------------------------===//
@@ -231,14 +290,12 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
// For incorrect code, there might not be an ObjCInterfaceDecl. Do
// a null check to avoid a crash.
if (const ObjCInterfaceDecl *ID = MD->getClassInterface())
- Out << ID->getNameAsString();
+ Out << ID;
if (const ObjCCategoryImplDecl *CID =
- dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext())) {
- Out << '(';
- Out << CID->getNameAsString();
- Out << ')';
- }
+ dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext()))
+ Out << '(' << CID << ')';
+
Out << ' ';
Out << MD->getSelector().getAsString();
Out << ']';
@@ -492,17 +549,70 @@ QualType CallExpr::getCallReturnType() const {
return FnType->getResultType();
}
+OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type,
+ SourceLocation OperatorLoc,
+ TypeSourceInfo *tsi,
+ OffsetOfNode* compsPtr, unsigned numComps,
+ Expr** exprsPtr, unsigned numExprs,
+ SourceLocation RParenLoc) {
+ void *Mem = C.Allocate(sizeof(OffsetOfExpr) +
+ sizeof(OffsetOfNode) * numComps +
+ sizeof(Expr*) * numExprs);
+
+ return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, compsPtr, numComps,
+ exprsPtr, numExprs, RParenLoc);
+}
+
+OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C,
+ unsigned numComps, unsigned numExprs) {
+ void *Mem = C.Allocate(sizeof(OffsetOfExpr) +
+ sizeof(OffsetOfNode) * numComps +
+ sizeof(Expr*) * numExprs);
+ return new (Mem) OffsetOfExpr(numComps, numExprs);
+}
+
+OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type,
+ SourceLocation OperatorLoc, TypeSourceInfo *tsi,
+ OffsetOfNode* compsPtr, unsigned numComps,
+ Expr** exprsPtr, unsigned numExprs,
+ SourceLocation RParenLoc)
+ : Expr(OffsetOfExprClass, type, /*TypeDependent=*/false,
+ /*ValueDependent=*/tsi->getType()->isDependentType() ||
+ hasAnyTypeDependentArguments(exprsPtr, numExprs) ||
+ hasAnyValueDependentArguments(exprsPtr, numExprs)),
+ OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi),
+ NumComps(numComps), NumExprs(numExprs)
+{
+ for(unsigned i = 0; i < numComps; ++i) {
+ setComponent(i, compsPtr[i]);
+ }
+
+ for(unsigned i = 0; i < numExprs; ++i) {
+ setIndexExpr(i, exprsPtr[i]);
+ }
+}
+
+IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const {
+ assert(getKind() == Field || getKind() == Identifier);
+ if (getKind() == Field)
+ return getField()->getIdentifier();
+
+ return reinterpret_cast<IdentifierInfo *> (Data & ~(uintptr_t)Mask);
+}
+
MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifier *qual,
SourceRange qualrange,
ValueDecl *memberdecl,
- NamedDecl *founddecl,
+ DeclAccessPair founddecl,
SourceLocation l,
const TemplateArgumentListInfo *targs,
QualType ty) {
std::size_t Size = sizeof(MemberExpr);
- bool hasQualOrFound = (qual != 0 || founddecl != memberdecl);
+ bool hasQualOrFound = (qual != 0 ||
+ founddecl.getDecl() != memberdecl ||
+ founddecl.getAccess() != memberdecl->getAccess());
if (hasQualOrFound)
Size += sizeof(MemberNameQualifier);
@@ -593,6 +703,12 @@ const char *CastExpr::getCastKindName() const {
return 0;
}
+void CastExpr::DoDestroy(ASTContext &C)
+{
+ BasePath.Destroy();
+ Expr::DoDestroy(C);
+}
+
Expr *CastExpr::getSubExprAsWritten() {
Expr *SubExpr = 0;
CastExpr *E = this;
@@ -720,10 +836,11 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
return OverOps[Opc];
}
-InitListExpr::InitListExpr(SourceLocation lbraceloc,
+InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
Expr **initExprs, unsigned numInits,
SourceLocation rbraceloc)
: Expr(InitListExprClass, QualType(), false, false),
+ InitExprs(C, numInits),
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0),
UnionFieldInit(0), HadArrayRangeDesignator(false)
{
@@ -734,24 +851,24 @@ InitListExpr::InitListExpr(SourceLocation lbraceloc,
ValueDependent = true;
}
- InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits);
+ InitExprs.insert(C, InitExprs.end(), initExprs, initExprs+numInits);
}
-void InitListExpr::reserveInits(unsigned NumInits) {
+void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) {
if (NumInits > InitExprs.size())
- InitExprs.reserve(NumInits);
+ InitExprs.reserve(C, NumInits);
}
-void InitListExpr::resizeInits(ASTContext &Context, unsigned NumInits) {
+void InitListExpr::resizeInits(ASTContext &C, unsigned NumInits) {
for (unsigned Idx = NumInits, LastIdx = InitExprs.size();
Idx < LastIdx; ++Idx)
- InitExprs[Idx]->Destroy(Context);
- InitExprs.resize(NumInits, 0);
+ InitExprs[Idx]->Destroy(C);
+ InitExprs.resize(C, NumInits, 0);
}
-Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) {
+Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) {
if (Init >= InitExprs.size()) {
- InitExprs.insert(InitExprs.end(), Init - InitExprs.size() + 1, 0);
+ InitExprs.insert(C, InitExprs.end(), Init - InitExprs.size() + 1, 0);
InitExprs.back() = expr;
return 0;
}
@@ -835,19 +952,22 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
}
case BinaryOperatorClass: {
const BinaryOperator *BO = cast<BinaryOperator>(this);
- // Consider comma to have side effects if the LHS or RHS does.
- if (BO->getOpcode() == BinaryOperator::Comma) {
- // ((foo = <blah>), 0) is an idiom for hiding the result (and
- // lvalue-ness) of an assignment written in a macro.
- if (IntegerLiteral *IE =
- dyn_cast<IntegerLiteral>(BO->getRHS()->IgnoreParens()))
- if (IE->getValue() == 0)
- return false;
-
- return (BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) ||
- BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
+ switch (BO->getOpcode()) {
+ default:
+ break;
+ // Consider ',', '||', '&&' to have side effects if the LHS or RHS does.
+ case BinaryOperator::Comma:
+ // ((foo = <blah>), 0) is an idiom for hiding the result (and
+ // lvalue-ness) of an assignment written in a macro.
+ if (IntegerLiteral *IE =
+ dyn_cast<IntegerLiteral>(BO->getRHS()->IgnoreParens()))
+ if (IE->getValue() == 0)
+ return false;
+ case BinaryOperator::LAnd:
+ case BinaryOperator::LOr:
+ return (BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) ||
+ BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
}
-
if (BO->isAssignmentOp())
return false;
Loc = BO->getOperatorLoc();
@@ -1219,11 +1339,13 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
return LV_Valid;
case ObjCPropertyRefExprClass: // FIXME: check if read-only property.
return LV_Valid;
- case ObjCImplicitSetterGetterRefExprClass: // FIXME: check if read-only property.
+ case ObjCImplicitSetterGetterRefExprClass:
+ // FIXME: check if read-only property.
return LV_Valid;
case PredefinedExprClass:
return LV_Valid;
case UnresolvedLookupExprClass:
+ case UnresolvedMemberExprClass:
return LV_Valid;
case CXXDefaultArgExprClass:
return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue(Ctx);
@@ -1821,7 +1943,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case UnaryOperator::AddrOf:
case UnaryOperator::Deref:
return ICEDiag(2, E->getLocStart());
-
case UnaryOperator::Extension:
case UnaryOperator::LNot:
case UnaryOperator::Plus:
@@ -1831,6 +1952,12 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case UnaryOperator::Imag:
return CheckICE(Exp->getSubExpr(), Ctx);
case UnaryOperator::OffsetOf:
+ break;
+ }
+
+ // OffsetOf falls through here.
+ }
+ case Expr::OffsetOfExprClass: {
// Note that per C99, offsetof must be an ICE. And AFAIK, using
// Evaluate matches the proposed gcc behavior for cases like
// "offsetof(struct s{int x[4];}, x[!.0])". This doesn't affect
@@ -1838,7 +1965,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// array subscripts that aren't ICEs, and if the array subscripts
// are ICEs, the value of the offsetof must be an integer constant.
return CheckEvalInICE(E, Ctx);
- }
}
case Expr::SizeOfAlignOfExprClass: {
const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E);
@@ -1936,7 +2062,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::ImplicitCastExprClass:
case Expr::CStyleCastExprClass:
case Expr::CXXFunctionalCastExprClass:
- case Expr::CXXNamedCastExprClass:
case Expr::CXXStaticCastExprClass:
case Expr::CXXReinterpretCastExprClass:
case Expr::CXXConstCastExprClass: {
@@ -1953,7 +2078,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// then only the true side is actually considered in an integer constant
// expression, and it is fully evaluated. This is an important GNU
// extension. See GCC PR38377 for discussion.
- if (const CallExpr *CallCE = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
+ if (const CallExpr *CallCE
+ = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) {
Expr::EvalResult EVResult;
if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects ||
@@ -2176,101 +2302,156 @@ void ExtVectorElementExpr::getEncodedElementAccess(
}
}
-// constructor for instance messages.
-ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, Expr *receiver,
- Selector selInfo,
- QualType retType, ObjCMethodDecl *mproto,
- SourceLocation LBrac, SourceLocation RBrac,
- Expr **ArgExprs, unsigned nargs)
- : Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo),
- MethodProto(mproto) {
- NumArgs = nargs;
- SubExprs = new (C) Stmt*[NumArgs+1];
- SubExprs[RECEIVER] = receiver;
- if (NumArgs) {
- for (unsigned i = 0; i != NumArgs; ++i)
- SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]);
- }
- LBracloc = LBrac;
- RBracloc = RBrac;
-}
-
-// constructor for class messages.
-// FIXME: clsName should be typed to ObjCInterfaceType
-ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName,
- SourceLocation clsNameLoc, Selector selInfo,
- QualType retType, ObjCMethodDecl *mproto,
- SourceLocation LBrac, SourceLocation RBrac,
- Expr **ArgExprs, unsigned nargs)
- : Expr(ObjCMessageExprClass, retType, false, false), ClassNameLoc(clsNameLoc),
- SelName(selInfo), MethodProto(mproto) {
- NumArgs = nargs;
- SubExprs = new (C) Stmt*[NumArgs+1];
- SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | IsClsMethDeclUnknown);
- if (NumArgs) {
- for (unsigned i = 0; i != NumArgs; ++i)
- SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]);
- }
- LBracloc = LBrac;
- RBracloc = RBrac;
-}
-
-// constructor for class messages.
-ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls,
- SourceLocation clsNameLoc, Selector selInfo,
- QualType retType,
- ObjCMethodDecl *mproto, SourceLocation LBrac,
- SourceLocation RBrac, Expr **ArgExprs,
- unsigned nargs)
- : Expr(ObjCMessageExprClass, retType, false, false), ClassNameLoc(clsNameLoc),
- SelName(selInfo), MethodProto(mproto)
+ObjCMessageExpr::ObjCMessageExpr(QualType T,
+ SourceLocation LBracLoc,
+ SourceLocation SuperLoc,
+ bool IsInstanceSuper,
+ QualType SuperType,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc)
+ : Expr(ObjCMessageExprClass, T, /*TypeDependent=*/false,
+ /*ValueDependent=*/false),
+ NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass),
+ HasMethod(Method != 0), SuperLoc(SuperLoc),
+ SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
+ : Sel.getAsOpaquePtr())),
+ LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
- NumArgs = nargs;
- SubExprs = new (C) Stmt*[NumArgs+1];
- SubExprs[RECEIVER] = (Expr*) ((uintptr_t) cls | IsClsMethDeclKnown);
- if (NumArgs) {
- for (unsigned i = 0; i != NumArgs; ++i)
- SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]);
- }
- LBracloc = LBrac;
- RBracloc = RBrac;
-}
+ setReceiverPointer(SuperType.getAsOpaquePtr());
+ if (NumArgs)
+ memcpy(getArgs(), Args, NumArgs * sizeof(Expr *));
+}
+
+ObjCMessageExpr::ObjCMessageExpr(QualType T,
+ SourceLocation LBracLoc,
+ TypeSourceInfo *Receiver,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc)
+ : Expr(ObjCMessageExprClass, T, T->isDependentType(),
+ (T->isDependentType() ||
+ hasAnyValueDependentArguments(Args, NumArgs))),
+ NumArgs(NumArgs), Kind(Class), HasMethod(Method != 0),
+ SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
+ : Sel.getAsOpaquePtr())),
+ LBracLoc(LBracLoc), RBracLoc(RBracLoc)
+{
+ setReceiverPointer(Receiver);
+ if (NumArgs)
+ memcpy(getArgs(), Args, NumArgs * sizeof(Expr *));
+}
+
+ObjCMessageExpr::ObjCMessageExpr(QualType T,
+ SourceLocation LBracLoc,
+ Expr *Receiver,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc)
+ : Expr(ObjCMessageExprClass, T, Receiver->isTypeDependent(),
+ (Receiver->isTypeDependent() ||
+ hasAnyValueDependentArguments(Args, NumArgs))),
+ NumArgs(NumArgs), Kind(Instance), HasMethod(Method != 0),
+ SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
+ : Sel.getAsOpaquePtr())),
+ LBracLoc(LBracLoc), RBracLoc(RBracLoc)
+{
+ setReceiverPointer(Receiver);
+ if (NumArgs)
+ memcpy(getArgs(), Args, NumArgs * sizeof(Expr *));
+}
+
+ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ SourceLocation LBracLoc,
+ SourceLocation SuperLoc,
+ bool IsInstanceSuper,
+ QualType SuperType,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc) {
+ unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
+ NumArgs * sizeof(Expr *);
+ void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
+ return new (Mem) ObjCMessageExpr(T, LBracLoc, SuperLoc, IsInstanceSuper,
+ SuperType, Sel, Method, Args, NumArgs,
+ RBracLoc);
+}
+
+ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ SourceLocation LBracLoc,
+ TypeSourceInfo *Receiver,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc) {
+ unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
+ NumArgs * sizeof(Expr *);
+ void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
+ return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args,
+ NumArgs, RBracLoc);
+}
+
+ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ SourceLocation LBracLoc,
+ Expr *Receiver,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc) {
+ unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
+ NumArgs * sizeof(Expr *);
+ void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
+ return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args,
+ NumArgs, RBracLoc);
+}
+
+ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context,
+ unsigned NumArgs) {
+ unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
+ NumArgs * sizeof(Expr *);
+ void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
+ return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs);
+}
+
+Selector ObjCMessageExpr::getSelector() const {
+ if (HasMethod)
+ return reinterpret_cast<const ObjCMethodDecl *>(SelectorOrMethod)
+ ->getSelector();
+ return Selector(SelectorOrMethod);
+}
+
+ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
+ switch (getReceiverKind()) {
+ case Instance:
+ if (const ObjCObjectPointerType *Ptr
+ = getInstanceReceiver()->getType()->getAs<ObjCObjectPointerType>())
+ return Ptr->getInterfaceDecl();
+ break;
-ObjCMessageExpr::ClassInfo ObjCMessageExpr::getClassInfo() const {
- uintptr_t x = (uintptr_t) SubExprs[RECEIVER];
- switch (x & Flags) {
- default:
- assert(false && "Invalid ObjCMessageExpr.");
- case IsInstMeth:
- return ClassInfo(0, 0, SourceLocation());
- case IsClsMethDeclUnknown:
- return ClassInfo(0, (IdentifierInfo*) (x & ~Flags), ClassNameLoc);
- case IsClsMethDeclKnown: {
- ObjCInterfaceDecl* D = (ObjCInterfaceDecl*) (x & ~Flags);
- return ClassInfo(D, D->getIdentifier(), ClassNameLoc);
- }
- }
-}
+ case Class:
+ if (const ObjCInterfaceType *Iface
+ = getClassReceiver()->getAs<ObjCInterfaceType>())
+ return Iface->getDecl();
+ break;
-void ObjCMessageExpr::setClassInfo(const ObjCMessageExpr::ClassInfo &CI) {
- if (CI.Decl == 0 && CI.Name == 0) {
- SubExprs[RECEIVER] = (Expr*)((uintptr_t)0 | IsInstMeth);
- return;
- }
+ case SuperInstance:
+ if (const ObjCObjectPointerType *Ptr
+ = getSuperType()->getAs<ObjCObjectPointerType>())
+ return Ptr->getInterfaceDecl();
+ break;
- if (CI.Decl == 0)
- SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.Name | IsClsMethDeclUnknown);
- else
- SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.Decl | IsClsMethDeclKnown);
- ClassNameLoc = CI.Loc;
-}
+ case SuperClass:
+ if (const ObjCObjectPointerType *Iface
+ = getSuperType()->getAs<ObjCObjectPointerType>())
+ return Iface->getInterfaceDecl();
+ break;
+ }
-void ObjCMessageExpr::DoDestroy(ASTContext &C) {
- DestroyChildren(C);
- if (SubExprs)
- C.Deallocate(SubExprs);
- this->~ObjCMessageExpr();
- C.Deallocate((void*) this);
+ return 0;
}
bool ChooseExpr::isConditionTrue(ASTContext &C) const {
@@ -2577,6 +2758,15 @@ Stmt::child_iterator ParenExpr::child_end() { return &Val+1; }
Stmt::child_iterator UnaryOperator::child_begin() { return &Val; }
Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; }
+// OffsetOfExpr
+Stmt::child_iterator OffsetOfExpr::child_begin() {
+ return reinterpret_cast<Stmt **> (reinterpret_cast<OffsetOfNode *> (this + 1)
+ + NumComps);
+}
+Stmt::child_iterator OffsetOfExpr::child_end() {
+ return child_iterator(&*child_begin() + NumExprs);
+}
+
// SizeOfAlignOfExpr
Stmt::child_iterator SizeOfAlignOfExpr::child_begin() {
// If this is of a type and the type is a VLA type (and not a typedef), the
@@ -2746,10 +2936,12 @@ Stmt::child_iterator ObjCProtocolExpr::child_end() {
// ObjCMessageExpr
Stmt::child_iterator ObjCMessageExpr::child_begin() {
- return getReceiver() ? &SubExprs[0] : &SubExprs[0] + ARGS_START;
+ if (getReceiverKind() == Instance)
+ return reinterpret_cast<Stmt **>(this + 1);
+ return getArgs();
}
Stmt::child_iterator ObjCMessageExpr::child_end() {
- return &SubExprs[0]+ARGS_START+getNumArgs();
+ return getArgs() + getNumArgs();
}
// Blocks
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index b9a4ee6..2e03beb 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -18,16 +18,25 @@
#include "clang/AST/TypeLoc.h"
using namespace clang;
+
//===----------------------------------------------------------------------===//
// Child Iterators for iterating over subexpressions/substatements
//===----------------------------------------------------------------------===//
+QualType CXXTypeidExpr::getTypeOperand() const {
+ assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)");
+ return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType()
+ .getUnqualifiedType();
+}
+
// CXXTypeidExpr - has child iterators if the operand is an expression
Stmt::child_iterator CXXTypeidExpr::child_begin() {
- return isTypeOperand() ? child_iterator() : &Operand.Ex;
+ return isTypeOperand() ? child_iterator()
+ : reinterpret_cast<Stmt **>(&Operand);
}
Stmt::child_iterator CXXTypeidExpr::child_end() {
- return isTypeOperand() ? child_iterator() : &Operand.Ex+1;
+ return isTypeOperand() ? child_iterator()
+ : reinterpret_cast<Stmt **>(&Operand) + 1;
}
// CXXBoolLiteralExpr
@@ -180,6 +189,13 @@ bool OverloadExpr::ComputeDependence(UnresolvedSetIterator Begin,
return false;
}
+CXXRecordDecl *OverloadExpr::getNamingClass() const {
+ if (isa<UnresolvedLookupExpr>(this))
+ return cast<UnresolvedLookupExpr>(this)->getNamingClass();
+ else
+ return cast<UnresolvedMemberExpr>(this)->getNamingClass();
+}
+
Stmt::child_iterator UnresolvedLookupExpr::child_begin() {
return child_iterator();
}
@@ -443,9 +459,10 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
SourceLocation tyBeginLoc,
Expr **Args,
unsigned NumArgs,
- SourceLocation rParenLoc)
+ SourceLocation rParenLoc,
+ bool ZeroInitialization)
: CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, tyBeginLoc,
- Cons, false, Args, NumArgs),
+ Cons, false, Args, NumArgs, ZeroInitialization),
TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {
}
@@ -454,25 +471,25 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
CXXConstructorDecl *D, bool Elidable,
Expr **Args, unsigned NumArgs,
bool ZeroInitialization,
- bool BaseInitialization) {
+ ConstructionKind ConstructKind) {
return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
Elidable, Args, NumArgs, ZeroInitialization,
- BaseInitialization);
+ ConstructKind);
}
CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool elidable,
Expr **args, unsigned numargs,
- bool ZeroInitialization,
- bool BaseInitialization)
+ bool ZeroInitialization,
+ ConstructionKind ConstructKind)
: Expr(SC, T,
T->isDependentType(),
(T->isDependentType() ||
CallExpr::hasAnyValueDependentArguments(args, numargs))),
Constructor(D), Loc(Loc), Elidable(elidable),
- ZeroInitialization(ZeroInitialization),
- BaseInitialization(BaseInitialization), Args(0), NumArgs(numargs)
+ ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind),
+ Args(0), NumArgs(numargs)
{
if (NumArgs) {
Args = new (C) Stmt*[NumArgs];
@@ -712,15 +729,15 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const {
// If there was a nested name specifier, it names the naming class.
// It can't be dependent: after all, we were actually able to do the
// lookup.
- const RecordType *RT;
+ CXXRecordDecl *Record = 0;
if (getQualifier()) {
Type *T = getQualifier()->getAsType();
assert(T && "qualifier in member expression does not name type");
- RT = T->getAs<RecordType>();
- assert(RT && "qualifier in member expression does not name record");
-
+ Record = T->getAsCXXRecordDecl();
+ assert(Record && "qualifier in member expression does not name record");
+ }
// Otherwise the naming class must have been the base class.
- } else {
+ else {
QualType BaseType = getBaseType().getNonReferenceType();
if (isArrow()) {
const PointerType *PT = BaseType->getAs<PointerType>();
@@ -728,11 +745,11 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const {
BaseType = PT->getPointeeType();
}
- RT = BaseType->getAs<RecordType>();
- assert(RT && "base of member expression does not name record");
+ Record = BaseType->getAsCXXRecordDecl();
+ assert(Record && "base of member expression does not name record");
}
- return cast<CXXRecordDecl>(RT->getDecl());
+ return Record;
}
Stmt::child_iterator UnresolvedMemberExpr::child_begin() {
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index eeeeb5c..c1a42d8 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -16,7 +16,9 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/Expr.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
@@ -203,6 +205,13 @@ public:
return Visit(E->getSubExpr());
}
bool VisitUnaryOperator(UnaryOperator *E) { return Visit(E->getSubExpr()); }
+
+ // Has side effects if any element does.
+ bool VisitInitListExpr(InitListExpr *E) {
+ for (unsigned i = 0, e = E->getNumInits(); i != e; ++i)
+ if (Visit(E->getInit(i))) return true;
+ return false;
+ }
};
} // end anonymous namespace
@@ -221,7 +230,7 @@ public:
APValue VisitStmt(Stmt *S) {
return APValue();
}
-
+
APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
APValue VisitDeclRefExpr(DeclRefExpr *E);
APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E); }
@@ -821,6 +830,7 @@ public:
bool VisitCallExpr(CallExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
+ bool VisitOffsetOfExpr(const OffsetOfExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
bool VisitConditionalOperator(const ConditionalOperator *E);
@@ -961,7 +971,7 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) {
return complex_type_class;
else if (ArgTy->isFunctionType())
return function_type_class;
- else if (ArgTy->isStructureType())
+ else if (ArgTy->isStructureOrClassType())
return record_type_class;
else if (ArgTy->isUnionType())
return union_type_class;
@@ -1109,9 +1119,11 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
assert(E->getOpcode() == BinaryOperator::NE &&
"Invalid complex comparison.");
return Success(((CR_r == APFloat::cmpGreaterThan ||
- CR_r == APFloat::cmpLessThan) &&
+ CR_r == APFloat::cmpLessThan ||
+ CR_r == APFloat::cmpUnordered) ||
(CR_i == APFloat::cmpGreaterThan ||
- CR_i == APFloat::cmpLessThan)), E);
+ CR_i == APFloat::cmpLessThan ||
+ CR_i == APFloat::cmpUnordered)), E);
}
} else {
if (E->getOpcode() == BinaryOperator::EQ)
@@ -1154,7 +1166,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return Success(CR == APFloat::cmpEqual, E);
case BinaryOperator::NE:
return Success(CR == APFloat::cmpGreaterThan
- || CR == APFloat::cmpLessThan, E);
+ || CR == APFloat::cmpLessThan
+ || CR == APFloat::cmpUnordered, E);
}
}
@@ -1191,8 +1204,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
}
if (E->getOpcode() == BinaryOperator::Sub) {
- const QualType Type = E->getLHS()->getType();
- const QualType ElementType = Type->getAs<PointerType>()->getPointeeType();
+ QualType Type = E->getLHS()->getType();
+ QualType ElementType = Type->getAs<PointerType>()->getPointeeType();
CharUnits ElementSize = CharUnits::One();
if (!ElementType->isVoidType() && !ElementType->isFunctionType())
@@ -1365,6 +1378,85 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
return Success(Info.Ctx.getTypeSizeInChars(SrcTy).getQuantity(), E);
}
+bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) {
+ CharUnits Result;
+ unsigned n = E->getNumComponents();
+ OffsetOfExpr* OOE = const_cast<OffsetOfExpr*>(E);
+ if (n == 0)
+ return false;
+ QualType CurrentType = E->getTypeSourceInfo()->getType();
+ for (unsigned i = 0; i != n; ++i) {
+ OffsetOfExpr::OffsetOfNode ON = OOE->getComponent(i);
+ switch (ON.getKind()) {
+ case OffsetOfExpr::OffsetOfNode::Array: {
+ Expr *Idx = OOE->getIndexExpr(ON.getArrayExprIndex());
+ APSInt IdxResult;
+ if (!EvaluateInteger(Idx, IdxResult, Info))
+ return false;
+ const ArrayType *AT = Info.Ctx.getAsArrayType(CurrentType);
+ if (!AT)
+ return false;
+ CurrentType = AT->getElementType();
+ CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType);
+ Result += IdxResult.getSExtValue() * ElementSize;
+ break;
+ }
+
+ case OffsetOfExpr::OffsetOfNode::Field: {
+ FieldDecl *MemberDecl = ON.getField();
+ const RecordType *RT = CurrentType->getAs<RecordType>();
+ if (!RT)
+ return false;
+ RecordDecl *RD = RT->getDecl();
+ const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
+ unsigned i = 0;
+ // FIXME: It would be nice if we didn't have to loop here!
+ for (RecordDecl::field_iterator Field = RD->field_begin(),
+ FieldEnd = RD->field_end();
+ Field != FieldEnd; (void)++Field, ++i) {
+ if (*Field == MemberDecl)
+ break;
+ }
+ assert(i < RL.getFieldCount() && "offsetof field in wrong type");
+ Result += CharUnits::fromQuantity(
+ RL.getFieldOffset(i) / Info.Ctx.getCharWidth());
+ CurrentType = MemberDecl->getType().getNonReferenceType();
+ break;
+ }
+
+ case OffsetOfExpr::OffsetOfNode::Identifier:
+ llvm_unreachable("dependent __builtin_offsetof");
+ return false;
+
+ case OffsetOfExpr::OffsetOfNode::Base: {
+ CXXBaseSpecifier *BaseSpec = ON.getBase();
+ if (BaseSpec->isVirtual())
+ return false;
+
+ // Find the layout of the class whose base we are looking into.
+ const RecordType *RT = CurrentType->getAs<RecordType>();
+ if (!RT)
+ return false;
+ RecordDecl *RD = RT->getDecl();
+ const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
+
+ // Find the base class itself.
+ CurrentType = BaseSpec->getType();
+ const RecordType *BaseRT = CurrentType->getAs<RecordType>();
+ if (!BaseRT)
+ return false;
+
+ // Add the offset to the base.
+ Result += CharUnits::fromQuantity(
+ RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl()))
+ / Info.Ctx.getCharWidth());
+ break;
+ }
+ }
+ }
+ return Success(Result.getQuantity(), E);
+}
+
bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
// Special case unary operators that do not need their subexpression
// evaluated. offsetof/sizeof/alignof are all special.
@@ -1373,12 +1465,12 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
// directly Evaluate it as an l-value.
APValue LV;
if (!EvaluateLValue(E->getSubExpr(), LV, Info))
- return false;
+ return false;
if (LV.getLValueBase())
- return false;
+ return false;
return Success(LV.getLValueOffset().getQuantity(), E);
}
-
+
if (E->getOpcode() == UnaryOperator::LNot) {
// LNot's operand isn't necessarily an integer, so we handle it specially.
bool bres;
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 93edb42..3782985 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -15,15 +15,16 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/TargetInfo.h"
-#include <llvm/ADT/SmallSet.h>
-#include <llvm/Support/MathExtras.h>
+#include "llvm/Support/Format.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/MathExtras.h"
using namespace clang;
-ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
- : Ctx(Ctx), Size(0), Alignment(8), Packed(false), UnfilledBitsInLastByte(0),
- MaxFieldAlignment(0), DataSize(0), IsUnion(false), NonVirtualSize(0),
- NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { }
+ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Context)
+ : Context(Context), Size(0), Alignment(8), Packed(false),
+ UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0), IsUnion(false),
+ NonVirtualSize(0), NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { }
/// IsNearlyEmpty - Indicates when a class has a vtable pointer, but
/// no other data.
@@ -31,29 +32,29 @@ bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
// FIXME: Audit the corners
if (!RD->isDynamicClass())
return false;
- const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
- if (BaseInfo.getNonVirtualSize() == Ctx.Target.getPointerWidth(0))
+ const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD);
+ if (BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0))
return true;
return false;
}
void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
- const ASTRecordLayout::PrimaryBaseInfo &BaseInfo =
- Ctx.getASTRecordLayout(RD).getPrimaryBaseInfo();
-
+ const ASTRecordLayout::PrimaryBaseInfo &BaseInfo =
+ Context.getASTRecordLayout(RD).getPrimaryBaseInfo();
+
// If the record has a primary base class that is virtual, add it to the set
// of primary bases.
if (BaseInfo.isVirtual())
IndirectPrimaryBases.insert(BaseInfo.getBase());
-
+
// Now traverse all bases and find primary bases for them.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
+ e = RD->bases_end(); i != e; ++i) {
assert(!i->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
-
+
// Only bases with virtual bases participate in computing the
// indirect primary virtual base classes.
if (Base->getNumVBases())
@@ -64,10 +65,10 @@ void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
void
ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
+ E = RD->bases_end(); I != E; ++I) {
assert(!I->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
-
+
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
@@ -80,12 +81,12 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
/*IsVirtual=*/true);
return;
}
-
+
// Is this the first nearly empty virtual base?
if (!FirstNearlyEmptyVBase)
FirstNearlyEmptyVBase = Base;
}
-
+
SelectPrimaryVBase(Base);
if (PrimaryBase.getBase())
return;
@@ -97,11 +98,11 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
// If the class isn't dynamic, it won't have a primary base.
if (!RD->isDynamicClass())
return;
-
+
// Compute all the primary virtual bases for all of our direct and
// indirect bases, and record all their primary virtual base classes.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
+ e = RD->bases_end(); i != e; ++i) {
assert(!i->getType()->isDependentType() &&
"Cannot lay out class with dependent bases.");
const CXXRecordDecl *Base =
@@ -109,15 +110,15 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
IdentifyPrimaryBases(Base);
}
- // If the record has a dynamic base class, attempt to choose a primary base
- // class. It is the first (in direct base class order) non-virtual dynamic
+ // If the record has a dynamic base class, attempt to choose a primary base
+ // class. It is the first (in direct base class order) non-virtual dynamic
// base class, if one exists.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
+ e = RD->bases_end(); i != e; ++i) {
// Ignore virtual bases.
if (i->isVirtual())
continue;
-
+
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
@@ -139,44 +140,47 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
// Otherwise, it is the first nearly empty virtual base that is not an
// indirect primary virtual base class, if one exists.
if (FirstNearlyEmptyVBase) {
- PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(FirstNearlyEmptyVBase,
+ PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(FirstNearlyEmptyVBase,
/*IsVirtual=*/true);
return;
}
-
+
// Otherwise there is no primary base class.
assert(!PrimaryBase.getBase() && "Should not get here with a primary base!");
// Allocate the virtual table pointer at offset zero.
assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
-
+
// Update the size.
- Size += Ctx.Target.getPointerWidth(0);
+ Size += Context.Target.getPointerWidth(0);
DataSize = Size;
// Update the alignment.
- UpdateAlignment(Ctx.Target.getPointerAlign(0));
+ UpdateAlignment(Context.Target.getPointerAlign(0));
}
void
ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
// First, determine the primary base class.
DeterminePrimaryBase(RD);
-
+
// If we have a primary base class, lay it out.
if (const CXXRecordDecl *Base = PrimaryBase.getBase()) {
if (PrimaryBase.isVirtual()) {
// We have a virtual primary base, insert it as an indirect primary base.
IndirectPrimaryBases.insert(Base);
+ assert(!VisitedVirtualBases.count(Base) && "vbase already visited!");
+ VisitedVirtualBases.insert(Base);
+
LayoutVirtualBase(Base);
} else
LayoutNonVirtualBase(Base);
}
-
+
// Now lay out the non-virtual bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
+ E = RD->bases_end(); I != E; ++I) {
// Ignore virtual bases.
if (I->isVirtual())
@@ -197,83 +201,113 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) {
// Layout the base.
uint64_t Offset = LayoutBase(RD);
-
+
// Add its base class offset.
if (!Bases.insert(std::make_pair(RD, Offset)).second)
assert(false && "Added same base offset more than once!");
}
-void
-ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
+void
+ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD,
uint64_t Offset,
const CXXRecordDecl *MostDerivedClass) {
+ // We already have the offset for the primary base of the most derived class.
+ if (RD != MostDerivedClass) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ // If this is a primary virtual base and we haven't seen it before, add it.
+ if (PrimaryBase && Layout.getPrimaryBaseWasVirtual() &&
+ !VBases.count(PrimaryBase))
+ VBases.insert(std::make_pair(PrimaryBase, Offset));
+ }
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ assert(!I->getType()->isDependentType() &&
+ "Cannot layout class with dependent bases.");
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ if (!BaseDecl->getNumVBases()) {
+ // This base isn't interesting since it doesn't have any virtual bases.
+ continue;
+ }
+
+ // Compute the offset of this base.
+ uint64_t BaseOffset;
+
+ if (I->isVirtual()) {
+ // If we don't know this vbase yet, don't visit it. It will be visited
+ // later.
+ if (!VBases.count(BaseDecl)) {
+ continue;
+ }
+
+ // Check if we've already visited this base.
+ if (!VisitedVirtualBases.insert(BaseDecl))
+ continue;
+
+ // We want the vbase offset from the class we're currently laying out.
+ BaseOffset = VBases[BaseDecl];
+ } else if (RD == MostDerivedClass) {
+ // We want the base offset from the class we're currently laying out.
+ assert(Bases.count(BaseDecl) && "Did not find base!");
+ BaseOffset = Bases[BaseDecl];
+ } else {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
+ }
+
+ AddPrimaryVirtualBaseOffsets(BaseDecl, BaseOffset, MostDerivedClass);
+ }
+}
+
+void
+ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
+ const CXXRecordDecl *MostDerivedClass) {
const CXXRecordDecl *PrimaryBase;
+ bool PrimaryBaseIsVirtual;
- if (MostDerivedClass == RD)
+ if (MostDerivedClass == RD) {
PrimaryBase = this->PrimaryBase.getBase();
- else {
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+ PrimaryBaseIsVirtual = this->PrimaryBase.isVirtual();
+ } else {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
PrimaryBase = Layout.getPrimaryBase();
+ PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual();
}
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
assert(!I->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
-
+
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
if (I->isVirtual()) {
- bool IndirectPrimaryBase = IndirectPrimaryBases.count(Base);
-
- // We only want to visit this virtual base if it's either a primary base,
- // or not an indirect primary base.
- if (Base == PrimaryBase || !IndirectPrimaryBase) {
- // Only lay things out once.
- if (!VisitedVirtualBases.insert(Base))
- continue;
-
- if (Base == PrimaryBase) {
- assert(IndirectPrimaryBase &&
- "Base is supposed to be an indirect primary base!");
-
- // We only want to add a vbase offset if this primary base is not the
- // primary base of the most derived class.
- if (PrimaryBase != this->PrimaryBase.getBase() ||
- !this->PrimaryBase.isVirtual()) {
- if (!VBases.insert(std::make_pair(Base, Offset)).second)
- assert(false && "Added same vbase offset more than once!");
- }
- } else {
- // We actually do want to lay out this base.
+ if (PrimaryBase != Base || !PrimaryBaseIsVirtual) {
+ bool IndirectPrimaryBase = IndirectPrimaryBases.count(Base);
+
+ // Only lay out the virtual base if it's not an indirect primary base.
+ if (!IndirectPrimaryBase) {
+ // Only visit virtual bases once.
+ if (!VisitedVirtualBases.insert(Base))
+ continue;
+
LayoutVirtualBase(Base);
}
}
}
-
+
if (!Base->getNumVBases()) {
// This base isn't interesting since it doesn't have any virtual bases.
continue;
}
- // Compute the offset of this base.
- uint64_t BaseOffset;
-
- if (I->isVirtual()) {
- // We want the vbase offset from the class we're currently laying out.
- assert(VBases.count(Base) && "Did not find virtual base!");
- BaseOffset = VBases[Base];
- } else if (RD == MostDerivedClass) {
- // We want the base offset from the class we're currently laying out.
- assert(Bases.count(Base) && "Did not find base!");
- BaseOffset = Bases[Base];
- } else {
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
- BaseOffset = Offset + Layout.getBaseClassOffset(Base);
- }
-
- LayoutVirtualBases(Base, BaseOffset, MostDerivedClass);
+ LayoutVirtualBases(Base, MostDerivedClass);
}
}
@@ -287,7 +321,7 @@ void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) {
}
uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
- const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
+ const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD);
// If we have an empty base class, try to place it at offset 0.
if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) {
@@ -298,17 +332,17 @@ uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
return 0;
}
-
+
unsigned BaseAlign = BaseInfo.getNonVirtualAlign();
-
+
// Round up the current record size to the base's alignment boundary.
uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign);
-
+
// Try to place the base.
while (true) {
if (canPlaceRecordAtOffset(RD, Offset))
break;
-
+
Offset += BaseAlign;
}
@@ -327,44 +361,44 @@ uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
return Offset;
}
-bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
+bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
uint64_t Offset) const {
// Look for an empty class with the same type at the same offset.
- for (EmptyClassOffsetsTy::const_iterator I =
- EmptyClassOffsets.lower_bound(Offset),
- E = EmptyClassOffsets.upper_bound(Offset); I != E; ++I) {
-
+ for (EmptyClassOffsetsTy::const_iterator I =
+ EmptyClassOffsets.lower_bound(Offset),
+ E = EmptyClassOffsets.upper_bound(Offset); I != E; ++I) {
+
if (I->second == RD)
return false;
}
-
- const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD);
+
+ const ASTRecordLayout &Info = Context.getASTRecordLayout(RD);
// Check bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
+ E = RD->bases_end(); I != E; ++I) {
assert(!I->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
if (I->isVirtual())
continue;
-
+
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
uint64_t BaseClassOffset = Info.getBaseClassOffset(Base);
-
+
if (!canPlaceRecordAtOffset(Base, Offset + BaseClassOffset))
return false;
}
-
+
// Check fields.
unsigned FieldNo = 0;
- for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
-
+
uint64_t FieldOffset = Info.getFieldOffset(FieldNo);
-
+
if (!canPlaceFieldAtOffset(FD, Offset + FieldOffset))
return false;
}
@@ -373,35 +407,35 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
return true;
}
-bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD,
+bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD,
uint64_t Offset) const {
QualType T = FD->getType();
if (const RecordType *RT = T->getAs<RecordType>()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
return canPlaceRecordAtOffset(RD, Offset);
}
-
- if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) {
- QualType ElemTy = Ctx.getBaseElementType(AT);
+
+ if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
+ QualType ElemTy = Context.getBaseElementType(AT);
const RecordType *RT = ElemTy->getAs<RecordType>();
if (!RT)
return true;
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
if (!RD)
return true;
-
- const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD);
- uint64_t NumElements = Ctx.getConstantArrayElementCount(AT);
+ const ASTRecordLayout &Info = Context.getASTRecordLayout(RD);
+
+ uint64_t NumElements = Context.getConstantArrayElementCount(AT);
uint64_t ElementOffset = Offset;
for (uint64_t I = 0; I != NumElements; ++I) {
if (!canPlaceRecordAtOffset(RD, ElementOffset))
return false;
-
+
ElementOffset += Info.getSize();
}
}
-
+
return true;
}
@@ -409,39 +443,39 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD,
uint64_t Offset) {
if (RD->isEmpty())
EmptyClassOffsets.insert(std::make_pair(Offset, RD));
-
- const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD);
+
+ const ASTRecordLayout &Info = Context.getASTRecordLayout(RD);
// Update bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
+ E = RD->bases_end(); I != E; ++I) {
assert(!I->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
if (I->isVirtual())
continue;
-
+
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
+
uint64_t BaseClassOffset = Info.getBaseClassOffset(Base);
UpdateEmptyClassOffsets(Base, Offset + BaseClassOffset);
}
-
+
// Update fields.
unsigned FieldNo = 0;
- for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
-
+
uint64_t FieldOffset = Info.getFieldOffset(FieldNo);
UpdateEmptyClassOffsets(FD, Offset + FieldOffset);
}
-
+
// FIXME: Update virtual bases.
}
void
-ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
+ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
uint64_t Offset) {
QualType T = FD->getType();
@@ -451,19 +485,19 @@ ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
return;
}
}
-
- if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) {
- QualType ElemTy = Ctx.getBaseElementType(AT);
+
+ if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
+ QualType ElemTy = Context.getBaseElementType(AT);
const RecordType *RT = ElemTy->getAs<RecordType>();
if (!RT)
return;
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
if (!RD)
return;
-
- const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD);
- uint64_t NumElements = Ctx.getConstantArrayElementCount(AT);
+ const ASTRecordLayout &Info = Context.getASTRecordLayout(RD);
+
+ uint64_t NumElements = Context.getConstantArrayElementCount(AT);
uint64_t ElementOffset = Offset;
for (uint64_t I = 0; I != NumElements; ++I) {
@@ -495,20 +529,50 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
NonVirtualSize = Size;
NonVirtualAlignment = Alignment;
- // If this is a C++ class, lay out its virtual bases.
- if (RD)
- LayoutVirtualBases(RD, 0, RD);
+ // If this is a C++ class, lay out its virtual bases and add its primary
+ // virtual base offsets.
+ if (RD) {
+ LayoutVirtualBases(RD, RD);
+
+ VisitedVirtualBases.clear();
+ AddPrimaryVirtualBaseOffsets(RD, 0, RD);
+ }
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
FinishLayout();
+
+#ifndef NDEBUG
+ if (RD) {
+ // Check that we have base offsets for all bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ assert(Bases.count(BaseDecl) && "Did not find base offset!");
+ }
+
+ // And all virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ assert(VBases.count(BaseDecl) && "Did not find base offset!");
+ }
+ }
+#endif
}
// FIXME. Impl is no longer needed.
void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
const ObjCImplementationDecl *Impl) {
if (ObjCInterfaceDecl *SD = D->getSuperClass()) {
- const ASTRecordLayout &SL = Ctx.getASTObjCInterfaceLayout(SD);
+ const ASTRecordLayout &SL = Context.getASTObjCInterfaceLayout(SD);
UpdateAlignment(SL.getAlignment());
@@ -528,7 +592,7 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
UpdateAlignment(AA->getMaxAlignment());
// Layout each ivar sequentially.
llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
- Ctx.ShallowCollectObjCIvars(D, Ivars);
+ Context.ShallowCollectObjCIvars(D, Ivars);
for (unsigned i = 0, e = Ivars.size(); i != e; ++i)
LayoutField(Ivars[i]);
@@ -541,20 +605,82 @@ void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Layout each field, for now, just sequentially, respecting alignment. In
// the future, this will need to be tweakable by targets.
for (RecordDecl::field_iterator Field = D->field_begin(),
- FieldEnd = D->field_end(); Field != FieldEnd; ++Field)
+ FieldEnd = D->field_end(); Field != FieldEnd; ++Field)
LayoutField(*Field);
}
+void ASTRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
+ uint64_t TypeSize) {
+ assert(Context.getLangOptions().CPlusPlus &&
+ "Can only have wide bit-fields in C++!");
+
+ // Itanium C++ ABI 2.4:
+ // If sizeof(T)*8 < n, let T' be the largest integral POD type with
+ // sizeof(T')*8 <= n.
+
+ QualType IntegralPODTypes[] = {
+ Context.UnsignedCharTy, Context.UnsignedShortTy, Context.UnsignedIntTy,
+ Context.UnsignedLongTy, Context.UnsignedLongLongTy
+ };
+
+ QualType Type;
+ for (unsigned I = 0, E = llvm::array_lengthof(IntegralPODTypes);
+ I != E; ++I) {
+ uint64_t Size = Context.getTypeSize(IntegralPODTypes[I]);
+
+ if (Size > FieldSize)
+ break;
+
+ Type = IntegralPODTypes[I];
+ }
+ assert(!Type.isNull() && "Did not find a type!");
+
+ unsigned TypeAlign = Context.getTypeAlign(Type);
+
+ // We're not going to use any of the unfilled bits in the last byte.
+ UnfilledBitsInLastByte = 0;
+
+ uint64_t FieldOffset;
+
+ if (IsUnion) {
+ DataSize = std::max(DataSize, FieldSize);
+ FieldOffset = 0;
+ } else {
+ // The bitfield is allocated starting at the next offset aligned appropriately
+ // for T', with length n bits.
+ FieldOffset = llvm::RoundUpToAlignment(DataSize, TypeAlign);
+
+ uint64_t NewSizeInBits = FieldOffset + FieldSize;
+
+ DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8);
+ UnfilledBitsInLastByte = DataSize - NewSizeInBits;
+ }
+
+ // Place this field at the current location.
+ FieldOffsets.push_back(FieldOffset);
+
+ // Update the size.
+ Size = std::max(Size, DataSize);
+
+ // Remember max struct/class alignment.
+ UpdateAlignment(TypeAlign);
+}
+
void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte);
- uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Ctx).getZExtValue();
-
- std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
+ uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
+
+ std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
uint64_t TypeSize = FieldInfo.first;
unsigned FieldAlign = FieldInfo.second;
-
- if (FieldPacked)
+
+ if (FieldSize > TypeSize) {
+ LayoutWideBitField(FieldSize, TypeSize);
+ return;
+ }
+
+ if (FieldPacked || !Context.Target.useBitFieldTypeAlignment())
FieldAlign = 1;
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
FieldAlign = std::max(FieldAlign, AA->getMaxAlignment());
@@ -562,33 +688,32 @@ void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
// The maximum field alignment overrides the aligned attribute.
if (MaxFieldAlignment)
FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
-
- // Check if we need to add padding to give the field the correct
- // alignment.
+
+ // Check if we need to add padding to give the field the correct alignment.
if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
-
- // Padding members don't affect overall alignment
+
+ // Padding members don't affect overall alignment.
if (!D->getIdentifier())
FieldAlign = 1;
-
+
// Place this field at the current location.
FieldOffsets.push_back(FieldOffset);
-
+
// Update DataSize to include the last byte containing (part of) the bitfield.
if (IsUnion) {
// FIXME: I think FieldSize should be TypeSize here.
DataSize = std::max(DataSize, FieldSize);
} else {
uint64_t NewSizeInBits = FieldOffset + FieldSize;
-
+
DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8);
UnfilledBitsInLastByte = DataSize - NewSizeInBits;
}
-
+
// Update the size.
Size = std::max(Size, DataSize);
-
+
// Remember max struct/class alignment.
UpdateAlignment(FieldAlign);
}
@@ -606,21 +731,21 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
uint64_t FieldOffset = IsUnion ? 0 : DataSize;
uint64_t FieldSize;
unsigned FieldAlign;
-
+
if (D->getType()->isIncompleteArrayType()) {
// This is a flexible array member; we can't directly
// query getTypeInfo about these, so we figure it out here.
// Flexible array members don't have any size, but they
// have to be aligned appropriately for their element type.
FieldSize = 0;
- const ArrayType* ATy = Ctx.getAsArrayType(D->getType());
- FieldAlign = Ctx.getTypeAlign(ATy->getElementType());
+ const ArrayType* ATy = Context.getAsArrayType(D->getType());
+ FieldAlign = Context.getTypeAlign(ATy->getElementType());
} else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
unsigned AS = RT->getPointeeType().getAddressSpace();
- FieldSize = Ctx.Target.getPointerWidth(AS);
- FieldAlign = Ctx.Target.getPointerAlign(AS);
+ FieldSize = Context.Target.getPointerWidth(AS);
+ FieldAlign = Context.Target.getPointerAlign(AS);
} else {
- std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
+ std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
}
@@ -636,20 +761,20 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
// Round up the current record size to the field's alignment boundary.
FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
-
+
if (!IsUnion) {
while (true) {
// Check if we can place the field at this offset.
if (canPlaceFieldAtOffset(D, FieldOffset))
break;
-
+
// We couldn't place the field at the offset. Try again at a new offset.
FieldOffset += FieldAlign;
}
-
+
UpdateEmptyClassOffsets(D, FieldOffset);
}
-
+
// Place this field at the current location.
FieldOffsets.push_back(FieldOffset);
@@ -668,7 +793,7 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
void ASTRecordLayoutBuilder::FinishLayout() {
// In C++, records cannot be of size 0.
- if (Ctx.getLangOptions().CPlusPlus && Size == 0)
+ if (Context.getLangOptions().CPlusPlus && Size == 0)
Size = 8;
// Finally, round the size of the record up to the alignment of the
// record itself.
@@ -735,7 +860,7 @@ const CXXMethodDecl *
ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
assert(RD->isDynamicClass() && "Class does not have any virtual methods!");
- // If a class isnt' polymorphic it doesn't have a key function.
+ // If a class isn't polymorphic it doesn't have a key function.
if (!RD->isPolymorphic())
return 0;
@@ -745,13 +870,13 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
if (RD->isInAnonymousNamespace())
return 0;
- for (CXXRecordDecl::method_iterator I = RD->method_begin(),
- E = RD->method_end(); I != E; ++I) {
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
const CXXMethodDecl *MD = *I;
-
+
if (!MD->isVirtual())
continue;
-
+
if (MD->isPure())
continue;
@@ -759,17 +884,134 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
// they don't have a body until they're defined.
if (MD->isImplicit())
continue;
-
+
if (MD->isInlineSpecified())
continue;
if (MD->hasInlineBody())
continue;
-
+
// We found it.
return MD;
}
-
+
return 0;
}
+static void PrintOffset(llvm::raw_ostream &OS,
+ uint64_t Offset, unsigned IndentLevel) {
+ OS << llvm::format("%4d | ", Offset);
+ OS.indent(IndentLevel * 2);
+}
+
+static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
+ const CXXRecordDecl *RD, ASTContext &C,
+ uint64_t Offset,
+ unsigned IndentLevel,
+ const char* Description,
+ bool IncludeVirtualBases) {
+ const ASTRecordLayout &Info = C.getASTRecordLayout(RD);
+
+ PrintOffset(OS, Offset, IndentLevel);
+ OS << C.getTypeDeclType(const_cast<CXXRecordDecl *>(RD)).getAsString();
+ if (Description)
+ OS << ' ' << Description;
+ if (RD->isEmpty())
+ OS << " (empty)";
+ OS << '\n';
+
+ IndentLevel++;
+
+ const CXXRecordDecl *PrimaryBase = Info.getPrimaryBase();
+
+ // Vtable pointer.
+ if (RD->isDynamicClass() && !PrimaryBase) {
+ PrintOffset(OS, Offset, IndentLevel);
+ OS << '(' << RD << " vtable pointer)\n";
+ }
+ // Dump (non-virtual) bases
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ assert(!I->getType()->isDependentType() &&
+ "Cannot layout class with dependent bases.");
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ uint64_t BaseOffset = Offset + Info.getBaseClassOffset(Base) / 8;
+
+ DumpCXXRecordLayout(OS, Base, C, BaseOffset, IndentLevel,
+ Base == PrimaryBase ? "(primary base)" : "(base)",
+ /*IncludeVirtualBases=*/false);
+ }
+
+ // Dump fields.
+ uint64_t FieldNo = 0;
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I, ++FieldNo) {
+ const FieldDecl *Field = *I;
+ uint64_t FieldOffset = Offset + Info.getFieldOffset(FieldNo) / 8;
+
+ if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
+ if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ DumpCXXRecordLayout(OS, D, C, FieldOffset, IndentLevel,
+ Field->getNameAsCString(),
+ /*IncludeVirtualBases=*/true);
+ continue;
+ }
+ }
+
+ PrintOffset(OS, FieldOffset, IndentLevel);
+ OS << Field->getType().getAsString() << ' ' << Field << '\n';
+ }
+
+ if (!IncludeVirtualBases)
+ return;
+
+ // Dump virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I) {
+ assert(I->isVirtual() && "Found non-virtual class!");
+ const CXXRecordDecl *VBase =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ uint64_t VBaseOffset = Offset + Info.getVBaseClassOffset(VBase) / 8;
+ DumpCXXRecordLayout(OS, VBase, C, VBaseOffset, IndentLevel,
+ VBase == PrimaryBase ?
+ "(primary virtual base)" : "(virtual base)",
+ /*IncludeVirtualBases=*/false);
+ }
+
+ OS << " sizeof=" << Info.getSize() / 8;
+ OS << ", dsize=" << Info.getDataSize() / 8;
+ OS << ", align=" << Info.getAlignment() / 8 << '\n';
+ OS << " nvsize=" << Info.getNonVirtualSize() / 8;
+ OS << ", nvalign=" << Info.getNonVirtualAlign() / 8 << '\n';
+ OS << '\n';
+}
+
+void ASTContext::DumpRecordLayout(const RecordDecl *RD,
+ llvm::raw_ostream &OS) {
+ const ASTRecordLayout &Info = getASTRecordLayout(RD);
+
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+ return DumpCXXRecordLayout(OS, CXXRD, *this, 0, 0, 0,
+ /*IncludeVirtualBases=*/true);
+
+ OS << "Type: " << getTypeDeclType(RD).getAsString() << "\n";
+ OS << "Record: ";
+ RD->dump();
+ OS << "\nLayout: ";
+ OS << "<ASTRecordLayout\n";
+ OS << " Size:" << Info.getSize() << "\n";
+ OS << " DataSize:" << Info.getDataSize() << "\n";
+ OS << " Alignment:" << Info.getAlignment() << "\n";
+ OS << " FieldOffsets: [";
+ for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i) {
+ if (i) OS << ", ";
+ OS << Info.getFieldOffset(i);
+ }
+ OS << "]>\n";
+}
diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h
index a4bce75..f277c29 100644
--- a/lib/AST/RecordLayoutBuilder.h
+++ b/lib/AST/RecordLayoutBuilder.h
@@ -26,7 +26,7 @@ namespace clang {
class RecordDecl;
class ASTRecordLayoutBuilder {
- ASTContext &Ctx;
+ ASTContext &Context;
/// Size - The current size of the record layout.
uint64_t Size;
@@ -91,6 +91,7 @@ class ASTRecordLayoutBuilder {
void LayoutFields(const RecordDecl *D);
void LayoutField(const FieldDecl *D);
+ void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize);
void LayoutBitField(const FieldDecl *D);
/// DeterminePrimaryBase - Determine the primary base of the given class.
@@ -112,8 +113,11 @@ class ASTRecordLayoutBuilder {
/// LayoutNonVirtualBase - Lays out a single non-virtual base.
void LayoutNonVirtualBase(const CXXRecordDecl *RD);
+ void AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset,
+ const CXXRecordDecl *MostDerivedClass);
+
/// LayoutVirtualBases - Lays out all the virtual bases.
- void LayoutVirtualBases(const CXXRecordDecl *RD, uint64_t Offset,
+ void LayoutVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *MostDerivedClass);
/// LayoutVirtualBase - Lays out a single virtual base.
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 9702382..67fd74c 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Basic/TargetInfo.h"
#include <cstdio>
using namespace clang;
@@ -240,6 +241,8 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
// asm string.
std::string CurStringPiece;
+ bool HasVariants = !C.Target.hasNoAsmVariants();
+
while (1) {
// Done with the string?
if (CurPtr == StrEnd) {
@@ -251,9 +254,9 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
char CurChar = *CurPtr++;
switch (CurChar) {
case '$': CurStringPiece += "$$"; continue;
- case '{': CurStringPiece += "$("; continue;
- case '|': CurStringPiece += "$|"; continue;
- case '}': CurStringPiece += "$)"; continue;
+ case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue;
+ case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue;
+ case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue;
case '%':
break;
default:
@@ -389,26 +392,53 @@ ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
RParenLoc = RPL;
}
-
-ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc,
- SourceLocation rparenloc,
- ParmVarDecl *catchVarDecl, Stmt *atCatchStmt,
- Stmt *atCatchList)
-: Stmt(ObjCAtCatchStmtClass) {
- ExceptionDecl = catchVarDecl;
- SubExprs[BODY] = atCatchStmt;
- SubExprs[NEXT_CATCH] = NULL;
- // FIXME: O(N^2) in number of catch blocks.
- if (atCatchList) {
- ObjCAtCatchStmt *AtCatchList = static_cast<ObjCAtCatchStmt*>(atCatchList);
-
- while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt())
- AtCatchList = NextCatch;
-
- AtCatchList->SubExprs[NEXT_CATCH] = this;
- }
- AtCatchLoc = atCatchLoc;
- RParenLoc = rparenloc;
+ObjCAtTryStmt::ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
+ Stmt **CatchStmts, unsigned NumCatchStmts,
+ Stmt *atFinallyStmt)
+ : Stmt(ObjCAtTryStmtClass), AtTryLoc(atTryLoc),
+ NumCatchStmts(NumCatchStmts), HasFinally(atFinallyStmt != 0)
+{
+ Stmt **Stmts = getStmts();
+ Stmts[0] = atTryStmt;
+ for (unsigned I = 0; I != NumCatchStmts; ++I)
+ Stmts[I + 1] = CatchStmts[I];
+
+ if (HasFinally)
+ Stmts[NumCatchStmts + 1] = atFinallyStmt;
+}
+
+ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context,
+ SourceLocation atTryLoc,
+ Stmt *atTryStmt,
+ Stmt **CatchStmts,
+ unsigned NumCatchStmts,
+ Stmt *atFinallyStmt) {
+ unsigned Size = sizeof(ObjCAtTryStmt) +
+ (1 + NumCatchStmts + (atFinallyStmt != 0)) * sizeof(Stmt *);
+ void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>());
+ return new (Mem) ObjCAtTryStmt(atTryLoc, atTryStmt, CatchStmts, NumCatchStmts,
+ atFinallyStmt);
+}
+
+ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context,
+ unsigned NumCatchStmts,
+ bool HasFinally) {
+ unsigned Size = sizeof(ObjCAtTryStmt) +
+ (1 + NumCatchStmts + HasFinally) * sizeof(Stmt *);
+ void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>());
+ return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally);
+}
+
+SourceRange ObjCAtTryStmt::getSourceRange() const {
+ SourceLocation EndLoc;
+ if (HasFinally)
+ EndLoc = getFinallyStmt()->getLocEnd();
+ else if (NumCatchStmts)
+ EndLoc = getCatchStmt(NumCatchStmts - 1)->getLocEnd();
+ else
+ EndLoc = getTryBody()->getLocEnd();
+
+ return SourceRange(AtTryLoc, EndLoc);
}
CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
@@ -627,19 +657,18 @@ Stmt::child_iterator AsmStmt::child_end() {
}
// ObjCAtCatchStmt
-Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; }
-Stmt::child_iterator ObjCAtCatchStmt::child_end() {
- return &SubExprs[0]+END_EXPR;
-}
+Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &Body; }
+Stmt::child_iterator ObjCAtCatchStmt::child_end() { return &Body + 1; }
// ObjCAtFinallyStmt
Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; }
Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; }
// ObjCAtTryStmt
-Stmt::child_iterator ObjCAtTryStmt::child_begin() { return &SubStmts[0]; }
-Stmt::child_iterator ObjCAtTryStmt::child_end() {
- return &SubStmts[0]+END_EXPR;
+Stmt::child_iterator ObjCAtTryStmt::child_begin() { return getStmts(); }
+
+Stmt::child_iterator ObjCAtTryStmt::child_end() {
+ return getStmts() + 1 + NumCatchStmts + HasFinally;
}
// ObjCAtThrowStmt
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index ba6218b..ca62ed1 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -143,6 +143,7 @@ namespace {
void DumpCXXTemporary(CXXTemporary *Temporary);
// ObjC
+ void VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node);
void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
void VisitObjCMessageExpr(ObjCMessageExpr* Node);
void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
@@ -219,7 +220,7 @@ void StmtDumper::DumpDeclarator(Decl *D) {
// nodes are where they need to be.
if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
OS << "\"typedef " << localType->getUnderlyingType().getAsString()
- << " " << localType->getNameAsString() << "\"";
+ << ' ' << localType << '"';
} else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
OS << "\"";
// Emit storage class for vardecls.
@@ -299,9 +300,35 @@ void StmtDumper::VisitExpr(Expr *Node) {
DumpExpr(Node);
}
+static void DumpBasePath(llvm::raw_ostream &OS, CastExpr *Node) {
+ if (Node->getBasePath().empty())
+ return;
+
+ OS << " (";
+ bool First = true;
+ for (CXXBaseSpecifierArray::iterator I = Node->getBasePath().begin(),
+ E = Node->getBasePath().end(); I != E; ++I) {
+ const CXXBaseSpecifier *Base = *I;
+ if (!First)
+ OS << " -> ";
+
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+
+ if (Base->isVirtual())
+ OS << "virtual ";
+ OS << RD->getName();
+ First = false;
+ }
+
+ OS << ')';
+}
+
void StmtDumper::VisitCastExpr(CastExpr *Node) {
DumpExpr(Node);
- OS << " <" << Node->getCastKindName() << ">";
+ OS << " <" << Node->getCastKindName();
+ DumpBasePath(OS, Node);
+ OS << ">";
}
void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
@@ -328,15 +355,14 @@ void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
case Decl::ObjCClass: OS << "ObjCClass"; break;
}
- OS << "='" << Node->getDecl()->getNameAsString()
- << "' " << (void*)Node->getDecl();
+ OS << "='" << Node->getDecl() << "' " << (void*)Node->getDecl();
}
void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
DumpExpr(Node);
OS << " (";
if (!Node->requiresADL()) OS << "no ";
- OS << "ADL) = '" << Node->getName().getAsString() << "'";
+ OS << "ADL) = '" << Node->getName() << '\'';
UnresolvedLookupExpr::decls_iterator
I = Node->decls_begin(), E = Node->decls_end();
@@ -349,7 +375,7 @@ void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
DumpExpr(Node);
OS << " " << Node->getDecl()->getDeclKindName()
- << "Decl='" << Node->getDecl()->getNameAsString()
+ << "Decl='" << Node->getDecl()
<< "' " << (void*)Node->getDecl();
if (Node->isFreeIvar())
OS << " isFreeIvar";
@@ -408,7 +434,7 @@ void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
void StmtDumper::VisitMemberExpr(MemberExpr *Node) {
DumpExpr(Node);
OS << " " << (Node->isArrow() ? "->" : ".")
- << Node->getMemberDecl()->getNameAsString() << " "
+ << Node->getMemberDecl() << ' '
<< (void*)Node->getMemberDecl();
}
void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
@@ -452,7 +478,9 @@ void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
DumpExpr(Node);
OS << " " << Node->getCastName()
<< "<" << Node->getTypeAsWritten().getAsString() << ">"
- << " <" << Node->getCastKindName() << ">";
+ << " <" << Node->getCastKindName();
+ DumpBasePath(OS, Node);
+ OS << ">";
}
void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
@@ -506,8 +534,33 @@ void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) {
void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
DumpExpr(Node);
OS << " selector=" << Node->getSelector().getAsString();
- if (IdentifierInfo *clsName = Node->getClassName())
- OS << " class=" << clsName->getNameStart();
+ switch (Node->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ break;
+
+ case ObjCMessageExpr::Class:
+ OS << " class=";
+ DumpType(Node->getClassReceiver());
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ OS << " super (instance)";
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ OS << " super (class)";
+ break;
+ }
+}
+
+void StmtDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node) {
+ DumpStmt(Node);
+ if (VarDecl *CatchParam = Node->getCatchParamDecl()) {
+ OS << " catch parm = ";
+ DumpDeclarator(CatchParam);
+ } else {
+ OS << " catch all";
+ }
}
void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
@@ -525,14 +578,13 @@ void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
DumpExpr(Node);
- OS << " " << Node->getProtocol()->getNameAsString();
+ OS << ' ' << Node->getProtocol();
}
void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
DumpExpr(Node);
- OS << " Kind=PropertyRef Property=\""
- << Node->getProperty()->getNameAsString() << "\"";
+ OS << " Kind=PropertyRef Property=\"" << Node->getProperty() << '"';
}
void StmtDumper::VisitObjCImplicitSetterGetterRefExpr(
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index da43878..52f627d 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/PrettyPrinter.h"
#include "llvm/Support/Format.h"
+#include "clang/AST/Expr.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -388,11 +389,8 @@ void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) {
OS << "\n";
}
- for (ObjCAtCatchStmt *catchStmt =
- static_cast<ObjCAtCatchStmt *>(Node->getCatchStmts());
- catchStmt;
- catchStmt =
- static_cast<ObjCAtCatchStmt *>(catchStmt->getNextCatchStmt())) {
+ for (unsigned I = 0, N = Node->getNumCatchStmts(); I != N; ++I) {
+ ObjCAtCatchStmt *catchStmt = Node->getCatchStmt(I);
Indent() << "@catch(";
if (catchStmt->getCatchParamDecl()) {
if (Decl *DS = catchStmt->getCatchParamDecl())
@@ -474,7 +472,7 @@ void StmtPrinter::VisitExpr(Expr *Node) {
void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
- OS << Node->getDecl()->getNameAsString();
+ OS << Node->getDecl();
if (Node->hasExplicitTemplateArgumentList())
OS << TemplateSpecializationType::PrintTemplateArgumentList(
Node->getTemplateArgs(),
@@ -509,7 +507,7 @@ void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->" : ".");
}
- OS << Node->getDecl()->getNameAsString();
+ OS << Node->getDecl();
}
void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
@@ -527,7 +525,7 @@ void StmtPrinter::VisitObjCImplicitSetterGetterRefExpr(
OS << ".";
}
if (Node->getGetterMethod())
- OS << Node->getGetterMethod()->getNameAsString();
+ OS << Node->getGetterMethod();
}
@@ -695,7 +693,7 @@ bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) {
} else {
MemberExpr *ME = cast<MemberExpr>(E);
bool IsFirst = PrintOffsetOfDesignator(ME->getBase());
- OS << (IsFirst ? "" : ".") << ME->getMemberDecl()->getNameAsString();
+ OS << (IsFirst ? "" : ".") << ME->getMemberDecl();
return false;
}
}
@@ -706,6 +704,39 @@ void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) {
OS << ")";
}
+void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) {
+ OS << "__builtin_offsetof(";
+ OS << Node->getTypeSourceInfo()->getType().getAsString() << ", ";
+ bool PrintedSomething = false;
+ for (unsigned i = 0, n = Node->getNumComponents(); i < n; ++i) {
+ OffsetOfExpr::OffsetOfNode ON = Node->getComponent(i);
+ if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Array) {
+ // Array node
+ OS << "[";
+ PrintExpr(Node->getIndexExpr(ON.getArrayExprIndex()));
+ OS << "]";
+ PrintedSomething = true;
+ continue;
+ }
+
+ // Skip implicit base indirections.
+ if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Base)
+ continue;
+
+ // Field or identifier node.
+ IdentifierInfo *Id = ON.getFieldName();
+ if (!Id)
+ continue;
+
+ if (PrintedSomething)
+ OS << ".";
+ else
+ PrintedSomething = true;
+ OS << Id->getName();
+ }
+ OS << ")";
+}
+
void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
OS << (Node->isSizeOf() ? "sizeof" : "__alignof");
if (Node->isArgumentType())
@@ -746,7 +777,7 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
- OS << Node->getMemberDecl()->getNameAsString();
+ OS << Node->getMemberDecl();
if (Node->hasExplicitTemplateArgumentList())
OS << TemplateSpecializationType::PrintTemplateArgumentList(
@@ -1242,14 +1273,26 @@ void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
}
void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
- OS << "@protocol(" << Node->getProtocol()->getNameAsString() << ')';
+ OS << "@protocol(" << Node->getProtocol() << ')';
}
void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
OS << "[";
- Expr *receiver = Mess->getReceiver();
- if (receiver) PrintExpr(receiver);
- else OS << Mess->getClassName()->getName();
+ switch (Mess->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ PrintExpr(Mess->getInstanceReceiver());
+ break;
+
+ case ObjCMessageExpr::Class:
+ OS << Mess->getClassReceiver().getAsString(Policy);
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ case ObjCMessageExpr::SuperClass:
+ OS << "Super";
+ break;
+ }
+
OS << ' ';
Selector selector = Mess->getSelector();
if (selector.isUnarySelector()) {
@@ -1304,7 +1347,7 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
}
void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) {
- OS << Node->getDecl()->getNameAsString();
+ OS << Node->getDecl();
}
//===----------------------------------------------------------------------===//
// Stmt method implementations
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 3a19ec2..d45bb2f 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -261,6 +261,34 @@ void StmtProfiler::VisitUnaryOperator(UnaryOperator *S) {
ID.AddInteger(S->getOpcode());
}
+void StmtProfiler::VisitOffsetOfExpr(OffsetOfExpr *S) {
+ VisitType(S->getTypeSourceInfo()->getType());
+ unsigned n = S->getNumComponents();
+ for (unsigned i = 0; i < n; ++i) {
+ const OffsetOfExpr::OffsetOfNode& ON = S->getComponent(i);
+ ID.AddInteger(ON.getKind());
+ switch (ON.getKind()) {
+ case OffsetOfExpr::OffsetOfNode::Array:
+ // Expressions handled below.
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Field:
+ VisitDecl(ON.getField());
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Identifier:
+ ID.AddPointer(ON.getFieldName());
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Base:
+ // These nodes are implicit, and therefore don't need profiling.
+ break;
+ }
+ }
+
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isSizeOf());
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index b56c0ceb..14722f7 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -15,9 +15,11 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+using namespace llvm;
TemplateDecl *TemplateName::getAsTemplateDecl() const {
if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
@@ -45,13 +47,13 @@ void
TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
bool SuppressNNS) const {
if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
- OS << Template->getNameAsString();
+ OS << Template;
else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
if (!SuppressNNS)
QTN->getQualifier()->print(OS, Policy);
if (QTN->hasTemplateKeyword())
OS << "template ";
- OS << QTN->getDecl()->getNameAsString();
+ OS << QTN->getDecl();
} else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
if (!SuppressNNS && DTN->getQualifier())
DTN->getQualifier()->print(OS, Policy);
@@ -64,6 +66,18 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
}
}
+const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
+ TemplateName N) {
+ std::string NameStr;
+ raw_string_ostream OS(NameStr);
+ LangOptions LO;
+ LO.CPlusPlus = true;
+ LO.Bool = true;
+ N.print(OS, PrintingPolicy(LO));
+ OS.flush();
+ return DB << NameStr;
+}
+
void TemplateName::dump() const {
LangOptions LO; // FIXME!
LO.CPlusPlus = true;
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 27a277d..05e7fdc 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -225,6 +225,11 @@ bool Type::isStructureType() const {
return RT->getDecl()->isStruct();
return false;
}
+bool Type::isStructureOrClassType() const {
+ if (const RecordType *RT = getAs<RecordType>())
+ return RT->getDecl()->isStruct() || RT->getDecl()->isClass();
+ return false;
+}
bool Type::isVoidPointerType() const {
if (const PointerType *PT = getAs<PointerType>())
return PT->getPointeeType()->isVoidType();
@@ -410,6 +415,16 @@ const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const {
return 0;
}
+CXXRecordDecl *Type::getAsCXXRecordDecl() const {
+ if (const RecordType *RT = getAs<RecordType>())
+ return dyn_cast<CXXRecordDecl>(RT->getDecl());
+ else if (const InjectedClassNameType *Injected
+ = getAs<InjectedClassNameType>())
+ return Injected->getDecl();
+
+ return 0;
+}
+
bool Type::isIntegerType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
@@ -999,12 +1014,13 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) {
TemplateSpecializationType::
TemplateSpecializationType(ASTContext &Context, TemplateName T,
+ bool IsCurrentInstantiation,
const TemplateArgument *Args,
unsigned NumArgs, QualType Canon)
: Type(TemplateSpecialization,
Canon.isNull()? QualType(this, 0) : Canon,
T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)),
- Context(Context),
+ ContextAndCurrentInstantiation(&Context, IsCurrentInstantiation),
Template(T), NumArgs(NumArgs) {
assert((!Canon.isNull() ||
T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) &&
@@ -1039,9 +1055,11 @@ TemplateSpecializationType::getArg(unsigned Idx) const {
void
TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
TemplateName T,
+ bool IsCurrentInstantiation,
const TemplateArgument *Args,
unsigned NumArgs,
ASTContext &Context) {
+ ID.AddBoolean(IsCurrentInstantiation);
T.Profile(ID);
for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
Args[Idx].Profile(ID, Context);
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 340e373..915d7af 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -29,7 +29,7 @@ namespace {
public:
explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { }
-
+
void Print(QualType T, std::string &S);
void AppendScope(DeclContext *DC, std::string &S);
void PrintTag(TagDecl *T, std::string &S);
@@ -546,7 +546,7 @@ void TypePrinter::PrintTemplateSpecialization(
void TypePrinter::PrintInjectedClassName(const InjectedClassNameType *T,
std::string &S) {
- PrintTemplateSpecialization(T->getUnderlyingTST(), S);
+ PrintTemplateSpecialization(T->getInjectedTST(), S);
}
void TypePrinter::PrintQualifiedName(const QualifiedNameType *T,
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index f94f6b3..7f71e0a 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -46,7 +46,7 @@ public:
AddStmtChoice(Kind kind) : k(kind) {}
bool alwaysAdd() const { return (unsigned)k & 0x1; }
- bool asLValue() const { return k >= AlwaysAddAsLValue; }
+ bool asLValue() const { return k >= AsLValueNotAlwaysAdd; }
private:
Kind k;
@@ -108,16 +108,16 @@ private:
CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc);
CFGBlock *VisitBlockExpr(BlockExpr* E, AddStmtChoice asc);
CFGBlock *VisitBreakStmt(BreakStmt *B);
+ CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S);
+ CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
+ CFGBlock *VisitCXXTryStmt(CXXTryStmt *S);
+ CFGBlock *VisitCXXMemberCallExpr(CXXMemberCallExpr *C, AddStmtChoice asc);
CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc);
CFGBlock *VisitCaseStmt(CaseStmt *C);
CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc);
CFGBlock *VisitCompoundStmt(CompoundStmt *C);
- CFGBlock *VisitConditionalOperator(ConditionalOperator *C,
- AddStmtChoice asc);
+ CFGBlock *VisitConditionalOperator(ConditionalOperator *C, AddStmtChoice asc);
CFGBlock *VisitContinueStmt(ContinueStmt *C);
- CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S);
- CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
- CFGBlock *VisitCXXTryStmt(CXXTryStmt *S);
CFGBlock *VisitDeclStmt(DeclStmt *DS);
CFGBlock *VisitDeclSubExpr(Decl* D);
CFGBlock *VisitDefaultStmt(DefaultStmt *D);
@@ -127,6 +127,7 @@ private:
CFGBlock *VisitIfStmt(IfStmt *I);
CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I);
CFGBlock *VisitLabelStmt(LabelStmt *L);
+ CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc);
CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S);
CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S);
CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S);
@@ -337,6 +338,10 @@ bool CFGBuilder::FinishBlock(CFGBlock* B) {
/// DeclStmts (which may contain nested control-flow).
CFGBlock* CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
tryAgain:
+ if (!S) {
+ badCFG = true;
+ return 0;
+ }
switch (S->getStmtClass()) {
default:
return VisitStmt(S, asc);
@@ -374,6 +379,9 @@ tryAgain:
case Stmt::CXXCatchStmtClass:
return VisitCXXCatchStmt(cast<CXXCatchStmt>(S));
+ case Stmt::CXXMemberCallExprClass:
+ return VisitCXXMemberCallExpr(cast<CXXMemberCallExpr>(S), asc);
+
case Stmt::CXXThrowExprClass:
return VisitCXXThrowExpr(cast<CXXThrowExpr>(S));
@@ -404,6 +412,9 @@ tryAgain:
case Stmt::LabelStmtClass:
return VisitLabelStmt(cast<LabelStmt>(S));
+ case Stmt::MemberExprClass:
+ return VisitMemberExpr(cast<MemberExpr>(S), asc);
+
case Stmt::ObjCAtCatchStmtClass:
return VisitObjCAtCatchStmt(cast<ObjCAtCatchStmt>(S));
@@ -491,8 +502,16 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
Succ = ConfluenceBlock;
Block = NULL;
CFGBlock* RHSBlock = addStmt(B->getRHS());
- if (!FinishBlock(RHSBlock))
- return 0;
+
+ if (RHSBlock) {
+ if (!FinishBlock(RHSBlock))
+ return 0;
+ }
+ else {
+ // Create an empty block for cases where the RHS doesn't require
+ // any explicit statements in the CFG.
+ RHSBlock = createBlock();
+ }
// See if this is a known constant.
TryResult KnownVal = TryEvaluateBool(B->getLHS());
@@ -627,15 +646,18 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
if (!FinishBlock(ConfluenceBlock))
return 0;
+ asc = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue
+ : AddStmtChoice::AlwaysAdd;
+
Succ = ConfluenceBlock;
Block = NULL;
- CFGBlock* LHSBlock = addStmt(C->getLHS());
+ CFGBlock* LHSBlock = addStmt(C->getLHS(), asc);
if (!FinishBlock(LHSBlock))
return 0;
Succ = ConfluenceBlock;
Block = NULL;
- CFGBlock* RHSBlock = addStmt(C->getRHS());
+ CFGBlock* RHSBlock = addStmt(C->getRHS(), asc);
if (!FinishBlock(RHSBlock))
return 0;
@@ -676,6 +698,9 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C,
if (!FinishBlock(ConfluenceBlock))
return 0;
+ asc = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue
+ : AddStmtChoice::AlwaysAdd;
+
// Create a block for the LHS expression if there is an LHS expression. A
// GCC extension allows LHS to be NULL, causing the condition to be the
// value that is returned instead.
@@ -684,7 +709,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C,
Block = NULL;
CFGBlock* LHSBlock = NULL;
if (C->getLHS()) {
- LHSBlock = addStmt(C->getLHS());
+ LHSBlock = addStmt(C->getLHS(), asc);
if (!FinishBlock(LHSBlock))
return 0;
Block = NULL;
@@ -692,7 +717,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C,
// Create the block for the RHS expression.
Succ = ConfluenceBlock;
- CFGBlock* RHSBlock = addStmt(C->getRHS());
+ CFGBlock* RHSBlock = addStmt(C->getRHS(), asc);
if (!FinishBlock(RHSBlock))
return 0;
@@ -1074,6 +1099,16 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
}
}
+CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) {
+ if (asc.alwaysAdd()) {
+ autoCreateBlock();
+ AppendStmt(Block, M, asc);
+ }
+ return Visit(M->getBase(),
+ M->isArrow() ? AddStmtChoice::NotAlwaysAdd
+ : AddStmtChoice::AsLValueNotAlwaysAdd);
+}
+
CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
// Objective-C fast enumeration 'for' statements:
// http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC
@@ -1694,6 +1729,15 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) {
return CatchBlock;
}
+CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C,
+ AddStmtChoice asc) {
+ AddStmtChoice::Kind K = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue
+ : AddStmtChoice::AlwaysAdd;
+ autoCreateBlock();
+ AppendStmt(Block, C, AddStmtChoice(K));
+ return VisitChildren(C);
+}
+
CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) {
// Lazily create the indirect-goto dispatch block if there isn't one already.
CFGBlock* IBlock = cfg->getIndirectGotoBlock();
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 2b7fcd0..1870195 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -11,24 +11,24 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/PartialDiagnostic.h"
-
-#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Parse/ParseDiagnostic.h"
#include "clang/AST/ASTDiagnostic.h"
-#include "clang/Sema/SemaDiagnostic.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Analysis/AnalysisDiagnostic.h"
-#include "clang/Driver/DriverDiagnostic.h"
-
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
+
#include <vector>
#include <map>
#include <cstring>
@@ -223,9 +223,12 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
ErrorOccurred = false;
FatalErrorOccurred = false;
- NumDiagnostics = 0;
-
+ ErrorLimit = 0;
+ TemplateBacktraceLimit = 0;
+
+ NumWarnings = 0;
NumErrors = 0;
+ NumErrorsSuppressed = 0;
CustomDiagInfo = 0;
CurDiagID = ~0U;
LastDiagLevel = Ignored;
@@ -286,11 +289,18 @@ bool Diagnostic::isBuiltinNote(unsigned DiagID) {
}
/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
-/// ID is for an extension of some sort.
+/// ID is for an extension of some sort. This also returns EnabledByDefault,
+/// which is set to indicate whether the diagnostic is ignored by default (in
+/// which case -pedantic enables it) or treated as a warning/error by default.
///
-bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID) {
- return DiagID < diag::DIAG_UPPER_LIMIT &&
- getBuiltinDiagClass(DiagID) == CLASS_EXTENSION;
+bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID,
+ bool &EnabledByDefault) {
+ if (DiagID >= diag::DIAG_UPPER_LIMIT ||
+ getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
+ return false;
+
+ EnabledByDefault = StaticDiagInfo[DiagID].Mapping != diag::MAP_IGNORE;
+ return true;
}
@@ -529,8 +539,14 @@ bool Diagnostic::ProcessDiag() {
// If a fatal error has already been emitted, silence all subsequent
// diagnostics.
- if (FatalErrorOccurred)
+ if (FatalErrorOccurred) {
+ if (DiagLevel >= Diagnostic::Error) {
+ ++NumErrors;
+ ++NumErrorsSuppressed;
+ }
+
return false;
+ }
// If the client doesn't care about this message, don't issue it. If this is
// a note and the last real diagnostic was ignored, ignore it too.
@@ -551,11 +567,20 @@ bool Diagnostic::ProcessDiag() {
if (DiagLevel >= Diagnostic::Error) {
ErrorOccurred = true;
++NumErrors;
+
+ // If we've emitted a lot of errors, emit a fatal error after it to stop a
+ // flood of bogus errors.
+ if (ErrorLimit && NumErrors >= ErrorLimit &&
+ DiagLevel == Diagnostic::Error)
+ SetDelayedDiagnostic(diag::fatal_too_many_errors);
}
// Finally, report it.
Client->HandleDiagnostic(DiagLevel, Info);
- if (Client->IncludeInDiagnosticCounts()) ++NumDiagnostics;
+ if (Client->IncludeInDiagnosticCounts()) {
+ if (DiagLevel == Diagnostic::Warning)
+ ++NumWarnings;
+ }
CurDiagID = ~0U;
@@ -1026,8 +1051,15 @@ static void WriteSourceLocation(llvm::raw_ostream &OS,
Location = SM->getInstantiationLoc(Location);
std::pair<FileID, unsigned> Decomposed = SM->getDecomposedLoc(Location);
-
- WriteString(OS, SM->getFileEntryForID(Decomposed.first)->getName());
+
+ const FileEntry *FE = SM->getFileEntryForID(Decomposed.first);
+ if (FE)
+ WriteString(OS, FE->getName());
+ else {
+ // Fallback to using the buffer name when there is no entry.
+ WriteString(OS, SM->getBuffer(Decomposed.first)->getBufferIdentifier());
+ }
+
WriteUnsigned(OS, SM->getLineNumber(Decomposed.first, Decomposed.second));
WriteUnsigned(OS, SM->getColumnNumber(Decomposed.first, Decomposed.second));
}
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 3da19ca..ed0de8c 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -78,9 +78,9 @@ namespace {
/// identifiers because they are language keywords. This causes the lexer to
/// automatically map matching identifiers to specialized token codes.
///
-/// The C90/C99/CPP/CPP0x flags are set to 0 if the token should be
+/// The C90/C99/CPP/CPP0x flags are set to 2 if the token should be
/// enabled in the specified langauge, set to 1 if it is an extension
-/// in the specified language, and set to 2 if disabled in the
+/// in the specified language, and set to 0 if disabled in the
/// specified language.
static void AddKeyword(llvm::StringRef Keyword,
tok::TokenKind TokenCode, unsigned Flags,
@@ -90,7 +90,7 @@ static void AddKeyword(llvm::StringRef Keyword,
else if (LangOpts.CPlusPlus && (Flags & KEYCXX)) AddResult = 2;
else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2;
else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2;
- else if (LangOpts.GNUMode && (Flags & KEYGNU)) AddResult = 1;
+ else if (LangOpts.GNUKeywords && (Flags & KEYGNU)) AddResult = 1;
else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1;
else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2;
else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2;
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 27cb9be..3ecab1d 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -60,6 +60,8 @@ void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) {
}
const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
+ const SourceManager &SM,
+ SourceLocation Loc,
bool *Invalid) const {
if (Invalid)
*Invalid = false;
@@ -94,22 +96,67 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
Diag.SetDelayedDiagnostic(diag::err_cannot_open_file,
Entry->getName(), ErrorStr);
else
- Diag.Report(diag::err_cannot_open_file)
+ Diag.Report(FullSourceLoc(Loc, SM), diag::err_cannot_open_file)
<< Entry->getName() << ErrorStr;
Buffer.setInt(true);
+
+ // FIXME: This conditionalization is horrible, but we see spurious failures
+ // in the test suite due to this warning and no one has had time to hunt it
+ // down. So for now, we just don't emit this diagnostic on Win32, and hope
+ // nothing bad happens.
+ //
+ // PR6812.
+#if !defined(LLVM_ON_WIN32)
} else if (FileInfo.st_size != Entry->getSize() ||
FileInfo.st_mtime != Entry->getModificationTime()) {
- // Check that the file's size, modification time, and inode are
- // the same as in the file entry (which may have come from a
- // stat cache).
+ // Check that the file's size and modification time are the same
+ // as in the file entry (which may have come from a stat cache).
if (Diag.isDiagnosticInFlight())
- Diag.SetDelayedDiagnostic(diag::err_file_modified,
+ Diag.SetDelayedDiagnostic(diag::err_file_modified,
Entry->getName());
- else
- Diag.Report(diag::err_file_modified) << Entry->getName();
+ else
+ Diag.Report(FullSourceLoc(Loc, SM), diag::err_file_modified)
+ << Entry->getName();
Buffer.setInt(true);
+#endif
+ }
+
+ // If the buffer is valid, check to see if it has a UTF Byte Order Mark
+ // (BOM). We only support UTF-8 without a BOM right now. See
+ // http://en.wikipedia.org/wiki/Byte_order_mark for more information.
+ if (!Buffer.getInt()) {
+ llvm::StringRef BufStr = Buffer.getPointer()->getBuffer();
+ const char *BOM = 0;
+ if (BufStr.startswith("\xFE\xBB\xBF"))
+ BOM = "UTF-8";
+ else if (BufStr.startswith("\xFE\xFF"))
+ BOM = "UTF-16 (BE)";
+ else if (BufStr.startswith("\xFF\xFE"))
+ BOM = "UTF-16 (LE)";
+ else if (BufStr.startswith(llvm::StringRef("\x00\x00\xFE\xFF", 4)))
+ BOM = "UTF-32 (BE)";
+ else if (BufStr.startswith(llvm::StringRef("\xFF\xFE\x00\x00", 4)))
+ BOM = "UTF-32 (LE)";
+ else if (BufStr.startswith("\x2B\x2F\x76"))
+ BOM = "UTF-7";
+ else if (BufStr.startswith("\xF7\x64\x4C"))
+ BOM = "UTF-1";
+ else if (BufStr.startswith("\xDD\x73\x66\x73"))
+ BOM = "UTF-EBCDIC";
+ else if (BufStr.startswith("\x0E\xFE\xFF"))
+ BOM = "SDSU";
+ else if (BufStr.startswith("\xFB\xEE\x28"))
+ BOM = "BOCU-1";
+ else if (BufStr.startswith("\x84\x31\x95\x33"))
+ BOM = "BOCU-1";
+
+ if (BOM) {
+ Diag.Report(FullSourceLoc(Loc, SM), diag::err_unsupported_bom)
+ << BOM << Entry->getName();
+ Buffer.setInt(1);
+ }
}
}
@@ -470,7 +517,7 @@ SourceManager::getMemoryBufferForFile(const FileEntry *File,
bool *Invalid) {
const SrcMgr::ContentCache *IR = getOrCreateContentCache(File);
assert(IR && "getOrCreateContentCache() cannot return NULL");
- return IR->getBuffer(Diag, Invalid);
+ return IR->getBuffer(Diag, *this, SourceLocation(), Invalid);
}
bool SourceManager::overrideFileContents(const FileEntry *SourceFile,
@@ -717,8 +764,8 @@ const char *SourceManager::getCharacterData(SourceLocation SL,
// Note that calling 'getBuffer()' may lazily page in a source file.
bool CharDataInvalid = false;
const llvm::MemoryBuffer *Buffer
- = getSLocEntry(LocInfo.first).getFile().getContentCache()->getBuffer(Diag,
- &CharDataInvalid);
+ = getSLocEntry(LocInfo.first).getFile().getContentCache()
+ ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid);
if (Invalid)
*Invalid = CharDataInvalid;
return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second);
@@ -757,14 +804,16 @@ unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc,
return getColumnNumber(LocInfo.first, LocInfo.second, Invalid);
}
-static DISABLE_INLINE void ComputeLineNumbers(Diagnostic &Diag,
- ContentCache* FI,
- llvm::BumpPtrAllocator &Alloc,
- bool &Invalid);
-static void ComputeLineNumbers(Diagnostic &Diag, ContentCache* FI,
- llvm::BumpPtrAllocator &Alloc, bool &Invalid) {
+static DISABLE_INLINE void
+ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI,
+ llvm::BumpPtrAllocator &Alloc,
+ const SourceManager &SM, bool &Invalid);
+static void ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI,
+ llvm::BumpPtrAllocator &Alloc,
+ const SourceManager &SM, bool &Invalid) {
// Note that calling 'getBuffer()' may lazily page in the file.
- const MemoryBuffer *Buffer = FI->getBuffer(Diag, &Invalid);
+ const MemoryBuffer *Buffer = FI->getBuffer(Diag, SM, SourceLocation(),
+ &Invalid);
if (Invalid)
return;
@@ -825,7 +874,7 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
/// SourceLineCache for it on demand.
if (Content->SourceLineCache == 0) {
bool MyInvalid = false;
- ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid);
+ ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid);
if (Invalid)
*Invalid = MyInvalid;
if (MyInvalid)
@@ -991,8 +1040,11 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
// To get the source name, first consult the FileEntry (if one exists)
// before the MemBuffer as this will avoid unnecessarily paging in the
// MemBuffer.
- const char *Filename =
- C->Entry ? C->Entry->getName() : C->getBuffer(Diag)->getBufferIdentifier();
+ const char *Filename;
+ if (C->Entry)
+ Filename = C->Entry->getName();
+ else
+ Filename = C->getBuffer(Diag, *this)->getBufferIdentifier();
unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second);
unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second);
SourceLocation IncludeLoc = FI.getIncludeLoc();
@@ -1050,7 +1102,7 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
/// SourceLineCache for it on demand.
if (Content->SourceLineCache == 0) {
bool MyInvalid = false;
- ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid);
+ ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid);
if (MyInvalid)
return SourceLocation();
}
@@ -1082,15 +1134,15 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
return SourceLocation();
if (Line > Content->NumLines) {
- unsigned Size = Content->getBuffer(Diag)->getBufferSize();
+ unsigned Size = Content->getBuffer(Diag, *this)->getBufferSize();
if (Size > 0)
--Size;
return getLocForStartOfFile(FirstFID).getFileLocWithOffset(Size);
}
unsigned FilePos = Content->SourceLineCache[Line - 1];
- const char *Buf = Content->getBuffer(Diag)->getBufferStart() + FilePos;
- unsigned BufLength = Content->getBuffer(Diag)->getBufferEnd() - Buf;
+ const char *Buf = Content->getBuffer(Diag, *this)->getBufferStart() + FilePos;
+ unsigned BufLength = Content->getBuffer(Diag, *this)->getBufferEnd() - Buf;
unsigned i = 0;
// Check that the given column is valid.
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index 136089f..4c0c59a 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -20,10 +20,10 @@ using namespace clang;
// TargetInfo Constructor.
TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
- // Set defaults. Defaults are set for a 32-bit RISC platform,
- // like PPC or SPARC.
- // These should be overridden by concrete targets as needed.
+ // Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or
+ // SPARC. These should be overridden by concrete targets as needed.
TLSSupported = true;
+ NoAsmVariants = false;
PointerWidth = PointerAlign = 32;
IntWidth = IntAlign = 32;
LongWidth = LongAlign = 32;
@@ -45,6 +45,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
Char32Type = UnsignedInt;
Int64Type = SignedLongLong;
SigAtomicType = SignedInt;
+ UseBitFieldTypeAlignment = true;
FloatFormat = &llvm::APFloat::IEEEsingle;
DoubleFormat = &llvm::APFloat::IEEEdouble;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
@@ -142,9 +143,10 @@ bool TargetInfo::isTypeSigned(IntType T) const {
/// Apply changes to the target information with respect to certain
/// language options which change the target configuration.
void TargetInfo::setForcedLangOptions(LangOptions &Opts) {
- if (Opts.ShortWChar) {
+ if (Opts.NoBitFieldTypeAlign)
+ UseBitFieldTypeAlignment = false;
+ if (Opts.ShortWChar)
WCharType = UnsignedShort;
- }
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 1797804..3d5048c 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -219,6 +219,8 @@ protected:
Builder.defineMacro("__ELF__");
if (Opts.POSIXThreads)
Builder.defineMacro("_REENTRANT");
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
}
public:
LinuxTargetInfo(const std::string& triple)
@@ -1221,6 +1223,27 @@ public:
Builder.defineMacro("__CYGWIN__");
Builder.defineMacro("__CYGWIN32__");
DefineStd(Builder, "unix", Opts);
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-32 Haiku target
+class HaikuX86_32TargetInfo : public X86_32TargetInfo {
+public:
+ HaikuX86_32TargetInfo(const std::string& triple)
+ : X86_32TargetInfo(triple) {
+ SizeType = UnsignedLong;
+ IntPtrType = SignedLong;
+ PtrDiffType = SignedLong;
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ X86_32TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__INTEL__");
+ Builder.defineMacro("__HAIKU__");
}
};
} // end anonymous namespace
@@ -1373,6 +1396,10 @@ public:
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
+ // {} in inline assembly are neon specifiers, not assembly variant
+ // specifiers.
+ NoAsmVariants = true;
+
// FIXME: Should we just treat this as a feature?
IsThumb = getTriple().getArchName().startswith("thumb");
if (IsThumb) {
@@ -1397,6 +1424,10 @@ public:
DoubleAlign = LongLongAlign = LongDoubleAlign = 32;
SizeType = UnsignedLong;
+ // Do not respect the alignment of bit-field types when laying out
+ // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc.
+ UseBitFieldTypeAlignment = false;
+
if (IsThumb) {
DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
"i64:32:32-f32:32:32-f64:32:32-"
@@ -2351,6 +2382,8 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new MinGWX86_32TargetInfo(T);
case llvm::Triple::Win32:
return new VisualStudioWindowsX86_32TargetInfo(T);
+ case llvm::Triple::Haiku:
+ return new HaikuX86_32TargetInfo(T);
default:
return new X86_32TargetInfo(T);
}
diff --git a/lib/Checker/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp
index 810d0fb..e7275ca 100644
--- a/lib/Checker/BasicObjCFoundationChecks.cpp
+++ b/lib/Checker/BasicObjCFoundationChecks.cpp
@@ -31,13 +31,22 @@
using namespace clang;
static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
- const Expr* Receiver = ME->getReceiver();
-
- if (!Receiver)
- return NULL;
+ QualType T;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ T = ME->getInstanceReceiver()->getType();
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ T = ME->getSuperType();
+ break;
+
+ case ObjCMessageExpr::Class:
+ case ObjCMessageExpr::SuperClass:
+ return 0;
+ }
- if (const ObjCObjectPointerType *PT =
- Receiver->getType()->getAs<ObjCObjectPointerType>())
+ if (const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>())
return PT->getInterfaceType();
return NULL;
@@ -509,11 +518,21 @@ public:
void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
const ObjCMessageExpr *ME) {
-
- const IdentifierInfo *ClsName = ME->getClassName();
- if (!ClsName)
+ ObjCInterfaceDecl *Class = 0;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Class:
+ Class = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ Class = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+
+ case ObjCMessageExpr::Instance:
+ case ObjCMessageExpr::SuperInstance:
return;
-
+ }
+
Selector S = ME->getSelector();
if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
return;
@@ -531,7 +550,7 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
llvm::raw_svector_ostream os(buf);
os << "The '" << S.getAsString() << "' message should be sent to instances "
- "of class '" << ClsName->getName()
+ "of class '" << Class->getName()
<< "' and not the class directly";
RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp
index 7c53991..34470af 100644
--- a/lib/Checker/BasicStore.cpp
+++ b/lib/Checker/BasicStore.cpp
@@ -401,7 +401,7 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR,
const VarDecl *VD = VR->getDecl();
// BasicStore does not model arrays and structs.
- if (VD->getType()->isArrayType() || VD->getType()->isStructureType())
+ if (VD->getType()->isArrayType() || VD->getType()->isStructureOrClassType())
return store;
if (VD->hasGlobalStorage()) {
diff --git a/lib/Checker/BugReporter.cpp b/lib/Checker/BugReporter.cpp
index 4475872..3bcc03f 100644
--- a/lib/Checker/BugReporter.cpp
+++ b/lib/Checker/BugReporter.cpp
@@ -607,7 +607,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (D) {
GetRawInt = false;
- os << D->getNameAsString();
+ os << D;
}
}
diff --git a/lib/Checker/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp
index 06cee5b..776e12b 100644
--- a/lib/Checker/BugReporterVisitors.cpp
+++ b/lib/Checker/BugReporterVisitors.cpp
@@ -47,14 +47,6 @@ const Stmt *clang::bugreporter::GetDerefExpr(const ExplodedNode *N) {
}
const Stmt*
-clang::bugreporter::GetReceiverExpr(const ExplodedNode *N){
- const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
- if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
- return ME->getReceiver();
- return NULL;
-}
-
-const Stmt*
clang::bugreporter::GetDenomExpr(const ExplodedNode *N) {
const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
@@ -144,7 +136,7 @@ public:
if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- os << "Variable '" << VR->getDecl()->getNameAsString() << "' ";
+ os << "Variable '" << VR->getDecl() << "' ";
}
else
return NULL;
@@ -206,7 +198,7 @@ public:
return NULL;
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- os << '\'' << VR->getDecl()->getNameAsString() << '\'';
+ os << '\'' << VR->getDecl() << '\'';
}
else
return NULL;
@@ -402,7 +394,7 @@ public:
const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
if (!ME)
return 0;
- const Expr *Receiver = ME->getReceiver();
+ const Expr *Receiver = ME->getInstanceReceiver();
if (!Receiver)
return 0;
const GRState *state = N->getState();
diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp
index 3c4a27c..d26ee1d 100644
--- a/lib/Checker/CFRefCount.cpp
+++ b/lib/Checker/CFRefCount.cpp
@@ -603,12 +603,33 @@ public:
Selector S = ME->getSelector();
- if (Expr* Receiver = ME->getReceiver()) {
- const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
- return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
+ const ObjCInterfaceDecl* OD = 0;
+ bool IsInstanceMessage = false;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ OD = getReceiverDecl(ME->getInstanceReceiver());
+ IsInstanceMessage = true;
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ IsInstanceMessage = true;
+ OD = ME->getSuperType()->getAs<ObjCObjectPointerType>()
+ ->getInterfaceDecl();
+ break;
+
+ case ObjCMessageExpr::Class:
+ OD = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ OD = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
}
- return M[ObjCSummaryKey(ME->getClassName(), S)];
+ if (IsInstanceMessage)
+ return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
+
+ return M[ObjCSummaryKey(OD->getIdentifier(), S)];
}
RetainSummary*& operator[](ObjCSummaryKey K) {
@@ -836,7 +857,7 @@ public:
RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME,
const ObjCInterfaceDecl* ID) {
- return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(),
+ return getInstanceMethodSummary(ME->getSelector(), 0,
ID, ME->getMethodDecl(), ME->getType());
}
@@ -851,8 +872,21 @@ public:
QualType RetTy);
RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) {
- return getClassMethodSummary(ME->getSelector(), ME->getClassName(),
- ME->getClassInfo().Decl,
+ ObjCInterfaceDecl *Class = 0;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Class:
+ case ObjCMessageExpr::SuperClass:
+ Class = ME->getReceiverInterface();
+ break;
+
+ case ObjCMessageExpr::Instance:
+ case ObjCMessageExpr::SuperInstance:
+ break;
+ }
+
+ return getClassMethodSummary(ME->getSelector(),
+ Class? Class->getIdentifier() : 0,
+ Class,
ME->getMethodDecl(), ME->getType());
}
@@ -1333,37 +1367,44 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
// We need the type-information of the tracked receiver object
// Retrieve it from the state.
- const Expr *Receiver = ME->getReceiver();
+ const Expr *Receiver = ME->getInstanceReceiver();
const ObjCInterfaceDecl* ID = 0;
// FIXME: Is this really working as expected? There are cases where
// we just use the 'ID' from the message expression.
- SVal receiverV = state->getSValAsScalarOrLoc(Receiver);
+ SVal receiverV;
+
+ if (const Expr *Receiver = ME->getInstanceReceiver()) {
+ receiverV = state->getSValAsScalarOrLoc(Receiver);
- // FIXME: Eventually replace the use of state->get<RefBindings> with
- // a generic API for reasoning about the Objective-C types of symbolic
- // objects.
- if (SymbolRef Sym = receiverV.getAsLocSymbol())
- if (const RefVal *T = state->get<RefBindings>(Sym))
- if (const ObjCObjectPointerType* PT =
+ // FIXME: Eventually replace the use of state->get<RefBindings> with
+ // a generic API for reasoning about the Objective-C types of symbolic
+ // objects.
+ if (SymbolRef Sym = receiverV.getAsLocSymbol())
+ if (const RefVal *T = state->get<RefBindings>(Sym))
+ if (const ObjCObjectPointerType* PT =
T->getType()->getAs<ObjCObjectPointerType>())
- ID = PT->getInterfaceDecl();
+ ID = PT->getInterfaceDecl();
- // FIXME: this is a hack. This may or may not be the actual method
- // that is called.
- if (!ID) {
- if (const ObjCObjectPointerType *PT =
- Receiver->getType()->getAs<ObjCObjectPointerType>())
- ID = PT->getInterfaceDecl();
+ // FIXME: this is a hack. This may or may not be the actual method
+ // that is called.
+ if (!ID) {
+ if (const ObjCObjectPointerType *PT =
+ Receiver->getType()->getAs<ObjCObjectPointerType>())
+ ID = PT->getInterfaceDecl();
+ }
+ } else {
+ // FIXME: Hack for 'super'.
+ ID = ME->getReceiverInterface();
}
-
+
// FIXME: The receiver could be a reference to a class, meaning that
// we should use the class method.
RetainSummary *Summ = getInstanceMethodSummary(ME, ID);
// Special-case: are we sending a mesage to "self"?
// This is a hack. When we have full-IP this should be removed.
- if (isa<ObjCMethodDecl>(LC->getDecl())) {
+ if (isa<ObjCMethodDecl>(LC->getDecl()) && Receiver) {
if (const loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&receiverV)) {
// Get the region associated with 'self'.
if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) {
@@ -2081,7 +2122,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
// Get the name of the callee (if it is available).
SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee());
if (const FunctionDecl* FD = X.getAsFunctionDecl())
- os << "Call to function '" << FD->getNameAsString() <<'\'';
+ os << "Call to function '" << FD << '\'';
else
os << "function call";
}
@@ -2144,7 +2185,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
}
}
else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
- if (const Expr *receiver = ME->getReceiver())
+ if (const Expr *receiver = ME->getInstanceReceiver())
if (CurrSt->getSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) {
// The symbol we are tracking is the receiver.
AEffects.push_back(Summ->getReceiverEffect());
@@ -2510,7 +2551,7 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
// id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
// is a call to a class method whose type we can resolve. In such
// cases, promote the return type to XXX* (where XXX is the class).
- const ObjCInterfaceDecl *D = ME->getClassInfo().Decl;
+ const ObjCInterfaceDecl *D = ME->getReceiverInterface();
return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
}
@@ -2660,15 +2701,15 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
RetEffect RE = Summ.getRetEffect();
if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
- assert(Receiver);
- SVal V = state->getSValAsScalarOrLoc(Receiver);
bool found = false;
- if (SymbolRef Sym = V.getAsLocSymbol())
- if (state->get<RefBindings>(Sym)) {
- found = true;
- RE = Summaries.getObjAllocRetEffect();
- }
-
+ if (Receiver) {
+ SVal V = state->getSValAsScalarOrLoc(Receiver);
+ if (SymbolRef Sym = V.getAsLocSymbol())
+ if (state->get<RefBindings>(Sym)) {
+ found = true;
+ RE = Summaries.getObjAllocRetEffect();
+ }
+ } // FIXME: Otherwise, this is a send-to-super instance message.
if (!found)
RE = RetEffect::MakeNoRet();
}
@@ -2802,12 +2843,12 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
ExplodedNode* Pred,
const GRState *state) {
RetainSummary *Summ =
- ME->getReceiver()
+ ME->isInstanceMessage()
? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext())
: Summaries.getClassMethodSummary(ME);
assert(Summ && "RetainSummary is null");
- EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, NULL,
+ EvalSummary(Dst, Eng, Builder, ME, ME->getInstanceReceiver(), *Summ, NULL,
ME->arg_begin(), ME->arg_end(), Pred, state);
}
diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt
index dec375e..82e93a4 100644
--- a/lib/Checker/CMakeLists.txt
+++ b/lib/Checker/CMakeLists.txt
@@ -31,6 +31,7 @@ add_clang_library(clangChecker
FlatStore.cpp
GRBlockCounter.cpp
GRCoreEngine.cpp
+ GRCXXExprEngine.cpp
GRExprEngine.cpp
GRExprEngineExperimentalChecks.cpp
GRState.cpp
diff --git a/lib/Checker/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp
index dd1856c9..c619d75 100644
--- a/lib/Checker/CallAndMessageChecker.cpp
+++ b/lib/Checker/CallAndMessageChecker.cpp
@@ -154,8 +154,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
os << "Passed-by-value struct argument contains uninitialized data";
if (F.FieldChain.size() == 1)
- os << " (e.g., field: '" << F.FieldChain[0]->getNameAsString()
- << "')";
+ os << " (e.g., field: '" << F.FieldChain[0] << "')";
else {
os << " (e.g., via the field chain: '";
bool first = true;
@@ -165,7 +164,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
first = false;
else
os << '.';
- os << (*DI)->getNameAsString();
+ os << *DI;
}
os << "')";
}
@@ -219,7 +218,8 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
const GRState *state = C.getState();
- if (const Expr *receiver = ME->getReceiver())
+ // FIXME: Handle 'super'?
+ if (const Expr *receiver = ME->getInstanceReceiver())
if (state->getSVal(receiver).isUndef()) {
if (ExplodedNode *N = C.GenerateSink()) {
if (!BT_msg_undef)
@@ -266,10 +266,11 @@ void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
<< ME->getType().getAsString() << "' that will be garbage";
EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
- const Expr *receiver = ME->getReceiver();
- report->addRange(receiver->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- receiver);
+ if (const Expr *receiver = ME->getInstanceReceiver()) {
+ report->addRange(receiver->getSourceRange());
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ receiver);
+ }
C.EmitReport(report);
}
@@ -289,7 +290,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
ASTContext &Ctx = C.getASTContext();
CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
- if (CanRetTy->isStructureType()) {
+ if (CanRetTy->isStructureOrClassType()) {
// FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
// have the "use of undefined value" be smarter about where the
// undefined value came from.
diff --git a/lib/Checker/CastToStructChecker.cpp b/lib/Checker/CastToStructChecker.cpp
index 2c16f89..eeaed97 100644
--- a/lib/Checker/CastToStructChecker.cpp
+++ b/lib/Checker/CastToStructChecker.cpp
@@ -51,7 +51,7 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
QualType OrigPointeeTy = OrigPTy->getPointeeType();
QualType ToPointeeTy = ToPTy->getPointeeType();
- if (!ToPointeeTy->isStructureType())
+ if (!ToPointeeTy->isStructureOrClassType())
return;
// We allow cast from void*.
diff --git a/lib/Checker/CheckObjCDealloc.cpp b/lib/Checker/CheckObjCDealloc.cpp
index d9606f1..c23be87 100644
--- a/lib/Checker/CheckObjCDealloc.cpp
+++ b/lib/Checker/CheckObjCDealloc.cpp
@@ -27,10 +27,14 @@ using namespace clang;
static bool scan_dealloc(Stmt* S, Selector Dealloc) {
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
- if (ME->getSelector() == Dealloc)
- if (ME->getReceiver())
- if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
- return isa<ObjCSuperExpr>(Receiver);
+ if (ME->getSelector() == Dealloc) {
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Instance: return false;
+ case ObjCMessageExpr::SuperInstance: return true;
+ case ObjCMessageExpr::Class: break;
+ case ObjCMessageExpr::SuperClass: break;
+ }
+ }
// Recurse to children.
@@ -50,16 +54,16 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID,
// [mMyIvar release]
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
if (ME->getSelector() == Release)
- if (ME->getReceiver())
- if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
+ if (ME->getInstanceReceiver())
+ if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
if (ObjCIvarRefExpr* E = dyn_cast<ObjCIvarRefExpr>(Receiver))
if (E->getDecl() == ID)
return true;
// [self setMyIvar:nil];
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
- if (ME->getReceiver())
- if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
+ if (ME->getInstanceReceiver())
+ if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
if (DeclRefExpr* E = dyn_cast<DeclRefExpr>(Receiver))
if (E->getDecl()->getIdentifier() == SelfII)
if (ME->getMethodDecl() == PD->getSetterMethodDecl() &&
@@ -166,8 +170,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
std::string buf;
llvm::raw_string_ostream os(buf);
- os << "Objective-C class '" << D->getNameAsString()
- << "' lacks a 'dealloc' instance method";
+ os << "Objective-C class '" << D << "' lacks a 'dealloc' instance method";
BR.EmitBasicReport(name, os.str(), D->getLocStart());
return;
@@ -182,8 +185,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
std::string buf;
llvm::raw_string_ostream os(buf);
- os << "The 'dealloc' instance method in Objective-C class '"
- << D->getNameAsString()
+ os << "The 'dealloc' instance method in Objective-C class '" << D
<< "' does not send a 'dealloc' message to its super class"
" (missing [super dealloc])";
@@ -238,7 +240,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
? "missing ivar release (leak)"
: "missing ivar release (Hybrid MM, non-GC)";
- os << "The '" << ID->getNameAsString()
+ os << "The '" << ID
<< "' instance variable was retained by a synthesized property but "
"wasn't released in 'dealloc'";
} else {
@@ -246,7 +248,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
? "extra ivar release (use-after-release)"
: "extra ivar release (Hybrid MM, non-GC)";
- os << "The '" << ID->getNameAsString()
+ os << "The '" << ID
<< "' instance variable was not retained by a synthesized property "
"but was released in 'dealloc'";
}
diff --git a/lib/Checker/CheckObjCInstMethSignature.cpp b/lib/Checker/CheckObjCInstMethSignature.cpp
index 8c43a45..76a0923 100644
--- a/lib/Checker/CheckObjCInstMethSignature.cpp
+++ b/lib/Checker/CheckObjCInstMethSignature.cpp
@@ -49,16 +49,16 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
llvm::raw_string_ostream os(sbuf);
os << "The Objective-C class '"
- << MethDerived->getClassInterface()->getNameAsString()
+ << MethDerived->getClassInterface()
<< "', which is derived from class '"
- << MethAncestor->getClassInterface()->getNameAsString()
+ << MethAncestor->getClassInterface()
<< "', defines the instance method '"
<< MethDerived->getSelector().getAsString()
<< "' whose return type is '"
<< ResDerived.getAsString()
<< "'. A method with the same name (same selector) is also defined in "
"class '"
- << MethAncestor->getClassInterface()->getNameAsString()
+ << MethAncestor->getClassInterface()
<< "' and has a return type of '"
<< ResAncestor.getAsString()
<< "'. These two types are incompatible, and may result in undefined "
diff --git a/lib/Checker/CheckSecuritySyntaxOnly.cpp b/lib/Checker/CheckSecuritySyntaxOnly.cpp
index efbce61..74e12b1 100644
--- a/lib/Checker/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Checker/CheckSecuritySyntaxOnly.cpp
@@ -387,11 +387,11 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
// Issue a warning.
llvm::SmallString<256> buf1;
llvm::raw_svector_ostream os1(buf1);
- os1 << "'" << FD->getNameAsString() << "' is a poor random number generator";
+ os1 << '\'' << FD << "' is a poor random number generator";
llvm::SmallString<256> buf2;
llvm::raw_svector_ostream os2(buf2);
- os2 << "Function '" << FD->getNameAsString()
+ os2 << "Function '" << FD
<< "' is obsolete because it implements a poor random number generator."
<< " Use 'arc4random' instead";
@@ -472,14 +472,12 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
// Issue a warning.
llvm::SmallString<256> buf1;
llvm::raw_svector_ostream os1(buf1);
- os1 << "Return value is not checked in call to '" << FD->getNameAsString()
- << "'";
+ os1 << "Return value is not checked in call to '" << FD << '\'';
llvm::SmallString<256> buf2;
llvm::raw_svector_ostream os2(buf2);
- os2 << "The return value from the call to '" << FD->getNameAsString()
- << "' is not checked. If an error occurs in '"
- << FD->getNameAsString()
+ os2 << "The return value from the call to '" << FD
+ << "' is not checked. If an error occurs in '" << FD
<< "', the following code may execute with unexpected privileges";
SourceRange R = CE->getCallee()->getSourceRange();
diff --git a/lib/Checker/Environment.cpp b/lib/Checker/Environment.cpp
index be1a677..addfc21 100644
--- a/lib/Checker/Environment.cpp
+++ b/lib/Checker/Environment.cpp
@@ -37,6 +37,13 @@ SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const {
return ValMgr.makeIntVal(C->getValue(), C->getType());
}
+ case Stmt::CXXBoolLiteralExprClass: {
+ const SVal *X = ExprBindings.lookup(E);
+ if (X)
+ return *X;
+ else
+ return ValMgr.makeIntVal(cast<CXXBoolLiteralExpr>(E));
+ }
case Stmt::IntegerLiteralClass: {
// In C++, this expression may have been bound to a temporary object.
SVal const *X = ExprBindings.lookup(E);
diff --git a/lib/Checker/GRCXXExprEngine.cpp b/lib/Checker/GRCXXExprEngine.cpp
new file mode 100644
index 0000000..00ac995
--- /dev/null
+++ b/lib/Checker/GRCXXExprEngine.cpp
@@ -0,0 +1,246 @@
+//===- GRCXXExprEngine.cpp - C++ expr evaluation engine ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the C++ expression evaluation engine.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Checker/PathSensitive/AnalysisManager.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+
+void GRExprEngine::EvalArguments(ExprIterator AI, ExprIterator AE,
+ const FunctionProtoType *FnType,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst) {
+ llvm::SmallVector<CallExprWLItem, 20> WorkList;
+ WorkList.reserve(AE - AI);
+ WorkList.push_back(CallExprWLItem(AI, Pred));
+
+ while (!WorkList.empty()) {
+ CallExprWLItem Item = WorkList.back();
+ WorkList.pop_back();
+
+ if (Item.I == AE) {
+ Dst.insert(Item.N);
+ continue;
+ }
+
+ ExplodedNodeSet Tmp;
+ const unsigned ParamIdx = Item.I - AI;
+ bool VisitAsLvalue = FnType? FnType->getArgType(ParamIdx)->isReferenceType()
+ : false;
+ if (VisitAsLvalue)
+ VisitLValue(*Item.I, Item.N, Tmp);
+ else
+ Visit(*Item.I, Item.N, Tmp);
+
+ ++(Item.I);
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI)
+ WorkList.push_back(CallExprWLItem(Item.I, *NI));
+ }
+}
+
+const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D,
+ const StackFrameContext *SFC) {
+ Type *T = D->getParent()->getTypeForDecl();
+ QualType PT = getContext().getPointerType(QualType(T,0));
+ return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC);
+}
+
+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)));
+ }
+}
+
+void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ if (E->isElidable()) {
+ VisitAggExpr(E->getArg(0), Dest, Pred, Dst);
+ return;
+ }
+
+ const CXXConstructorDecl *CD = E->getConstructor();
+ assert(CD);
+
+ if (!CD->isThisDeclarationADefinition())
+ // FIXME: invalidate the object.
+ return;
+
+
+ // Evaluate other arguments.
+ ExplodedNodeSet ArgsEvaluated;
+ const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>();
+ EvalArguments(const_cast<CXXConstructExpr*>(E)->arg_begin(),
+ const_cast<CXXConstructExpr*>(E)->arg_end(),
+ FnType, Pred, ArgsEvaluated);
+ // The callee stack frame context used to create the 'this' parameter region.
+ const StackFrameContext *SFC = AMgr.getStackFrame(CD,
+ Pred->getLocationContext(),
+ E, Builder->getBlock(), Builder->getIndex());
+
+ const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC);
+
+ CallEnter Loc(E, CD, Pred->getLocationContext());
+ for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(),
+ NE = ArgsEvaluated.end(); NI != NE; ++NI) {
+ const GRState *state = GetState(*NI);
+ // Setup 'this' region.
+ state = state->bindLoc(loc::MemRegionVal(ThisR), Dest);
+ ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
+ if (N)
+ Dst.Add(N);
+ }
+}
+
+void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ // Get the method type.
+ const FunctionProtoType *FnType =
+ MCE->getCallee()->getType()->getAs<FunctionProtoType>();
+ assert(FnType && "Method type not available");
+
+ // Evaluate explicit arguments with a worklist.
+ ExplodedNodeSet ArgsEvaluated;
+ EvalArguments(const_cast<CXXMemberCallExpr*>(MCE)->arg_begin(),
+ const_cast<CXXMemberCallExpr*>(MCE)->arg_end(),
+ FnType, Pred, ArgsEvaluated);
+
+ // Evaluate the implicit object argument.
+ ExplodedNodeSet AllArgsEvaluated;
+ const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens());
+ if (!ME)
+ return;
+ Expr *ObjArgExpr = ME->getBase();
+ for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(),
+ E = ArgsEvaluated.end(); I != E; ++I) {
+ if (ME->isArrow())
+ Visit(ObjArgExpr, *I, AllArgsEvaluated);
+ else
+ VisitLValue(ObjArgExpr, *I, AllArgsEvaluated);
+ }
+
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
+ assert(MD && "not a CXXMethodDecl?");
+
+ if (!MD->isThisDeclarationADefinition())
+ // FIXME: conservative method call evaluation.
+ return;
+
+ const StackFrameContext *SFC = AMgr.getStackFrame(MD,
+ Pred->getLocationContext(),
+ MCE,
+ Builder->getBlock(),
+ Builder->getIndex());
+ const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC);
+ CallEnter Loc(MCE, MD, Pred->getLocationContext());
+ for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(),
+ E = AllArgsEvaluated.end(); I != E; ++I) {
+ // Set up 'this' region.
+ const GRState *state = GetState(*I);
+ state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr));
+ ExplodedNode *N = Builder->generateNode(Loc, state, *I);
+ if (N)
+ Dst.Add(N);
+ }
+}
+
+void GRExprEngine::VisitCXXNewExpr(CXXNewExpr *CNE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ if (CNE->isArray()) {
+ // FIXME: allocating an array has not been handled.
+ return;
+ }
+
+ unsigned Count = Builder->getCurrentBlockCount();
+ DefinedOrUnknownSVal SymVal = getValueManager().getConjuredSymbolVal(NULL,CNE,
+ CNE->getType(), Count);
+ const MemRegion *NewReg = cast<loc::MemRegionVal>(SymVal).getRegion();
+
+ QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
+
+ const ElementRegion *EleReg =
+ getStoreManager().GetElementZeroRegion(NewReg, ObjTy);
+
+ // Evaluate constructor arguments.
+ const FunctionProtoType *FnType = NULL;
+ const CXXConstructorDecl *CD = CNE->getConstructor();
+ if (CD)
+ FnType = CD->getType()->getAs<FunctionProtoType>();
+ ExplodedNodeSet ArgsEvaluated;
+ EvalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(),
+ FnType, Pred, ArgsEvaluated);
+
+ // Initialize the object region and bind the 'new' expression.
+ for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(),
+ E = ArgsEvaluated.end(); I != E; ++I) {
+ const GRState *state = GetState(*I);
+
+ if (ObjTy->isRecordType()) {
+ Store store = state->getStore();
+ StoreManager::InvalidatedSymbols IS;
+ store = getStoreManager().InvalidateRegion(store, EleReg, CNE, Count, &IS);
+ state = state->makeWithStore(store);
+ } else {
+ if (CNE->hasInitializer()) {
+ SVal V = state->getSVal(*CNE->constructor_arg_begin());
+ state = state->bindLoc(loc::MemRegionVal(EleReg), V);
+ } else {
+ // Explicitly set to undefined, because currently we retrieve symbolic
+ // value from symbolic region.
+ state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal());
+ }
+ }
+ state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
+ MakeNode(Dst, CNE, *I, state);
+ }
+}
+
+void GRExprEngine::VisitCXXDeleteExpr(CXXDeleteExpr *CDE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ // Should do more checking.
+ ExplodedNodeSet ArgEvaluated;
+ Visit(CDE->getArgument(), Pred, ArgEvaluated);
+ for (ExplodedNodeSet::iterator I = ArgEvaluated.begin(),
+ E = ArgEvaluated.end(); I != E; ++I) {
+ const GRState *state = GetState(*I);
+ MakeNode(Dst, CDE, *I, state);
+ }
+}
+
+void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ // Get the this object region from StoreManager.
+ const MemRegion *R =
+ ValMgr.getRegionManager().getCXXThisRegion(
+ getContext().getCanonicalType(TE->getType()),
+ Pred->getLocationContext());
+
+ const GRState *state = GetState(Pred);
+ SVal V = state->getSVal(loc::MemRegionVal(R));
+ MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
+}
diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp
index e4ef6b0..23a87d3 100644
--- a/lib/Checker/GRCoreEngine.cpp
+++ b/lib/Checker/GRCoreEngine.cpp
@@ -455,6 +455,33 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
Eng.WList->Enqueue(Succ, B, Idx+1);
}
+ExplodedNode* GRStmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, Stmt* S,
+ ExplodedNode* Pred, const GRState* St,
+ ProgramPoint::Kind K) {
+ const GRState* PredState = GetState(Pred);
+
+ // If the state hasn't changed, don't generate a new node.
+ if (!BuildSinks && St == PredState && Auditor == 0) {
+ Dst.Add(Pred);
+ return NULL;
+ }
+
+ ExplodedNode* N = generateNode(S, St, Pred, K);
+
+ if (N) {
+ if (BuildSinks)
+ N->markAsSink();
+ else {
+ if (Auditor && Auditor->Audit(N, Mgr))
+ N->markAsSink();
+
+ Dst.Add(N);
+ }
+ }
+
+ return N;
+}
+
static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K,
const LocationContext *LC, const void *tag){
switch (K) {
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index bab8922..67090b8 100644
--- a/lib/Checker/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -584,43 +584,81 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
switch (S->getStmtClass()) {
// C++ stuff we don't support yet.
- case Stmt::CXXNamedCastExprClass:
- case Stmt::CXXStaticCastExprClass:
- case Stmt::CXXDynamicCastExprClass:
- case Stmt::CXXReinterpretCastExprClass:
- case Stmt::CXXConstCastExprClass:
- case Stmt::CXXFunctionalCastExprClass:
- case Stmt::CXXTypeidExprClass:
- case Stmt::CXXBoolLiteralExprClass:
- case Stmt::CXXNullPtrLiteralExprClass:
- case Stmt::CXXThrowExprClass:
- case Stmt::CXXDefaultArgExprClass:
- case Stmt::CXXZeroInitValueExprClass:
- case Stmt::CXXNewExprClass:
- case Stmt::CXXDeleteExprClass:
- case Stmt::CXXPseudoDestructorExprClass:
- case Stmt::UnresolvedLookupExprClass:
- case Stmt::UnaryTypeTraitExprClass:
- case Stmt::DependentScopeDeclRefExprClass:
- case Stmt::CXXConstructExprClass:
+ case Stmt::CXXBindReferenceExprClass:
case Stmt::CXXBindTemporaryExprClass:
+ case Stmt::CXXCatchStmtClass:
+ case Stmt::CXXConstructExprClass:
+ case Stmt::CXXDefaultArgExprClass:
+ case Stmt::CXXDependentScopeMemberExprClass:
case Stmt::CXXExprWithTemporariesClass:
+ case Stmt::CXXNullPtrLiteralExprClass:
+ case Stmt::CXXPseudoDestructorExprClass:
case Stmt::CXXTemporaryObjectExprClass:
+ case Stmt::CXXThrowExprClass:
+ case Stmt::CXXTryStmtClass:
+ case Stmt::CXXTypeidExprClass:
case Stmt::CXXUnresolvedConstructExprClass:
- case Stmt::CXXDependentScopeMemberExprClass:
+ case Stmt::CXXZeroInitValueExprClass:
+ case Stmt::DependentScopeDeclRefExprClass:
+ case Stmt::UnaryTypeTraitExprClass:
+ case Stmt::UnresolvedLookupExprClass:
case Stmt::UnresolvedMemberExprClass:
- case Stmt::CXXCatchStmtClass:
- case Stmt::CXXTryStmtClass: {
+ {
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
Builder->BuildSinks = true;
MakeNode(Dst, S, Pred, GetState(Pred));
break;
}
- default:
- // Cases we intentionally have "default" handle:
- // AddrLabelExpr, IntegerLiteral, CharacterLiteral
+ // Cases that should never be evaluated simply because they shouldn't
+ // appear in the CFG.
+ case Stmt::BreakStmtClass:
+ case Stmt::CaseStmtClass:
+ case Stmt::CompoundStmtClass:
+ case Stmt::ContinueStmtClass:
+ case Stmt::DefaultStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::GotoStmtClass:
+ case Stmt::IndirectGotoStmtClass:
+ case Stmt::LabelStmtClass:
+ case Stmt::NoStmtClass:
+ case Stmt::NullStmtClass:
+ case Stmt::SwitchCaseClass:
+ llvm_unreachable("Stmt should not be in analyzer evaluation loop");
+ break;
+ // Cases not handled yet; but will handle some day.
+ case Stmt::DesignatedInitExprClass:
+ case Stmt::ExtVectorElementExprClass:
+ case Stmt::GNUNullExprClass:
+ case Stmt::ImaginaryLiteralClass:
+ case Stmt::ImplicitValueInitExprClass:
+ case Stmt::ObjCAtCatchStmtClass:
+ case Stmt::ObjCAtFinallyStmtClass:
+ case Stmt::ObjCAtSynchronizedStmtClass:
+ case Stmt::ObjCAtTryStmtClass:
+ case Stmt::ObjCEncodeExprClass:
+ case Stmt::ObjCImplicitSetterGetterRefExprClass:
+ case Stmt::ObjCIsaExprClass:
+ case Stmt::ObjCPropertyRefExprClass:
+ case Stmt::ObjCProtocolExprClass:
+ case Stmt::ObjCSelectorExprClass:
+ case Stmt::ObjCStringLiteralClass:
+ case Stmt::ObjCSuperExprClass:
+ case Stmt::ParenListExprClass:
+ case Stmt::PredefinedExprClass:
+ case Stmt::ShuffleVectorExprClass:
+ case Stmt::TypesCompatibleExprClass:
+ case Stmt::VAArgExprClass:
+ // Fall through.
+
+ // Cases we intentionally don't evaluate, since they don't need
+ // to be explicitly evaluated.
+ case Stmt::AddrLabelExprClass:
+ case Stmt::IntegerLiteralClass:
+ case Stmt::CharacterLiteralClass:
+ case Stmt::CXXBoolLiteralExprClass:
+ case Stmt::FloatingLiteralClass:
Dst.Add(Pred); // No-op. Simply propagate the current state unchanged.
break;
@@ -678,6 +716,17 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
break;
}
+ case Stmt::CXXNewExprClass: {
+ CXXNewExpr *NE = cast<CXXNewExpr>(S);
+ VisitCXXNewExpr(NE, Pred, Dst);
+ break;
+ }
+
+ case Stmt::CXXDeleteExprClass: {
+ CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S);
+ VisitCXXDeleteExpr(CDE, Pred, Dst);
+ break;
+ }
// FIXME: ChooseExpr is really a constant. We need to fix
// the CFG do not model them as explicit control-flow.
@@ -720,7 +769,12 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
break;
case Stmt::ImplicitCastExprClass:
- case Stmt::CStyleCastExprClass: {
+ case Stmt::CStyleCastExprClass:
+ case Stmt::CXXStaticCastExprClass:
+ case Stmt::CXXDynamicCastExprClass:
+ case Stmt::CXXReinterpretCastExprClass:
+ case Stmt::CXXConstCastExprClass:
+ case Stmt::CXXFunctionalCastExprClass: {
CastExpr* C = cast<CastExpr>(S);
VisitCast(C, C->getSubExpr(), Pred, Dst, false);
break;
@@ -769,6 +823,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
break;
+ case Stmt::OffsetOfExprClass:
+ VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst);
+ break;
+
case Stmt::SizeOfAlignOfExprClass:
VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), Pred, Dst);
break;
@@ -935,6 +993,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
return;
// In C++, binding an rvalue to a reference requires to create an object.
+ case Stmt::CXXBoolLiteralExprClass:
case Stmt::IntegerLiteralClass:
CreateCXXTemporaryObject(Ex, Pred, Dst);
return;
@@ -1751,21 +1810,6 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
}
}
-//===----------------------------------------------------------------------===//
-// Transfer function: Function calls.
-//===----------------------------------------------------------------------===//
-
-namespace {
-class CallExprWLItem {
-public:
- CallExpr::arg_iterator I;
- ExplodedNode *N;
-
- CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n)
- : I(i), N(n) {}
-};
-} // end anonymous namespace
-
void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
CallExpr::arg_iterator AI,
CallExpr::arg_iterator AE,
@@ -1916,7 +1960,7 @@ void GRExprEngine::EvalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
continue;
}
- const GRState* state = Pred->getState();
+ const GRState* state = GetState(Pred);
SVal V = state->getSVal(Ex);
if (nonloc::SymExprVal *SEV = dyn_cast<nonloc::SymExprVal>(&V)) {
// First assume that the condition is true.
@@ -2087,7 +2131,7 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
// But first evaluate the receiver (if any).
ObjCMessageExpr::arg_iterator AI = ME->arg_begin(), AE = ME->arg_end();
- if (Expr *Receiver = ME->getReceiver()) {
+ if (Expr *Receiver = ME->getInstanceReceiver()) {
ExplodedNodeSet Tmp;
Visit(Receiver, Pred, Tmp);
@@ -2139,8 +2183,8 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
- if (const Expr *Receiver = ME->getReceiver()) {
- const GRState *state = Pred->getState();
+ if (const Expr *Receiver = ME->getInstanceReceiver()) {
+ const GRState *state = GetState(Pred);
// Bifurcate the state into nil and non-nil ones.
DefinedOrUnknownSVal receiverVal =
@@ -2169,8 +2213,8 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
// Dispatch to plug-in transfer function.
EvalObjCMessageExpr(DstEval, ME, Pred, notNilState);
}
- else {
- IdentifierInfo* ClsName = ME->getClassName();
+ else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) {
+ IdentifierInfo* ClsName = Iface->getIdentifier();
Selector S = ME->getSelector();
// Check for special instance methods.
@@ -2464,9 +2508,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred,
QualType T = getContext().getCanonicalType(E->getType());
unsigned NumInitElements = E->getNumInits();
- if (T->isArrayType() || T->isStructureType() ||
- T->isUnionType() || T->isVectorType()) {
-
+ if (T->isArrayType() || T->isRecordType() || T->isVectorType()) {
llvm::ImmutableList<SVal> StartVals = getBasicVals().getEmptySValList();
// Handle base case where the initializer has no elements.
@@ -2573,6 +2615,21 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
ValMgr.makeIntVal(amt.getQuantity(), Ex->getType())));
}
+void GRExprEngine::VisitOffsetOfExpr(OffsetOfExpr* OOE, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst) {
+ Expr::EvalResult Res;
+ if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) {
+ const APSInt &IV = Res.Val.getInt();
+ assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
+ assert(OOE->getType()->isIntegerType());
+ assert(IV.isSigned() == OOE->getType()->isSignedIntegerType());
+ SVal X = ValMgr.makeIntVal(IV);
+ MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X));
+ return;
+ }
+ // FIXME: Handle the case where __builtin_offsetof is not a constant.
+ Dst.Add(Pred);
+}
void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
ExplodedNodeSet& Dst, bool asLValue) {
@@ -2654,19 +2711,19 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
case UnaryOperator::OffsetOf: {
Expr::EvalResult Res;
if (U->Evaluate(Res, getContext()) && Res.Val.isInt()) {
- const APSInt &IV = Res.Val.getInt();
- assert(IV.getBitWidth() == getContext().getTypeSize(U->getType()));
- assert(U->getType()->isIntegerType());
- assert(IV.isSigned() == U->getType()->isSignedIntegerType());
- SVal X = ValMgr.makeIntVal(IV);
- MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X));
- return;
- }
+ const APSInt &IV = Res.Val.getInt();
+ assert(IV.getBitWidth() == getContext().getTypeSize(U->getType()));
+ assert(U->getType()->isIntegerType());
+ assert(IV.isSigned() == U->getType()->isSignedIntegerType());
+ SVal X = ValMgr.makeIntVal(IV);
+ MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X));
+ return;
+ }
// FIXME: Handle the case where __builtin_offsetof is not a constant.
Dst.Add(Pred);
return;
}
-
+
case UnaryOperator::Plus: assert (!asLValue); // FALL-THROUGH.
case UnaryOperator::Extension: {
@@ -2860,20 +2917,6 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
}
}
-
-void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
- ExplodedNodeSet & Dst) {
- // Get the this object region from StoreManager.
- const MemRegion *R =
- ValMgr.getRegionManager().getCXXThisRegion(
- getContext().getCanonicalType(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,
ExplodedNodeSet& Dst) {
VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst);
@@ -3006,7 +3049,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
ExplodedNodeSet Tmp3;
for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) {
- SVal LeftV = (*I1)->getState()->getSVal(LHS);
+ SVal LeftV = GetState(*I1)->getSVal(LHS);
ExplodedNodeSet Tmp2;
Visit(RHS, *I1, Tmp2);
@@ -3147,184 +3190,6 @@ 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)));
- }
-}
-
-void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- if (E->isElidable()) {
- VisitAggExpr(E->getArg(0), Dest, Pred, Dst);
- return;
- }
-
- const CXXConstructorDecl *CD = E->getConstructor();
- assert(CD);
-
- if (!CD->isThisDeclarationADefinition())
- // FIXME: invalidate the object.
- return;
-
-
- // Evaluate other arguments.
- CXXConstructExpr::arg_iterator AB
- = const_cast<CXXConstructExpr*>(E)->arg_begin();
- CXXConstructExpr::arg_iterator AE
- = const_cast<CXXConstructExpr*>(E)->arg_end();
- llvm::SmallVector<CallExprWLItem, 20> WorkList;
- WorkList.reserve(AE - AB);
- WorkList.push_back(CallExprWLItem(AB, Pred));
- ExplodedNodeSet ArgsEvaluated;
- const FunctionProtoType *Proto = CD->getType()->getAs<FunctionProtoType>();
-
- while (!WorkList.empty()) {
- CallExprWLItem Item = WorkList.back();
- WorkList.pop_back();
-
- if (Item.I == AE) {
- ArgsEvaluated.insert(Item.N);
- continue;
- }
-
- // Evaluate the argument.
- ExplodedNodeSet Tmp;
- const unsigned ParamIdx = Item.I - AB;
-
- bool VisitAsLvalue = false;
-
- if (ParamIdx < Proto->getNumArgs())
- VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();
-
- if (VisitAsLvalue)
- VisitLValue(*Item.I, Item.N, Tmp);
- else
- Visit(*Item.I, Item.N, Tmp);
-
- ++(Item.I);
-
- for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
- WorkList.push_back(CallExprWLItem(Item.I, *NI));
- }
- // The callee stack frame context used to create the 'this' parameter region.
- const StackFrameContext *SFC = AMgr.getStackFrame(CD,
- Pred->getLocationContext(),
- E, Builder->getBlock(), Builder->getIndex());
-
- const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC);
-
- CallEnter Loc(E, CD, Pred->getLocationContext());
- for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(),
- NE = ArgsEvaluated.end(); NI != NE; ++NI) {
- const GRState *state = GetState(*NI);
- // Setup 'this' region.
- state = state->bindLoc(loc::MemRegionVal(ThisR), Dest);
- ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
- if (N)
- Dst.Add(N);
- }
-}
-
-void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- // Get the method type.
- const FunctionProtoType *FnType =
- MCE->getCallee()->getType()->getAs<FunctionProtoType>();
- assert(FnType && "Method type not available");
-
- // Evaluate explicit arguments with a worklist.
- CallExpr::arg_iterator AB = const_cast<CXXMemberCallExpr*>(MCE)->arg_begin(),
- AE = const_cast<CXXMemberCallExpr*>(MCE)->arg_end();
- llvm::SmallVector<CallExprWLItem, 20> WorkList;
- WorkList.reserve(AE - AB);
- WorkList.push_back(CallExprWLItem(AB, Pred));
- ExplodedNodeSet ArgsEvaluated;
-
- while (!WorkList.empty()) {
- CallExprWLItem Item = WorkList.back();
- WorkList.pop_back();
-
- if (Item.I == AE) {
- ArgsEvaluated.insert(Item.N);
- continue;
- }
-
- ExplodedNodeSet Tmp;
- const unsigned ParamIdx = Item.I - AB;
- bool VisitAsLvalue = FnType->getArgType(ParamIdx)->isReferenceType();
-
- if (VisitAsLvalue)
- VisitLValue(*Item.I, Item.N, Tmp);
- else
- Visit(*Item.I, Item.N, Tmp);
-
- ++(Item.I);
- for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI)
- WorkList.push_back(CallExprWLItem(Item.I, *NI));
- }
- // Evaluate the implicit object argument.
- ExplodedNodeSet AllArgsEvaluated;
- const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens());
- if (!ME)
- return;
- Expr *ObjArgExpr = ME->getBase();
- for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(),
- E = ArgsEvaluated.end(); I != E; ++I) {
- if (ME->isArrow())
- Visit(ObjArgExpr, *I, AllArgsEvaluated);
- else
- VisitLValue(ObjArgExpr, *I, AllArgsEvaluated);
- }
-
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
- assert(MD && "not a CXXMethodDecl?");
-
- if (!MD->isThisDeclarationADefinition())
- // FIXME: conservative method call evaluation.
- return;
-
- const StackFrameContext *SFC = AMgr.getStackFrame(MD,
- Pred->getLocationContext(),
- MCE,
- Builder->getBlock(),
- Builder->getIndex());
- const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC);
- CallEnter Loc(MCE, MD, Pred->getLocationContext());
- for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(),
- E = AllArgsEvaluated.end(); I != E; ++I) {
- // Set up 'this' region.
- const GRState *state = GetState(*I);
- state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr));
- ExplodedNode *N = Builder->generateNode(Loc, state, *I);
- if (N)
- Dst.Add(N);
- }
-}
-
-const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D,
- const StackFrameContext *SFC) {
- Type *T = D->getParent()->getTypeForDecl();
- QualType PT = getContext().getPointerType(QualType(T,0));
- return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC);
-}
-
//===----------------------------------------------------------------------===//
// Checker registration/lookup.
//===----------------------------------------------------------------------===//
diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp
index 9f12ab6..9a664c7 100644
--- a/lib/Checker/MemRegion.cpp
+++ b/lib/Checker/MemRegion.cpp
@@ -365,11 +365,11 @@ void ElementRegion::dumpToStream(llvm::raw_ostream& os) const {
}
void FieldRegion::dumpToStream(llvm::raw_ostream& os) const {
- os << superRegion << "->" << getDecl()->getNameAsString();
+ os << superRegion << "->" << getDecl();
}
void ObjCIvarRegion::dumpToStream(llvm::raw_ostream& os) const {
- os << "ivar{" << superRegion << ',' << getDecl()->getNameAsString() << '}';
+ os << "ivar{" << superRegion << ',' << getDecl() << '}';
}
void StringRegion::dumpToStream(llvm::raw_ostream& os) const {
@@ -381,7 +381,7 @@ void SymbolicRegion::dumpToStream(llvm::raw_ostream& os) const {
}
void VarRegion::dumpToStream(llvm::raw_ostream& os) const {
- os << cast<VarDecl>(D)->getNameAsString();
+ os << cast<VarDecl>(D);
}
void RegionRawOffset::dump() const {
@@ -647,13 +647,14 @@ bool MemRegion::hasGlobalsOrParametersStorage() const {
const MemRegion *MemRegion::getBaseRegion() const {
const MemRegion *R = this;
while (true) {
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- R = ER->getSuperRegion();
- continue;
- }
- if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
- R = FR->getSuperRegion();
- continue;
+ switch (R->getKind()) {
+ case MemRegion::ElementRegionKind:
+ case MemRegion::FieldRegionKind:
+ case MemRegion::ObjCIvarRegionKind:
+ R = cast<SubRegion>(R)->getSuperRegion();
+ continue;
+ default:
+ break;
}
break;
}
diff --git a/lib/Checker/NSAutoreleasePoolChecker.cpp b/lib/Checker/NSAutoreleasePoolChecker.cpp
index 29bac9c..48f03a3 100644
--- a/lib/Checker/NSAutoreleasePoolChecker.cpp
+++ b/lib/Checker/NSAutoreleasePoolChecker.cpp
@@ -56,7 +56,7 @@ void
NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
const ObjCMessageExpr *ME) {
- const Expr *receiver = ME->getReceiver();
+ const Expr *receiver = ME->getInstanceReceiver();
if (!receiver)
return;
diff --git a/lib/Checker/NSErrorChecker.cpp b/lib/Checker/NSErrorChecker.cpp
index 9130bfa..e30d54c 100644
--- a/lib/Checker/NSErrorChecker.cpp
+++ b/lib/Checker/NSErrorChecker.cpp
@@ -226,7 +226,7 @@ void NSErrorChecker::CheckParamDeref(const VarDecl *Param,
else
os << "documented in CoreFoundation/CFError.h the parameter '";
- os << Param->getNameAsString() << "' may be null.";
+ os << Param << "' may be null.";
BugReport *report = new BugReport(*this, os.str(), *I);
// FIXME: Notable symbols are now part of the report. We should
diff --git a/lib/Checker/ObjCUnusedIVarsChecker.cpp b/lib/Checker/ObjCUnusedIVarsChecker.cpp
index 04d897a..0e47621 100644
--- a/lib/Checker/ObjCUnusedIVarsChecker.cpp
+++ b/lib/Checker/ObjCUnusedIVarsChecker.cpp
@@ -150,8 +150,7 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
if (I->second == Unused) {
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
- os << "Instance variable '" << I->first->getNameAsString()
- << "' in class '" << ID->getNameAsString()
+ os << "Instance variable '" << I->first << "' in class '" << ID
<< "' is never used by the methods in its @implementation "
"(although it may be used by category methods).";
diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp
index c97da33..1e15d43 100644
--- a/lib/Checker/RegionStore.cpp
+++ b/lib/Checker/RegionStore.cpp
@@ -14,22 +14,22 @@
// parameters are created lazily.
//
//===----------------------------------------------------------------------===//
-#include "clang/Checker/PathSensitive/MemRegion.h"
-#include "clang/Analysis/AnalysisContext.h"
-#include "clang/Checker/PathSensitive/GRState.h"
-#include "clang/Checker/PathSensitive/GRStateTrait.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/Support/Optional.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
-
-#include "llvm/ADT/ImmutableMap.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/MemRegion.h"
#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+using llvm::Optional;
//===----------------------------------------------------------------------===//
// Representation of binding keys.
@@ -346,8 +346,6 @@ public: // Part of public interface to class.
Store CopyLazyBindings(nonloc::LazyCompoundVal V, Store store,
const TypedRegion *R);
- const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
-
//===------------------------------------------------------------------===//
// State pruning.
//===------------------------------------------------------------------===//
@@ -995,14 +993,6 @@ static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) {
return true;
}
-const ElementRegion *
-RegionStoreManager::GetElementZeroRegion(const MemRegion *R, QualType T) {
- ASTContext &Ctx = getContext();
- SVal idx = ValMgr.makeZeroArrayIndex();
- assert(!T.isNull());
- return MRMgr.getElementRegion(T, idx, R, Ctx);
-}
-
SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
assert(!isa<UnknownVal>(L) && "location unknown");
assert(!isa<UndefinedVal>(L) && "location undefined");
@@ -1047,7 +1037,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
}
#endif
- if (RTy->isStructureType() || RTy->isClassType())
+ if (RTy->isStructureOrClassType())
return RetrieveStruct(store, R);
// FIXME: Handle unions.
@@ -1355,7 +1345,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) {
SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
QualType T = R->getValueType(getContext());
- assert(T->isStructureType() || T->isClassType());
+ assert(T->isStructureOrClassType());
return ValMgr.makeLazyCompoundVal(store, R);
}
@@ -1385,7 +1375,7 @@ Store RegionStoreManager::Bind(Store store, Loc L, SVal V) {
// Check if the region is a struct region.
if (const TypedRegion* TR = dyn_cast<TypedRegion>(R))
- if (TR->getValueType(getContext())->isStructureType())
+ if (TR->getValueType(getContext())->isStructureOrClassType())
return BindStruct(store, TR, V);
// Special case: the current region represents a cast and it and the super
@@ -1439,7 +1429,7 @@ Store RegionStoreManager::BindDecl(Store store, const VarRegion *VR,
if (T->isArrayType())
return BindArray(store, VR, InitVal);
- if (T->isStructureType())
+ if (T->isStructureOrClassType())
return BindStruct(store, VR, InitVal);
return Bind(store, ValMgr.makeLoc(VR), InitVal);
@@ -1464,7 +1454,7 @@ Store RegionStoreManager::setImplicitDefaultValue(Store store,
V = ValMgr.makeNull();
else if (T->isIntegerType())
V = ValMgr.makeZeroVal(T);
- else if (T->isStructureType() || T->isArrayType()) {
+ else if (T->isStructureOrClassType() || T->isArrayType()) {
// Set the default value to a zero constant when it is a structure
// or array. The type doesn't really matter.
V = ValMgr.makeZeroVal(ValMgr.getContext().IntTy);
@@ -1540,7 +1530,7 @@ Store RegionStoreManager::BindArray(Store store, const TypedRegion* R,
SVal Idx = ValMgr.makeArrayIndex(i);
const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext());
- if (ElementTy->isStructureType())
+ if (ElementTy->isStructureOrClassType())
store = BindStruct(store, ER, *VI);
else
store = Bind(store, ValMgr.makeLoc(ER), *VI);
@@ -1561,7 +1551,7 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R,
return store;
QualType T = R->getValueType(getContext());
- assert(T->isStructureType());
+ assert(T->isStructureOrClassType());
const RecordType* RT = T->getAs<RecordType>();
RecordDecl* RD = RT->getDecl();
@@ -1593,7 +1583,7 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R,
if (FTy->isArrayType())
store = BindArray(store, FR, *VI);
- else if (FTy->isStructureType())
+ else if (FTy->isStructureOrClassType())
store = BindStruct(store, FR, *VI);
else
store = Bind(store, ValMgr.makeLoc(FR), *VI);
diff --git a/lib/Checker/SVals.cpp b/lib/Checker/SVals.cpp
index 4bfa2cd..d756be7 100644
--- a/lib/Checker/SVals.cpp
+++ b/lib/Checker/SVals.cpp
@@ -318,7 +318,8 @@ void NonLoc::dumpToStream(llvm::raw_ostream& os) const {
}
case nonloc::LazyCompoundValKind: {
const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this);
- os << "lazyCompoundVal{" << (void*) C.getStore() << ',' << C.getRegion()
+ os << "lazyCompoundVal{" << const_cast<void *>(C.getStore())
+ << ',' << C.getRegion()
<< '}';
break;
}
diff --git a/lib/Checker/SimpleSValuator.cpp b/lib/Checker/SimpleSValuator.cpp
index fb1d74a..dd38a43 100644
--- a/lib/Checker/SimpleSValuator.cpp
+++ b/lib/Checker/SimpleSValuator.cpp
@@ -113,16 +113,22 @@ SVal SimpleSValuator::EvalCastL(Loc val, QualType castTy) {
if (castTy->isUnionType())
return UnknownVal();
- assert(castTy->isIntegerType());
- unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy);
+ if (castTy->isIntegerType()) {
+ unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy);
- if (!isa<loc::ConcreteInt>(val))
- return ValMgr.makeLocAsInteger(val, BitWidth);
+ if (!isa<loc::ConcreteInt>(val))
+ return ValMgr.makeLocAsInteger(val, BitWidth);
- llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
- i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
- i.extOrTrunc(BitWidth);
- return ValMgr.makeIntVal(i);
+ llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
+ i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
+ i.extOrTrunc(BitWidth);
+ return ValMgr.makeIntVal(i);
+ }
+
+ // All other cases: return 'UnknownVal'. This includes casting pointers
+ // to floats, which is probably badness it itself, but this is a good
+ // intermediate solution until we do something better.
+ return UnknownVal();
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Checker/Store.cpp b/lib/Checker/Store.cpp
index e524cb3..c12065b 100644
--- a/lib/Checker/Store.cpp
+++ b/lib/Checker/Store.cpp
@@ -38,6 +38,13 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
return true;
}
+const ElementRegion *StoreManager::GetElementZeroRegion(const MemRegion *R,
+ QualType T) {
+ SVal idx = ValMgr.makeZeroArrayIndex();
+ assert(!T.isNull());
+ return MRMgr.getElementRegion(T, idx, R, Ctx);
+}
+
const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) {
ASTContext& Ctx = StateMgr.getContext();
@@ -170,13 +177,14 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
if (IsCompleteType(Ctx, PointeeTy)) {
// Compute the size in **bytes**.
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
- // the base region.
- if (off % pointeeTySize == 0) {
- newIndex = off / pointeeTySize;
- newSuperR = baseR;
+ if (!pointeeTySize.isZero()) {
+ // Is the offset a multiple of the size? If so, we can layer the
+ // ElementRegion (with elementType == PointeeTy) directly on top of
+ // the base region.
+ if (off % pointeeTySize == 0) {
+ newIndex = off / pointeeTySize;
+ newSuperR = baseR;
+ }
}
}
diff --git a/lib/Checker/UnixAPIChecker.cpp b/lib/Checker/UnixAPIChecker.cpp
index d75e5d2..e9b8f09 100644
--- a/lib/Checker/UnixAPIChecker.cpp
+++ b/lib/Checker/UnixAPIChecker.cpp
@@ -13,23 +13,30 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
#include <fcntl.h>
using namespace clang;
+using llvm::Optional;
namespace {
class UnixAPIChecker : public CheckerVisitor<UnixAPIChecker> {
enum SubChecks {
OpenFn = 0,
+ PthreadOnceFn = 1,
NumChecks
};
BugType *BTypes[NumChecks];
public:
+ Optional<uint64_t> Val_O_CREAT;
+
+public:
UnixAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
static void *getTag() { static unsigned tag = 0; return &tag; }
@@ -55,7 +62,21 @@ static inline void LazyInitialize(BugType *&BT, const char *name) {
// "open" (man 2 open)
//===----------------------------------------------------------------------===//
-static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) {
+static void CheckOpen(CheckerContext &C, UnixAPIChecker &UC,
+ const CallExpr *CE, BugType *&BT) {
+ // The definition of O_CREAT is platform specific. We need a better way
+ // of querying this information from the checking environment.
+ if (!UC.Val_O_CREAT.hasValue()) {
+ if (C.getASTContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
+ UC.Val_O_CREAT = 0x0200;
+ else {
+ // FIXME: We need a more general way of getting the O_CREAT value.
+ // We could possibly grovel through the preprocessor state, but
+ // that would require passing the Preprocessor object to the GRExprEngine.
+ return;
+ }
+ }
+
LazyInitialize(BT, "Improper use of 'open'");
// Look at the 'oflags' argument for the O_CREAT flag.
@@ -77,7 +98,7 @@ static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) {
}
NonLoc oflags = cast<NonLoc>(V);
NonLoc ocreateFlag =
- cast<NonLoc>(C.getValueManager().makeIntVal((uint64_t) O_CREAT,
+ cast<NonLoc>(C.getValueManager().makeIntVal(UC.Val_O_CREAT.getValue(),
oflagsEx->getType()));
SVal maskedFlagsUC = C.getSValuator().EvalBinOpNN(state, BinaryOperator::And,
oflags, ocreateFlag,
@@ -110,21 +131,67 @@ static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) {
}
//===----------------------------------------------------------------------===//
+// pthread_once
+//===----------------------------------------------------------------------===//
+
+static void CheckPthreadOnce(CheckerContext &C, UnixAPIChecker &,
+ const CallExpr *CE, BugType *&BT) {
+
+ // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
+ // They can possibly be refactored.
+
+ LazyInitialize(BT, "Improper use of 'pthread_once'");
+
+ if (CE->getNumArgs() < 1)
+ return;
+
+ // Check if the first argument is stack allocated. If so, issue a warning
+ // because that's likely to be bad news.
+ const GRState *state = C.getState();
+ const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
+ if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
+ return;
+
+ ExplodedNode *N = C.GenerateSink(state);
+ if (!N)
+ return;
+
+ llvm::SmallString<256> S;
+ llvm::raw_svector_ostream os(S);
+ os << "Call to 'pthread_once' uses";
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R))
+ os << " the local variable '" << VR->getDecl()->getName() << '\'';
+ else
+ os << " stack allocated memory";
+ os << " for the \"control\" value. Using such transient memory for "
+ "the control value is potentially dangerous.";
+ if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
+ os << " Perhaps you intended to declare the variable as 'static'?";
+
+ EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
+ report->addRange(CE->getArg(0)->getSourceRange());
+ C.EmitReport(report);
+}
+
+//===----------------------------------------------------------------------===//
// Central dispatch function.
//===----------------------------------------------------------------------===//
-typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT);
+typedef void (*SubChecker)(CheckerContext &C, UnixAPIChecker &UC,
+ const CallExpr *CE, BugType *&BT);
namespace {
class SubCheck {
SubChecker SC;
+ UnixAPIChecker *UC;
BugType **BT;
public:
- SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {}
- SubCheck() : SC(NULL), BT(NULL) {}
+ SubCheck(SubChecker sc, UnixAPIChecker *uc, BugType *& bt) : SC(sc), UC(uc),
+ BT(&bt) {}
+ SubCheck() : SC(NULL), UC(NULL), BT(NULL) {}
void run(CheckerContext &C, const CallExpr *CE) const {
if (SC)
- SC(C, CE, *BT);
+ SC(C, *UC, CE, *BT);
}
};
} // end anonymous namespace
@@ -146,7 +213,9 @@ void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
const SubCheck &SC =
llvm::StringSwitch<SubCheck>(FI->getName())
- .Case("open", SubCheck(CheckOpen, BTypes[OpenFn]))
+ .Case("open", SubCheck(CheckOpen, this, BTypes[OpenFn]))
+ .Case("pthread_once", SubCheck(CheckPthreadOnce, this,
+ BTypes[PthreadOnceFn]))
.Default(SubCheck());
SC.run(C, CE);
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 5097341..db24def 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -706,7 +706,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
BlockDeclRefDecls);
// FIXME: This leaks
ImplicitParamDecl *SelfDecl =
- ImplicitParamDecl::Create(getContext(), 0,
+ ImplicitParamDecl::Create(getContext(), const_cast<BlockDecl*>(BD),
SourceLocation(), II,
ParmTy);
@@ -812,7 +812,8 @@ CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
Pad.getQuantity()),
ArrayType::Normal, 0);
ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(),
- 0, QualType(PadTy), 0, VarDecl::None);
+ 0, QualType(PadTy), 0,
+ VarDecl::None, VarDecl::None);
Expr *E;
E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(),
SourceLocation());
@@ -860,7 +861,9 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T,
FunctionDecl *FD = FunctionDecl::Create(getContext(),
getContext().getTranslationUnitDecl(),
SourceLocation(), II, R, 0,
- FunctionDecl::Static, false,
+ FunctionDecl::Static,
+ FunctionDecl::None,
+ false,
true);
CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
@@ -941,8 +944,9 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose,
FunctionDecl *FD = FunctionDecl::Create(getContext(),
getContext().getTranslationUnitDecl(),
SourceLocation(), II, R, 0,
- FunctionDecl::Static, false,
- true);
+ FunctionDecl::Static,
+ FunctionDecl::None,
+ false, true);
CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
if (NoteForHelperp) {
@@ -1025,8 +1029,9 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) {
FunctionDecl *FD = FunctionDecl::Create(getContext(),
getContext().getTranslationUnitDecl(),
SourceLocation(), II, R, 0,
- FunctionDecl::Static, false,
- true);
+ FunctionDecl::Static,
+ FunctionDecl::None,
+ false, true);
CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
// dst->x
@@ -1089,8 +1094,9 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
FunctionDecl *FD = FunctionDecl::Create(getContext(),
getContext().getTranslationUnitDecl(),
SourceLocation(), II, R, 0,
- FunctionDecl::Static, false,
- true);
+ FunctionDecl::Static,
+ FunctionDecl::None,
+ false, true);
CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
llvm::Value *V = CGF.GetAddrOfLocalVar(Src);
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index efee0e3..5646d00 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -38,6 +38,7 @@ namespace llvm {
class GlobalValue;
class TargetData;
class FunctionType;
+ class PointerType;
class Value;
class LLVMContext;
}
@@ -127,7 +128,7 @@ protected:
llvm::LLVMContext &VMContext;
public:
- const llvm::Type *PtrToInt8Ty;
+ const llvm::PointerType *PtrToInt8Ty;
struct HelperInfo {
int index;
int flag;
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 38c40ed..95c41db 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -682,13 +682,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BIsqrt:
case Builtin::BIsqrtf:
case Builtin::BIsqrtl: {
- // Rewrite sqrt to intrinsic if allowed.
- if (!FD->hasAttr<ConstAttr>())
- break;
- Value *Arg0 = EmitScalarExpr(E->getArg(0));
- const llvm::Type *ArgType = Arg0->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::sqrt, &ArgType, 1);
- return RValue::get(Builder.CreateCall(F, Arg0, "tmp"));
+ // TODO: there is currently no set of optimizer flags
+ // sufficient for us to rewrite sqrt to @llvm.sqrt.
+ // -fmath-errno=0 is not good enough; we need finiteness.
+ // We could probably precondition the call with an ult
+ // against 0, but is that worth the complexity?
+ break;
}
case Builtin::BIpow:
@@ -983,8 +982,38 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
return Builder.CreateStore(Ops[1], Ops[0]);
}
case X86::BI__builtin_ia32_palignr: {
- Function *F = CGM.getIntrinsic(Intrinsic::x86_ssse3_palign_r);
- return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size());
+ unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
+
+ // If palignr is shifting the pair of input vectors less than 9 bytes,
+ // emit a shuffle instruction.
+ if (shiftVal <= 8) {
+ const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext);
+
+ llvm::SmallVector<llvm::Constant*, 8> Indices;
+ for (unsigned i = 0; i != 8; ++i)
+ Indices.push_back(llvm::ConstantInt::get(IntTy, shiftVal + i));
+
+ Value* SV = llvm::ConstantVector::get(Indices.begin(), Indices.size());
+ return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr");
+ }
+
+ // If palignr is shifting the pair of input vectors more than 8 but less
+ // than 16 bytes, emit a logical right shift of the destination.
+ if (shiftVal < 16) {
+ // MMX has these as 1 x i64 vectors for some odd optimization reasons.
+ const llvm::Type *EltTy = llvm::Type::getInt64Ty(VMContext);
+ const llvm::Type *VecTy = llvm::VectorType::get(EltTy, 1);
+
+ Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast");
+ Ops[1] = llvm::ConstantInt::get(VecTy, (shiftVal-8) * 8);
+
+ // create i32 constant
+ llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_mmx_psrl_q);
+ return Builder.CreateCall(F, &Ops[0], &Ops[0] + 2, "palignr");
+ }
+
+ // If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
+ return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
case X86::BI__builtin_ia32_palignr128: {
unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
@@ -1025,5 +1054,49 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
+ llvm::SmallVector<Value*, 4> Ops;
+
+ for (unsigned i = 0, e = E->getNumArgs(); i != e; i++)
+ Ops.push_back(EmitScalarExpr(E->getArg(i)));
+
+ Intrinsic::ID ID = Intrinsic::not_intrinsic;
+
+ switch (BuiltinID) {
+ default: return 0;
+
+ // vec_st
+ case PPC::BI__builtin_altivec_stvx:
+ case PPC::BI__builtin_altivec_stvxl:
+ case PPC::BI__builtin_altivec_stvebx:
+ case PPC::BI__builtin_altivec_stvehx:
+ case PPC::BI__builtin_altivec_stvewx:
+ {
+ Ops[2] = Builder.CreateBitCast(Ops[2], llvm::Type::getInt8PtrTy(VMContext));
+ Ops[1] = !isa<Constant>(Ops[1]) || !cast<Constant>(Ops[1])->isNullValue()
+ ? Builder.CreateGEP(Ops[2], Ops[1], "tmp") : Ops[2];
+ Ops.pop_back();
+
+ switch (BuiltinID) {
+ default: assert(0 && "Unsupported vavg intrinsic!");
+ case PPC::BI__builtin_altivec_stvx:
+ ID = Intrinsic::ppc_altivec_stvx;
+ break;
+ case PPC::BI__builtin_altivec_stvxl:
+ ID = Intrinsic::ppc_altivec_stvxl;
+ break;
+ case PPC::BI__builtin_altivec_stvebx:
+ ID = Intrinsic::ppc_altivec_stvebx;
+ break;
+ case PPC::BI__builtin_altivec_stvehx:
+ ID = Intrinsic::ppc_altivec_stvehx;
+ break;
+ case PPC::BI__builtin_altivec_stvewx:
+ ID = Intrinsic::ppc_altivec_stvewx;
+ break;
+ }
+ llvm::Function *F = CGM.getIntrinsic(ID);
+ return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "");
+ }
+ }
return 0;
}
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 93a182f..74cf113 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -297,15 +297,15 @@ void CodeGenModule::getMangledCXXDtorName(MangleBuffer &Name,
getMangleContext().mangleCXXDtor(D, Type, Name.getBuffer());
}
-static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex,
+static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VTableIndex,
llvm::Value *This, const llvm::Type *Ty) {
Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo();
- llvm::Value *Vtable = CGF.Builder.CreateBitCast(This, Ty);
- Vtable = CGF.Builder.CreateLoad(Vtable);
+ llvm::Value *VTable = CGF.Builder.CreateBitCast(This, Ty);
+ VTable = CGF.Builder.CreateLoad(VTable);
llvm::Value *VFuncPtr =
- CGF.Builder.CreateConstInBoundsGEP1_64(Vtable, VtableIndex, "vfn");
+ CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn");
return CGF.Builder.CreateLoad(VFuncPtr);
}
@@ -313,7 +313,7 @@ llvm::Value *
CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
const llvm::Type *Ty) {
MD = MD->getCanonicalDecl();
- uint64_t VTableIndex = CGM.getVTables().getMethodVtableIndex(MD);
+ uint64_t VTableIndex = CGM.getVTables().getMethodVTableIndex(MD);
return ::BuildVirtualCall(*this, VTableIndex, This, Ty);
}
@@ -323,7 +323,7 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
llvm::Value *&This, const llvm::Type *Ty) {
DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl());
uint64_t VTableIndex =
- CGM.getVTables().getMethodVtableIndex(GlobalDecl(DD, Type));
+ CGM.getVTables().getMethodVTableIndex(GlobalDecl(DD, Type));
return ::BuildVirtualCall(*this, VTableIndex, This, Ty);
}
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index cb1ecc1..92d15d9 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -528,7 +528,7 @@ static bool HasIncompleteReturnTypeOrArgumentTypes(const FunctionProtoType *T) {
}
const llvm::Type *
-CodeGenTypes::GetFunctionTypeForVtable(const CXXMethodDecl *MD) {
+CodeGenTypes::GetFunctionTypeForVTable(const CXXMethodDecl *MD) {
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
if (!HasIncompleteReturnTypeOrArgumentTypes(FPT))
@@ -586,8 +586,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
case ABIArgInfo::Indirect:
PAL.push_back(llvm::AttributeWithIndex::get(Index,
- llvm::Attribute::StructRet |
- llvm::Attribute::NoAlias));
+ llvm::Attribute::StructRet));
++Index;
// sret disables readnone and readonly
FuncAttrs &= ~(llvm::Attribute::ReadOnly |
@@ -870,7 +869,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
const CallArgList &CallArgs,
- const Decl *TargetDecl) {
+ const Decl *TargetDecl,
+ llvm::Instruction **callOrInvoke) {
// FIXME: We no longer need the types from CallArgs; lift up and simplify.
llvm::SmallVector<llvm::Value*, 16> Args;
@@ -996,6 +996,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Args.data(), Args.data()+Args.size());
EmitBlock(Cont);
}
+ if (callOrInvoke) {
+ *callOrInvoke = CS.getInstruction();
+ }
CS.setAttributes(Attrs);
CS.setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 177e862..a604eef 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -20,65 +20,61 @@ using namespace clang;
using namespace CodeGen;
static uint64_t
-ComputeNonVirtualBaseClassOffset(ASTContext &Context,
- const CXXBasePath &Path,
- unsigned Start) {
+ComputeNonVirtualBaseClassOffset(ASTContext &Context,
+ const CXXRecordDecl *DerivedClass,
+ CXXBaseSpecifierArray::iterator Start,
+ CXXBaseSpecifierArray::iterator End) {
uint64_t Offset = 0;
-
- for (unsigned i = Start, e = Path.size(); i != e; ++i) {
- const CXXBasePathElement& Element = Path[i];
+
+ const CXXRecordDecl *RD = DerivedClass;
+
+ for (CXXBaseSpecifierArray::iterator I = Start; I != End; ++I) {
+ const CXXBaseSpecifier *Base = *I;
+ assert(!Base->isVirtual() && "Should not see virtual bases here!");
// Get the layout.
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- const CXXBaseSpecifier *BS = Element.Base;
- assert(!BS->isVirtual() && "Should not see virtual bases here!");
-
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(BS->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
// Add the offset.
- Offset += Layout.getBaseClassOffset(Base) / 8;
+ Offset += Layout.getBaseClassOffset(BaseDecl);
+
+ RD = BaseDecl;
}
-
- return Offset;
+
+ // FIXME: We should not use / 8 here.
+ return Offset / 8;
}
llvm::Constant *
-CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *Class,
- const CXXRecordDecl *BaseClass) {
- if (Class == BaseClass)
- return 0;
-
- CXXBasePaths Paths(/*FindAmbiguities=*/false,
- /*RecordPaths=*/true, /*DetectVirtual=*/false);
- if (!const_cast<CXXRecordDecl *>(Class)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClass), Paths)) {
- assert(false && "Class must be derived from the passed in base class!");
- return 0;
- }
+CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl,
+ const CXXBaseSpecifierArray &BasePath) {
+ assert(!BasePath.empty() && "Base path should not be empty!");
- uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(),
- Paths.front(), 0);
+ uint64_t Offset =
+ ComputeNonVirtualBaseClassOffset(getContext(), ClassDecl,
+ BasePath.begin(), BasePath.end());
if (!Offset)
return 0;
-
+
const llvm::Type *PtrDiffTy =
- Types.ConvertType(getContext().getPointerDiffType());
-
+ Types.ConvertType(getContext().getPointerDiffType());
+
return llvm::ConstantInt::get(PtrDiffTy, Offset);
}
-/// Gets the address of a virtual base class within a complete object.
+/// Gets the address of a direct base class within a complete object.
/// This should only be used for (1) non-virtual bases or (2) virtual bases
/// when the type is known to be complete (e.g. in complete destructors).
///
/// The object pointed to by 'This' is assumed to be non-null.
llvm::Value *
-CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This,
- bool isBaseVirtual,
- const CXXRecordDecl *Derived,
- const CXXRecordDecl *Base) {
+CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This,
+ const CXXRecordDecl *Derived,
+ const CXXRecordDecl *Base,
+ bool BaseIsVirtual) {
// 'this' must be a pointer (in some address space) to Derived.
assert(This->getType()->isPointerTy() &&
cast<llvm::PointerType>(This->getType())->getElementType()
@@ -87,7 +83,7 @@ CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This,
// Compute the offset of the virtual base.
uint64_t Offset;
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived);
- if (isBaseVirtual)
+ if (BaseIsVirtual)
Offset = Layout.getVBaseClassOffset(Base);
else
Offset = Layout.getBaseClassOffset(Base);
@@ -105,51 +101,63 @@ CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This,
return V;
}
-llvm::Value *
-CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
- const CXXRecordDecl *Class,
- const CXXRecordDecl *BaseClass,
- bool NullCheckValue) {
- QualType BTy =
- getContext().getCanonicalType(
- getContext().getTypeDeclType(BaseClass));
- const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy));
-
- if (Class == BaseClass) {
- // Just cast back.
- return Builder.CreateBitCast(Value, BasePtrTy);
- }
+static llvm::Value *
+ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr,
+ uint64_t NonVirtual, llvm::Value *Virtual) {
+ const llvm::Type *PtrDiffTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
+
+ llvm::Value *NonVirtualOffset = 0;
+ if (NonVirtual)
+ NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, NonVirtual);
+
+ llvm::Value *BaseOffset;
+ if (Virtual) {
+ if (NonVirtualOffset)
+ BaseOffset = CGF.Builder.CreateAdd(Virtual, NonVirtualOffset);
+ else
+ BaseOffset = Virtual;
+ } else
+ BaseOffset = NonVirtualOffset;
+
+ // Apply the base offset.
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ ThisPtr = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy);
+ ThisPtr = CGF.Builder.CreateGEP(ThisPtr, BaseOffset, "add.ptr");
- CXXBasePaths Paths(/*FindAmbiguities=*/false,
- /*RecordPaths=*/true, /*DetectVirtual=*/false);
- if (!const_cast<CXXRecordDecl *>(Class)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClass), Paths)) {
- assert(false && "Class must be derived from the passed in base class!");
- return 0;
- }
+ return ThisPtr;
+}
- unsigned Start = 0;
- llvm::Value *VirtualOffset = 0;
+llvm::Value *
+CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
+ const CXXRecordDecl *Derived,
+ const CXXBaseSpecifierArray &BasePath,
+ bool NullCheckValue) {
+ assert(!BasePath.empty() && "Base path should not be empty!");
- const CXXBasePath &Path = Paths.front();
+ CXXBaseSpecifierArray::iterator Start = BasePath.begin();
const CXXRecordDecl *VBase = 0;
- for (unsigned i = 0, e = Path.size(); i != e; ++i) {
- const CXXBasePathElement& Element = Path[i];
- if (Element.Base->isVirtual()) {
- Start = i+1;
- QualType VBaseType = Element.Base->getType();
- VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
- }
+
+ // Get the virtual base.
+ if ((*Start)->isVirtual()) {
+ VBase =
+ cast<CXXRecordDecl>((*Start)->getType()->getAs<RecordType>()->getDecl());
+ ++Start;
}
+
+ uint64_t NonVirtualOffset =
+ ComputeNonVirtualBaseClassOffset(getContext(), VBase ? VBase : Derived,
+ Start, BasePath.end());
- uint64_t Offset =
- ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start);
+ // Get the base pointer type.
+ const llvm::Type *BasePtrTy =
+ ConvertType((BasePath.end()[-1])->getType())->getPointerTo();
- if (!Offset && !VBase) {
+ if (!NonVirtualOffset && !VBase) {
// Just cast back.
return Builder.CreateBitCast(Value, BasePtrTy);
}
-
+
llvm::BasicBlock *CastNull = 0;
llvm::BasicBlock *CastNotNull = 0;
llvm::BasicBlock *CastEnd = 0;
@@ -165,28 +173,15 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
EmitBlock(CastNotNull);
}
-
+
+ llvm::Value *VirtualOffset = 0;
+
if (VBase)
- VirtualOffset = GetVirtualBaseClassOffset(Value, Class, VBase);
+ VirtualOffset = GetVirtualBaseClassOffset(Value, Derived, VBase);
- const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
- llvm::Value *NonVirtualOffset = 0;
- if (Offset)
- NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset);
-
- llvm::Value *BaseOffset;
- if (VBase) {
- if (NonVirtualOffset)
- BaseOffset = Builder.CreateAdd(VirtualOffset, NonVirtualOffset);
- else
- BaseOffset = VirtualOffset;
- } else
- BaseOffset = NonVirtualOffset;
-
- // Apply the base offset.
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
- Value = Builder.CreateBitCast(Value, Int8PtrTy);
- Value = Builder.CreateGEP(Value, BaseOffset, "add.ptr");
+ // Apply the offsets.
+ Value = ApplyNonVirtualAndVirtualOffset(*this, Value, NonVirtualOffset,
+ VirtualOffset);
// Cast back.
Value = Builder.CreateBitCast(Value, BasePtrTy);
@@ -210,21 +205,17 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
llvm::Value *
CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
- const CXXRecordDecl *Class,
- const CXXRecordDecl *DerivedClass,
+ const CXXRecordDecl *Derived,
+ const CXXBaseSpecifierArray &BasePath,
bool NullCheckValue) {
+ assert(!BasePath.empty() && "Base path should not be empty!");
+
QualType DerivedTy =
- getContext().getCanonicalType(
- getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClass)));
+ getContext().getCanonicalType(getContext().getTagDeclType(Derived));
const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
- if (Class == DerivedClass) {
- // Just cast back.
- return Builder.CreateBitCast(Value, DerivedPtrTy);
- }
-
llvm::Value *NonVirtualOffset =
- CGM.GetNonVirtualBaseClassOffset(DerivedClass, Class);
+ CGM.GetNonVirtualBaseClassOffset(Derived, BasePath);
if (!NonVirtualOffset) {
// No offset, we can just cast back.
@@ -274,23 +265,16 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
/// EmitCopyCtorCall - Emit a call to a copy constructor.
static void
-EmitCopyCtorCall(CodeGenFunction &CGF,
- const CXXConstructorDecl *CopyCtor, CXXCtorType CopyCtorType,
- llvm::Value *ThisPtr, llvm::Value *VTT, llvm::Value *Src) {
- llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, CopyCtorType);
+EmitCopyCtorCall(CodeGenFunction &CGF, const CXXConstructorDecl *CopyCtor,
+ llvm::Value *ThisPtr, llvm::Value *Src) {
+ llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, Ctor_Complete);
CallArgList CallArgs;
// Push the this ptr.
CallArgs.push_back(std::make_pair(RValue::get(ThisPtr),
CopyCtor->getThisType(CGF.getContext())));
-
- // Push the VTT parameter if necessary.
- if (VTT) {
- QualType T = CGF.getContext().getPointerType(CGF.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),
CopyCtor->getParamDecl(0)->getType()));
@@ -325,13 +309,8 @@ EmitCopyCtorCall(CodeGenFunction &CGF,
// FIXME. Consolidate this with EmitCXXAggrConstructorCall.
void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
llvm::Value *Src,
- const ArrayType *Array,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty) {
- const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
- assert(CA && "VLA cannot be copied over");
- bool BitwiseCopy = BaseClassDecl->hasTrivialCopyConstructor();
-
+ const ConstantArrayType *Array,
+ const CXXRecordDecl *ClassDecl) {
// Create a temporary for the loop index and initialize it with 0.
llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
"loop.index");
@@ -347,7 +326,7 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
llvm::BasicBlock *ForBody = createBasicBlock("for.body");
// Generate: if (loop-index < number-of-elements fall to the loop body,
// otherwise, go to the block after the for-loop.
- uint64_t NumElements = getContext().getConstantArrayElementCount(CA);
+ uint64_t NumElements = getContext().getConstantArrayElementCount(Array);
llvm::Value * NumElementsPtr =
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements);
llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
@@ -362,95 +341,8 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
Counter = Builder.CreateLoad(IndexPtr);
Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress");
Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress");
- if (BitwiseCopy)
- EmitAggregateCopy(Dest, Src, Ty);
- else if (CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(getContext(), 0))
- EmitCopyCtorCall(*this, BaseCopyCtor, Ctor_Complete, Dest, 0, Src);
-
- EmitBlock(ContinueBlock);
-
- // Emit the increment of the loop counter.
- llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
- Counter = Builder.CreateLoad(IndexPtr);
- NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
- Builder.CreateStore(NextVal, IndexPtr);
-
- // Finally, branch back up to the condition for the next iteration.
- EmitBranch(CondBlock);
-
- // Emit the fall-through block.
- EmitBlock(AfterFor, true);
-}
-
-/// EmitClassAggrCopyAssignment - This routine generates code to assign a class
-/// array of objects from SrcValue to DestValue. Assignment can be either a
-/// bitwise assignment or via a copy assignment operator function call.
-/// FIXME. This can be consolidated with EmitClassAggrMemberwiseCopy
-void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
- llvm::Value *Src,
- const ArrayType *Array,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty) {
- const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
- assert(CA && "VLA cannot be asssigned");
- bool BitwiseAssign = BaseClassDecl->hasTrivialCopyAssignment();
-
- // Create a temporary for the loop index and initialize it with 0.
- llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
- "loop.index");
- llvm::Value* zeroConstant =
- llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
- Builder.CreateStore(zeroConstant, IndexPtr);
- // Start the loop with a block that tests the condition.
- llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
- llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
-
- EmitBlock(CondBlock);
-
- llvm::BasicBlock *ForBody = createBasicBlock("for.body");
- // Generate: if (loop-index < number-of-elements fall to the loop body,
- // otherwise, go to the block after the for-loop.
- uint64_t NumElements = getContext().getConstantArrayElementCount(CA);
- llvm::Value * NumElementsPtr =
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements);
- llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
- llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr,
- "isless");
- // If the condition is true, execute the body.
- Builder.CreateCondBr(IsLess, ForBody, AfterFor);
-
- EmitBlock(ForBody);
- llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
- // Inside the loop body, emit the assignment operator call on array element.
- Counter = Builder.CreateLoad(IndexPtr);
- Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress");
- Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress");
- const CXXMethodDecl *MD = 0;
- if (BitwiseAssign)
- EmitAggregateCopy(Dest, Src, Ty);
- else {
- BaseClassDecl->hasConstCopyAssignment(getContext(), MD);
- assert(MD && "EmitClassAggrCopyAssignment - No user assign");
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *LTy =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
- llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy);
-
- CallArgList CallArgs;
- // Push the this (Dest) ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Dest),
- MD->getThisType(getContext())));
-
- // Push the Src ptr.
- QualType SrcTy = MD->getParamDecl(0)->getType();
- RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) :
- RValue::getAggregate(Src);
- CallArgs.push_back(std::make_pair(SrcValue, SrcTy));
- EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
- Callee, ReturnValueSlot(), CallArgs, MD);
- }
+ EmitClassMemberwiseCopy(Dest, Src, ClassDecl);
+
EmitBlock(ContinueBlock);
// Emit the increment of the loop counter.
@@ -468,7 +360,8 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
/// 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) {
+static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD,
+ bool ForVirtualBase) {
if (!CodeGenVTables::needsVTTParameter(GD)) {
// This constructor/destructor does not need a VTT parameter.
return 0;
@@ -486,9 +379,16 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) {
if (RD == Base) {
assert(!CodeGenVTables::needsVTTParameter(CGF.CurGD) &&
"doing no-op VTT offset in base dtor/ctor?");
+ assert(!ForVirtualBase && "Can't have same class as virtual base!");
SubVTTIndex = 0;
} else {
- SubVTTIndex = CGF.CGM.getVTables().getSubVTTIndex(RD, Base);
+ const ASTRecordLayout &Layout =
+ CGF.getContext().getASTRecordLayout(RD);
+ uint64_t BaseOffset = ForVirtualBase ?
+ Layout.getVBaseClassOffset(Base) : Layout.getBaseClassOffset(Base);
+
+ SubVTTIndex =
+ CGF.CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset));
assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!");
}
@@ -511,75 +411,16 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) {
/// or via a copy constructor call.
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);
+ const CXXRecordDecl *ClassDecl) {
+ if (ClassDecl->hasTrivialCopyConstructor()) {
+ EmitAggregateCopy(Dest, Src, getContext().getTagDeclType(ClassDecl));
return;
}
- CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(getContext(), 0);
- if (!BaseCopyCtor)
- return;
+ CXXConstructorDecl *CopyCtor = ClassDecl->getCopyConstructor(getContext(), 0);
+ assert(CopyCtor && "Did not have copy ctor!");
- llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(BaseCopyCtor, CtorType));
- EmitCopyCtorCall(*this, BaseCopyCtor, CtorType, Dest, VTT, Src);
-}
-
-/// EmitClassCopyAssignment - This routine generates code to copy assign a class
-/// object from SrcValue to DestValue. Assignment can be either a bitwise
-/// assignment of via an assignment operator call.
-// FIXME. Consolidate this with EmitClassMemberwiseCopy as they share a lot.
-void CodeGenFunction::EmitClassCopyAssignment(
- llvm::Value *Dest, llvm::Value *Src,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty) {
- if (ClassDecl) {
- Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- }
- if (BaseClassDecl->hasTrivialCopyAssignment()) {
- EmitAggregateCopy(Dest, Src, Ty);
- return;
- }
-
- const CXXMethodDecl *MD = 0;
- BaseClassDecl->hasConstCopyAssignment(getContext(), MD);
- assert(MD && "EmitClassCopyAssignment - missing copy assign");
-
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *LTy =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
- llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy);
-
- CallArgList CallArgs;
- // Push the this (Dest) ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Dest),
- MD->getThisType(getContext())));
-
- // Push the Src ptr.
- QualType SrcTy = MD->getParamDecl(0)->getType();
- RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) :
- RValue::getAggregate(Src);
- CallArgs.push_back(std::make_pair(SrcValue, SrcTy));
- EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
- Callee, ReturnValueSlot(), CallArgs, MD);
+ EmitCopyCtorCall(*this, CopyCtor, Dest, Src);
}
/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a
@@ -600,30 +441,25 @@ void CodeGenFunction::EmitClassCopyAssignment(
void
CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) {
const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(CurGD.getDecl());
+ CXXCtorType CtorType = CurGD.getCtorType();
+ (void) CtorType;
+
const CXXRecordDecl *ClassDecl = Ctor->getParent();
assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
"SynthesizeCXXCopyConstructor - copy constructor has definition already");
assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor");
- FunctionArgList::const_iterator i = Args.begin();
- const VarDecl *ThisArg = i->first;
- llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg);
- llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this");
- const VarDecl *SrcArg = (i+1)->first;
- llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg);
- llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj);
-
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- // FIXME. copy constrution of virtual base NYI
- if (Base->isVirtual())
- continue;
+ llvm::Value *ThisPtr = LoadCXXThis();
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- EmitClassMemberwiseCopy(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl,
- Base->getType());
- }
+ // Find the source pointer.
+ unsigned SrcArgIndex = Args.size() - 1;
+ assert(CtorType == Ctor_Base || SrcArgIndex == 1);
+ assert(CtorType != Ctor_Base ||
+ (ClassDecl->getNumVBases() != 0 && SrcArgIndex == 2) ||
+ SrcArgIndex == 1);
+
+ llvm::Value *SrcPtr =
+ Builder.CreateLoad(GetAddrOfLocalVar(Args[SrcArgIndex].first));
for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
E = ClassDecl->field_end(); I != E; ++I) {
@@ -638,27 +474,26 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) {
if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- LValue LHS = EmitLValueForField(LoadOfThis, Field, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, Field, 0);
+ LValue LHS = EmitLValueForField(ThisPtr, Field, 0);
+ LValue RHS = EmitLValueForField(SrcPtr, Field, 0);
if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ const llvm::Type *BasePtr = ConvertType(FieldType)->getPointerTo();
llvm::Value *DestBaseAddrPtr =
Builder.CreateBitCast(LHS.getAddress(), BasePtr);
llvm::Value *SrcBaseAddrPtr =
Builder.CreateBitCast(RHS.getAddress(), BasePtr);
EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array,
- FieldClassDecl, FieldType);
+ FieldClassDecl);
}
else
EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(),
- 0 /*ClassDecl*/, FieldClassDecl, FieldType);
+ FieldClassDecl);
continue;
}
// Do a built-in assignment of scalar data members.
- LValue LHS = EmitLValueForFieldInitialization(LoadOfThis, Field, 0);
- LValue RHS = EmitLValueForFieldInitialization(LoadOfSrc, Field, 0);
+ LValue LHS = EmitLValueForFieldInitialization(ThisPtr, Field, 0);
+ LValue RHS = EmitLValueForFieldInitialization(SrcPtr, Field, 0);
if (!hasAggregateLLVMType(Field->getType())) {
RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
@@ -675,100 +510,6 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) {
InitializeVTablePointers(ClassDecl);
}
-/// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator.
-/// Before the implicitly-declared copy assignment operator for a class is
-/// implicitly defined, all implicitly- declared copy assignment operators for
-/// its direct base classes and its nonstatic data members shall have been
-/// implicitly defined. [12.8-p12]
-/// The implicitly-defined copy assignment operator for class X performs
-/// memberwise assignment of its subob- jects. The direct base classes of X are
-/// assigned first, in the order of their declaration in
-/// the base-specifier-list, and then the immediate nonstatic data members of X
-/// are assigned, in the order in which they were declared in the class
-/// definition.Each subobject is assigned in the manner appropriate to its type:
-/// if the subobject is of class type, the copy assignment operator for the
-/// class is used (as if by explicit qualification; that is, ignoring any
-/// possible virtual overriding functions in more derived classes);
-///
-/// if the subobject is an array, each element is assigned, in the manner
-/// appropriate to the element type;
-///
-/// if the subobject is of scalar type, the built-in assignment operator is
-/// used.
-void CodeGenFunction::SynthesizeCXXCopyAssignment(const FunctionArgList &Args) {
- const CXXMethodDecl *CD = cast<CXXMethodDecl>(CurGD.getDecl());
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
- assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
- "SynthesizeCXXCopyAssignment - copy assignment has user declaration");
-
- FunctionArgList::const_iterator i = Args.begin();
- const VarDecl *ThisArg = i->first;
- llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg);
- llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this");
- const VarDecl *SrcArg = (i+1)->first;
- llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg);
- llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj);
-
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- // FIXME. copy assignment of virtual base NYI
- if (Base->isVirtual())
- continue;
-
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- EmitClassCopyAssignment(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl,
- Base->getType());
- }
-
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = getContext().getCanonicalType((*Field)->getType());
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
-
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- LValue LHS = EmitLValueForField(LoadOfThis, *Field, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, *Field, 0);
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *DestBaseAddrPtr =
- Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- llvm::Value *SrcBaseAddrPtr =
- Builder.CreateBitCast(RHS.getAddress(), BasePtr);
- EmitClassAggrCopyAssignment(DestBaseAddrPtr, SrcBaseAddrPtr, Array,
- FieldClassDecl, FieldType);
- }
- else
- EmitClassCopyAssignment(LHS.getAddress(), RHS.getAddress(),
- 0 /*ClassDecl*/, FieldClassDecl, FieldType);
- continue;
- }
- // Do a built-in assignment of scalar data members.
- LValue LHS = EmitLValueForField(LoadOfThis, *Field, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, *Field, 0);
- if (!hasAggregateLLVMType(Field->getType())) {
- RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
- EmitStoreThroughLValue(RVRHS, LHS, Field->getType());
- } else if (Field->getType()->isAnyComplexType()) {
- ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(),
- RHS.isVolatileQualified());
- StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified());
- } else {
- EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType());
- }
- }
-
- // return *this;
- Builder.CreateStore(LoadOfThis, ReturnValue);
-}
-
static void EmitBaseInitializer(CodeGenFunction &CGF,
const CXXRecordDecl *ClassDecl,
CXXBaseOrMemberInitializer *BaseInit,
@@ -782,15 +523,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
CXXRecordDecl *BaseClassDecl =
cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
- // FIXME: This method of determining whether a base is virtual is ridiculous;
- // it should be part of BaseInit.
- bool isBaseVirtual = false;
- for (CXXRecordDecl::base_class_const_iterator I = ClassDecl->vbases_begin(),
- E = ClassDecl->vbases_end(); I != E; ++I)
- if (I->getType()->getAs<RecordType>()->getDecl() == BaseClassDecl) {
- isBaseVirtual = true;
- break;
- }
+ bool isBaseVirtual = BaseInit->isBaseVirtual();
// The base constructor doesn't construct virtual bases.
if (CtorType == Ctor_Base && isBaseVirtual)
@@ -798,9 +531,10 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
// We can pretend to be a complete class because it only matters for
// virtual bases, and we only do virtual bases for complete ctors.
- llvm::Value *V = ThisPtr;
- V = CGF.GetAddressOfBaseOfCompleteClass(V, isBaseVirtual,
- ClassDecl, BaseClassDecl);
+ llvm::Value *V =
+ CGF.GetAddressOfDirectBaseInCompleteClass(ThisPtr, ClassDecl,
+ BaseClassDecl,
+ BaseInit->isBaseVirtual());
CGF.EmitAggExpr(BaseInit->getInit(), V, false, false, true);
@@ -809,7 +543,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
CodeGenFunction::EHCleanupBlock Cleanup(CGF);
CXXDestructorDecl *DD = BaseClassDecl->getDestructor(CGF.getContext());
- CGF.EmitCXXDestructorCall(DD, Dtor_Base, V);
+ CGF.EmitCXXDestructorCall(DD, Dtor_Base, isBaseVirtual, V);
}
}
@@ -850,7 +584,9 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
LHS.isVolatileQualified());
} else {
CGF.EmitAggExpr(MemberInit->getInit(), LHS.getAddress(),
- LHS.isVolatileQualified(), false, true);
+ LHS.isVolatileQualified(),
+ /*IgnoreResult*/ false,
+ /*IsInitializer*/ true);
if (!CGF.Exceptions)
return;
@@ -868,7 +604,8 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0);
CXXDestructorDecl *DD = RD->getDestructor(CGF.getContext());
- CGF.EmitCXXDestructorCall(DD, Dtor_Complete, LHS.getAddress());
+ CGF.EmitCXXDestructorCall(DD, Dtor_Complete, /*ForVirtualBase=*/false,
+ LHS.getAddress());
}
}
}
@@ -976,8 +713,6 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
llvm::SmallVector<CXXBaseOrMemberInitializer *, 8> MemberInitializers;
- // FIXME: Add vbase initialization
-
for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(),
E = CD->init_end();
B != E; ++B) {
@@ -1028,7 +763,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// variant, then call the appropriate operator delete() on the way
// out.
if (DtorType == Dtor_Deleting) {
- EmitCXXDestructorCall(Dtor, Dtor_Complete, LoadCXXThis());
+ EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
+ LoadCXXThis());
SkipBody = true;
// If this is the complete variant, just invoke the base variant;
@@ -1036,7 +772,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// this optimization if the body is a function-try-block, because
// we'd introduce *two* handler blocks.
} else if (!isTryBody && DtorType == Dtor_Complete) {
- EmitCXXDestructorCall(Dtor, Dtor_Base, LoadCXXThis());
+ EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false,
+ LoadCXXThis());
SkipBody = true;
// Otherwise, we're in the base variant, so we need to ensure the
@@ -1117,11 +854,11 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
if (BaseClassDecl->hasTrivialDestructor())
continue;
const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
- llvm::Value *V = GetAddressOfBaseOfCompleteClass(LoadCXXThis(),
- true,
- ClassDecl,
- BaseClassDecl);
- EmitCXXDestructorCall(D, Dtor_Base, V);
+ llvm::Value *V =
+ GetAddressOfDirectBaseInCompleteClass(LoadCXXThis(),
+ ClassDecl, BaseClassDecl,
+ /*BaseIsVirtual=*/true);
+ EmitCXXDestructorCall(D, Dtor_Base, /*ForVirtualBase=*/true, V);
}
return;
}
@@ -1175,7 +912,8 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
Array, BaseAddrPtr);
} else
EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()),
- Dtor_Complete, LHS.getAddress());
+ Dtor_Complete, /*ForVirtualBase=*/false,
+ LHS.getAddress());
}
// Destroy non-virtual bases.
@@ -1193,12 +931,14 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
// Ignore trivial destructors.
if (BaseClassDecl->hasTrivialDestructor())
continue;
- const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
-
- llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(),
- ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- EmitCXXDestructorCall(D, Dtor_Base, V);
+
+ const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
+ llvm::Value *V =
+ GetAddressOfDirectBaseInCompleteClass(LoadCXXThis(), ClassDecl,
+ BaseClassDecl,
+ /*BaseIsVirtual=*/false);
+
+ EmitCXXDestructorCall(D, Dtor_Base, /*ForVirtualBase=*/false, V);
}
}
@@ -1271,7 +1011,8 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
{
CXXTemporariesCleanupScope Scope(*this);
- EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd);
+ EmitCXXConstructorCall(D, Ctor_Complete, /*ForVirtualBase=*/false, Address,
+ ArgBeg, ArgEnd);
}
EmitBlock(ContinueBlock);
@@ -1345,7 +1086,7 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
Counter = Builder.CreateLoad(IndexPtr);
Counter = Builder.CreateSub(Counter, One);
llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx");
- EmitCXXDestructorCall(D, Dtor_Complete, Address);
+ EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, Address);
EmitBlock(ContinueBlock);
@@ -1390,6 +1131,7 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
getContext().getTranslationUnitDecl(),
SourceLocation(), II, R, 0,
FunctionDecl::Static,
+ FunctionDecl::None,
false, true);
StartFunction(FD, R, Fn, Args, SourceLocation());
QualType BaseElementTy = getContext().getBaseElementType(Array);
@@ -1407,7 +1149,7 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
void
CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
- CXXCtorType Type,
+ CXXCtorType Type, bool ForVirtualBase,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
@@ -1429,7 +1171,7 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
return;
}
- llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type));
+ llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type), ForVirtualBase);
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd);
@@ -1450,7 +1192,8 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
++I;
// vtt
- if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType))) {
+ if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType),
+ /*ForVirtualBase=*/false)) {
QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy);
DelegateArgs.push_back(std::make_pair(RValue::get(VTT), VoidPP));
@@ -1502,8 +1245,10 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
CXXDtorType Type,
+ bool ForVirtualBase,
llvm::Value *This) {
- llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type));
+ llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type),
+ ForVirtualBase);
llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0);
@@ -1538,7 +1283,8 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This,
void
CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
- bool BaseIsMorallyVirtual,
+ const CXXRecordDecl *NearestVBase,
+ uint64_t OffsetFromNearestVBase,
llvm::Constant *VTable,
const CXXRecordDecl *VTableClass) {
const CXXRecordDecl *RD = Base.getBase();
@@ -1548,7 +1294,7 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
// Check if we need to use a vtable from the VTT.
if (CodeGenVTables::needsVTTParameter(CurGD) &&
- (RD->getNumVBases() || BaseIsMorallyVirtual)) {
+ (RD->getNumVBases() || NearestVBase)) {
// Get the secondary vpointer index.
uint64_t VirtualPointerIndex =
CGM.getVTables().getSecondaryVirtualPointerIndex(VTableClass, Base);
@@ -1567,20 +1313,27 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
}
// Compute where to store the address point.
- llvm::Value *VTableField;
+ llvm::Value *VirtualOffset = 0;
+ uint64_t NonVirtualOffset = 0;
- if (CodeGenVTables::needsVTTParameter(CurGD) && BaseIsMorallyVirtual) {
+ if (CodeGenVTables::needsVTTParameter(CurGD) && NearestVBase) {
// We need to use the virtual base offset offset because the virtual base
// might have a different offset in the most derived class.
- VTableField = GetAddressOfBaseClass(LoadCXXThis(), VTableClass, RD,
- /*NullCheckValue=*/false);
+ VirtualOffset = GetVirtualBaseClassOffset(LoadCXXThis(), VTableClass,
+ NearestVBase);
+ NonVirtualOffset = OffsetFromNearestVBase / 8;
} else {
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
-
- VTableField = Builder.CreateBitCast(LoadCXXThis(), Int8PtrTy);
- VTableField =
- Builder.CreateConstInBoundsGEP1_64(VTableField, Base.getBaseOffset() / 8);
+ // We can just use the base offset in the complete class.
+ NonVirtualOffset = Base.getBaseOffset() / 8;
}
+
+ // Apply the offsets.
+ llvm::Value *VTableField = LoadCXXThis();
+
+ if (NonVirtualOffset || VirtualOffset)
+ VTableField = ApplyNonVirtualAndVirtualOffset(*this, VTableField,
+ NonVirtualOffset,
+ VirtualOffset);
// Finally, store the address point.
const llvm::Type *AddressPointPtrTy =
@@ -1591,7 +1344,8 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
void
CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
- bool BaseIsMorallyVirtual,
+ const CXXRecordDecl *NearestVBase,
+ uint64_t OffsetFromNearestVBase,
bool BaseIsNonVirtualPrimaryBase,
llvm::Constant *VTable,
const CXXRecordDecl *VTableClass,
@@ -1600,7 +1354,8 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
// been set.
if (!BaseIsNonVirtualPrimaryBase) {
// Initialize the vtable pointer for this base.
- InitializeVTablePointer(Base, BaseIsMorallyVirtual, VTable, VTableClass);
+ InitializeVTablePointer(Base, NearestVBase, OffsetFromNearestVBase,
+ VTable, VTableClass);
}
const CXXRecordDecl *RD = Base.getBase();
@@ -1616,7 +1371,7 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
continue;
uint64_t BaseOffset;
- bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
+ uint64_t BaseOffsetFromNearestVBase;
bool BaseDeclIsNonVirtualPrimaryBase;
if (I->isVirtual()) {
@@ -1628,17 +1383,20 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
getContext().getASTRecordLayout(VTableClass);
BaseOffset = Layout.getVBaseClassOffset(BaseDecl);
- BaseDeclIsMorallyVirtual = true;
+ BaseOffsetFromNearestVBase = 0;
BaseDeclIsNonVirtualPrimaryBase = false;
} else {
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl);
+ BaseOffsetFromNearestVBase =
+ OffsetFromNearestVBase + Layout.getBaseClassOffset(BaseDecl);
BaseDeclIsNonVirtualPrimaryBase = Layout.getPrimaryBase() == BaseDecl;
}
InitializeVTablePointers(BaseSubobject(BaseDecl, BaseOffset),
- BaseDeclIsMorallyVirtual,
+ I->isVirtual() ? BaseDecl : NearestVBase,
+ BaseOffsetFromNearestVBase,
BaseDeclIsNonVirtualPrimaryBase,
VTable, VTableClass, VBases);
}
@@ -1654,8 +1412,8 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) {
// Initialize the vtable pointers for this class and all of its bases.
VisitedVirtualBasesSetTy VBases;
- InitializeVTablePointers(BaseSubobject(RD, 0),
- /*BaseIsMorallyVirtual=*/false,
+ InitializeVTablePointers(BaseSubobject(RD, 0), /*NearestVBase=*/0,
+ /*OffsetFromNearestVBase=*/0,
/*BaseIsNonVirtualPrimaryBase=*/false,
VTable, RD, VBases);
}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index bcbda8a..4963e73 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -320,27 +320,9 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
FieldOffset = 0;
FType = CGM.getContext().UnsignedLongTy;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "reserved", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
+ EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset));
+ EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset));
- FieldOffset += FieldSize;
- FType = CGM.getContext().UnsignedLongTy;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "Size", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
-
- FieldOffset += FieldSize;
Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
EltTys.clear();
@@ -360,49 +342,13 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
FieldOffset = 0;
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__isa", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
-
- FieldOffset += FieldSize;
- FType = CGM.getContext().IntTy;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__flags", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
-
- FieldOffset += FieldSize;
+ EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset));
FType = CGM.getContext().IntTy;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__reserved", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
-
- FieldOffset += FieldSize;
+ EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset));
+ EltTys.push_back(CreateMemberType(Unit, FType, "__reserved", &FieldOffset));
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__FuncPtr", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
+ EltTys.push_back(CreateMemberType(Unit, FType, "__FuncPtr", &FieldOffset));
- FieldOffset += FieldSize;
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = DescTy;
FieldSize = CGM.getContext().getTypeSize(Ty);
@@ -525,13 +471,20 @@ CollectRecordFields(const RecordDecl *RD, llvm::DIFile Unit,
uint64_t FieldOffset = RL.getFieldOffset(FieldNo);
+ unsigned Flags = 0;
+ AccessSpecifier Access = I->getAccess();
+ if (Access == clang::AS_private)
+ Flags |= llvm::DIType::FlagPrivate;
+ else if (Access == clang::AS_protected)
+ Flags |= llvm::DIType::FlagProtected;
+
// Create a DW_TAG_member node to remember the offset of this field in the
// struct. FIXME: This is an absolutely insane way to capture this
// information. When we gut debug info, this should be fixed.
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
FieldName, FieldDefUnit,
FieldLine, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
+ FieldOffset, Flags, FieldTy);
EltTys.push_back(FieldTy);
}
}
@@ -626,7 +579,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
// It doesn't make sense to give a virtual destructor a vtable index,
// since a single destructor has two entries in the vtable.
if (!isa<CXXDestructorDecl>(Method))
- VIndex = CGM.getVTables().getMethodVtableIndex(Method);
+ VIndex = CGM.getVTables().getMethodVTableIndex(Method);
ContainingType = RecordTy;
}
@@ -734,8 +687,8 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) {
return VTablePtrType;
}
-/// getVtableName - Get vtable name for the given Class.
-llvm::StringRef CGDebugInfo::getVtableName(const CXXRecordDecl *RD) {
+/// getVTableName - Get vtable name for the given Class.
+llvm::StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) {
// Otherwise construct gdb compatible name name.
std::string Name = "_vptr$" + RD->getNameAsString();
@@ -746,10 +699,10 @@ llvm::StringRef CGDebugInfo::getVtableName(const CXXRecordDecl *RD) {
}
-/// CollectVtableInfo - If the C++ class has vtable info then insert appropriate
+/// CollectVTableInfo - If the C++ class has vtable info then insert appropriate
/// debug info entry in EltTys vector.
void CGDebugInfo::
-CollectVtableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
+CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys) {
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
@@ -764,7 +717,7 @@ CollectVtableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
llvm::DIType VPTR
= DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- getVtableName(RD), Unit,
+ getVTableName(RD), Unit,
0, Size, 0, 0, 0,
getOrCreateVTablePtrType(Unit));
EltTys.push_back(VPTR);
@@ -832,7 +785,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
if (CXXDecl) {
CollectCXXBases(CXXDecl, Unit, EltTys, FwdDecl);
- CollectVtableInfo(CXXDecl, Unit, EltTys);
+ CollectVTableInfo(CXXDecl, Unit, EltTys);
}
CollectRecordFields(RD, Unit, EltTys);
llvm::MDNode *ContainingType = NULL;
@@ -1293,7 +1246,6 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
case Type::MemberPointer:
return CreateType(cast<MemberPointerType>(Ty), Unit);
- case Type::InjectedClassName:
case Type::TemplateSpecialization:
case Type::Elaborated:
case Type::QualifiedName:
@@ -1318,6 +1270,21 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
return llvm::DIType();
}
+/// CreateMemberType - Create new member and increase Offset by FType's size.
+llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType,
+ llvm::StringRef Name,
+ uint64_t *Offset) {
+ llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ uint64_t FieldSize = CGM.getContext().getTypeSize(FType);
+ unsigned FieldAlign = CGM.getContext().getTypeAlign(FType);
+ llvm::DIType Ty = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member,
+ Unit, Name, Unit, 0,
+ FieldSize, FieldAlign,
+ *Offset, 0, FieldTy);
+ *Offset += FieldSize;
+ return Ty;
+}
+
/// EmitFunctionStart - Constructs the debug code for entering a function -
/// "llvm.dbg.func.start.".
void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
@@ -1341,17 +1308,15 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
}
}
Name = getFunctionName(FD);
- if (!Name.empty() && Name[0] == '\01')
- Name = Name.substr(1);
// Use mangled name as linkage name for c/c++ functions.
CGM.getMangledName(LinkageName, GD);
} else {
// Use llvm function name as linkage name.
Name = Fn->getName();
LinkageName.setString(Name);
- if (!Name.empty() && Name[0] == '\01')
- Name = Name.substr(1);
}
+ if (!Name.empty() && Name[0] == '\01')
+ Name = Name.substr(1);
// It is expected that CurLoc is set before using EmitFunctionStart.
// Usually, CurLoc points to the left bracket location of compound
@@ -1437,72 +1402,19 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
FieldOffset = 0;
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__isa", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__forwarding", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().IntTy;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__flags", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
+ EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset));
+ EltTys.push_back(CreateMemberType(Unit, FType, "__forwarding", &FieldOffset));
FType = CGM.getContext().IntTy;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__size", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
+ EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset));
+ EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset));
+
bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type);
if (HasCopyAndDispose) {
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__copy_helper", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__destroy_helper", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
+ EltTys.push_back(CreateMemberType(Unit, FType, "__copy_helper",
+ &FieldOffset));
+ EltTys.push_back(CreateMemberType(Unit, FType, "__destroy_helper",
+ &FieldOffset));
}
CharUnits Align = CGM.getContext().getDeclAlign(VD);
@@ -1517,20 +1429,12 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
llvm::APInt pad(32, NumPaddingBytes);
FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
pad, ArrayType::Normal, 0);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member,
- Unit, "", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
+ EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset));
}
}
FType = Type;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = Align.getQuantity()*8;
@@ -1558,13 +1462,6 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
llvm::Value *Storage, CGBuilderTy &Builder) {
assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
- // Do not emit variable debug information while generating optimized code.
- // The llvm optimizer and code generator are not yet ready to support
- // optimized code debugging.
- const CodeGenOptions &CGO = CGM.getCodeGenOpts();
- if (CGO.OptimizationLevel)
- return;
-
llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
llvm::DIType Ty;
uint64_t XOffset = 0;
@@ -1608,11 +1505,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
const ValueDecl *VD = BDRE->getDecl();
assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
- // Do not emit variable debug information while generating optimized code.
- // The llvm optimizer and code generator are not yet ready to support
- // optimized code debugging.
- const CodeGenOptions &CGO = CGM.getCodeGenOpts();
- if (CGO.OptimizationLevel || Builder.GetInsertBlock() == 0)
+ if (Builder.GetInsertBlock() == 0)
return;
uint64_t XOffset = 0;
@@ -1708,7 +1601,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
T = CGM.getContext().getConstantArrayType(ET, ConstVal,
ArrayType::Normal, 0);
}
- llvm::StringRef DeclName = Var->getName();
+ llvm::StringRef DeclName = D->getName();
llvm::DIDescriptor DContext =
getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()), Unit);
DebugFactory.CreateGlobalVariable(DContext, DeclName,
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 8397245..c16379a 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -112,7 +112,7 @@ class CGDebugInfo {
void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F,
llvm::SmallVectorImpl<llvm::DIDescriptor> &E);
- void CollectVtableInfo(const CXXRecordDecl *Decl,
+ void CollectVTableInfo(const CXXRecordDecl *Decl,
llvm::DIFile F,
llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys);
@@ -196,13 +196,17 @@ private:
/// CreateTypeNode - Create type metadata for a source language type.
llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F);
+ /// CreateMemberType - Create new member and increase Offset by FType's size.
+ llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType,
+ llvm::StringRef Name, uint64_t *Offset);
+
/// 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);
- /// getVtableName - Get vtable name for the given Class.
- llvm::StringRef getVtableName(const CXXRecordDecl *Decl);
+ /// getVTableName - Get vtable name for the given Class.
+ llvm::StringRef getVTableName(const CXXRecordDecl *Decl);
};
} // namespace CodeGen
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 07d219f..ba3a2b4 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -31,11 +31,44 @@ using namespace CodeGen;
void CodeGenFunction::EmitDecl(const Decl &D) {
switch (D.getKind()) {
- default:
- CGM.ErrorUnsupported(&D, "decl");
- return;
+ case Decl::TranslationUnit:
+ case Decl::Namespace:
+ case Decl::UnresolvedUsingTypename:
+ case Decl::ClassTemplateSpecialization:
+ case Decl::ClassTemplatePartialSpecialization:
+ case Decl::TemplateTypeParm:
+ case Decl::UnresolvedUsingValue:
+ case Decl::NonTypeTemplateParm:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::Field:
+ case Decl::ObjCIvar:
+ case Decl::ObjCAtDefsField:
case Decl::ParmVar:
- assert(0 && "Parmdecls should not be in declstmts!");
+ case Decl::ImplicitParam:
+ case Decl::ClassTemplate:
+ case Decl::FunctionTemplate:
+ case Decl::TemplateTemplateParm:
+ case Decl::ObjCMethod:
+ case Decl::ObjCCategory:
+ case Decl::ObjCProtocol:
+ case Decl::ObjCInterface:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCImplementation:
+ case Decl::ObjCProperty:
+ case Decl::ObjCCompatibleAlias:
+ case Decl::LinkageSpec:
+ case Decl::ObjCPropertyImpl:
+ case Decl::ObjCClass:
+ case Decl::ObjCForwardProtocol:
+ case Decl::FileScopeAsm:
+ case Decl::Friend:
+ case Decl::FriendTemplate:
+ case Decl::Block:
+
+ assert(0 && "Declaration not should not be in declstmts!");
case Decl::Function: // void X();
case Decl::Record: // struct/union/class X;
case Decl::Enum: // enum X;
@@ -44,6 +77,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Using: // using X; [C++]
case Decl::UsingShadow:
case Decl::UsingDirective: // using namespace X; [C++]
+ case Decl::NamespaceAlias:
case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
// None of these decls require codegen support.
return;
@@ -197,6 +231,9 @@ CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D,
void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D,
llvm::GlobalValue::LinkageTypes Linkage) {
+ // Bail out early if the block is unreachable.
+ if (!Builder.GetInsertBlock()) return;
+
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
@@ -205,6 +242,8 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D,
// Store into LocalDeclMap before generating initializer to handle
// circular references.
DMEntry = GV;
+ if (getContext().getLangOptions().CPlusPlus)
+ CGM.setStaticLocalDeclAddress(&D, GV);
// Make sure to evaluate VLA bounds now so that we have them for later.
//
@@ -610,6 +649,11 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
DtorTy = getContext().getBaseElementType(Array);
if (const RecordType *RT = DtorTy->getAs<RecordType>())
if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ llvm::Value *Loc = DeclPtr;
+ if (isByRef)
+ Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
+ D.getNameAsString());
+
if (!ClassDecl->hasTrivialDestructor()) {
const CXXDestructorDecl *D = ClassDecl->getDestructor(getContext());
assert(D && "EmitLocalBlockVarDecl - destructor is nul");
@@ -622,7 +666,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(DeclPtr, BasePtr);
+ Builder.CreateBitCast(Loc, BasePtr);
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
// Make sure to jump to the exit block.
@@ -634,20 +678,22 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(DeclPtr, BasePtr);
+ Builder.CreateBitCast(Loc, BasePtr);
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
}
} else {
{
DelayedCleanupBlock Scope(*this);
- EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
+ EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false,
+ Loc);
// Make sure to jump to the exit block.
EmitBranch(Scope.getCleanupExitBlock());
}
if (Exceptions) {
EHCleanupBlock Cleanup(*this);
- EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
+ EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false,
+ Loc);
}
}
}
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 40c18ca..f6c805f 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -219,9 +219,14 @@ void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
SourceLocation());
// Emit the dtors, in reverse order from construction.
- for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i)
- Builder.CreateCall(DtorsAndObjects[e - i - 1].first,
- DtorsAndObjects[e - i - 1].second);
+ for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) {
+ llvm::Constant *Callee = DtorsAndObjects[e - i - 1].first;
+ llvm::CallInst *CI = Builder.CreateCall(Callee,
+ DtorsAndObjects[e - i - 1].second);
+ // Make sure the call and the callee agree on calling convention.
+ if (llvm::Function *F = dyn_cast<llvm::Function>(Callee))
+ CI->setCallingConv(F->getCallingConv());
+ }
FinishFunction();
}
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 1e15066..c1d05bf 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -122,82 +122,71 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev");
}
-// CopyObject - Utility to copy an object. Calls copy constructor as necessary.
-// DestPtr is casted to the right type.
-static void CopyObject(CodeGenFunction &CGF, const Expr *E,
- llvm::Value *DestPtr, llvm::Value *ExceptionPtrPtr) {
- QualType ObjectType = E->getType();
-
- // Store the throw exception in the exception object.
- if (!CGF.hasAggregateLLVMType(ObjectType)) {
- llvm::Value *Value = CGF.EmitScalarExpr(E);
- const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo();
-
- CGF.Builder.CreateStore(Value,
- CGF.Builder.CreateBitCast(DestPtr, ValuePtrTy));
- } else {
- const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo();
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl());
-
- llvm::Value *This = CGF.Builder.CreateBitCast(DestPtr, Ty);
- if (RD->hasTrivialCopyConstructor()) {
- CGF.EmitAggExpr(E, This, false);
- } else if (CXXConstructorDecl *CopyCtor
- = RD->getCopyConstructor(CGF.getContext(), 0)) {
- llvm::Value *CondPtr = 0;
- if (CGF.Exceptions) {
- CodeGenFunction::EHCleanupBlock Cleanup(CGF);
- llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF);
-
- llvm::BasicBlock *CondBlock = CGF.createBasicBlock("cond.free");
- llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
- CondPtr = CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()),
- "doEHfree");
-
- CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CondPtr),
- CondBlock, Cont);
- CGF.EmitBlock(CondBlock);
-
- // Load the exception pointer.
- llvm::Value *ExceptionPtr = CGF.Builder.CreateLoad(ExceptionPtrPtr);
- CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr);
-
- CGF.EmitBlock(Cont);
- }
-
- if (CondPtr)
- CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()),
- CondPtr);
-
- llvm::Value *Src = CGF.EmitLValue(E).getAddress();
-
- if (CondPtr)
- CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()),
- CondPtr);
-
- llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler();
- llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest();
- CGF.setInvokeDest(TerminateHandler);
-
- // Stolen from EmitClassAggrMemberwiseCopy
- llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor,
- Ctor_Complete);
- CallArgList CallArgs;
- CallArgs.push_back(std::make_pair(RValue::get(This),
- CopyCtor->getThisType(CGF.getContext())));
-
- // Push the Src ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Src),
- CopyCtor->getParamDecl(0)->getType()));
- const FunctionProtoType *FPT
- = CopyCtor->getType()->getAs<FunctionProtoType>();
- CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
- Callee, ReturnValueSlot(), CallArgs, CopyCtor);
- CGF.setInvokeDest(PrevLandingPad);
- } else
- llvm_unreachable("uncopyable object");
+// Emits an exception expression into the given location. This
+// differs from EmitAnyExprToMem only in that, if a final copy-ctor
+// call is required, an exception within that copy ctor causes
+// std::terminate to be invoked.
+static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *E,
+ llvm::Value *ExnLoc) {
+ // We want to release the allocated exception object if this
+ // expression throws. We do this by pushing an EH-only cleanup
+ // block which, furthermore, deactivates itself after the expression
+ // is complete.
+ llvm::AllocaInst *ShouldFreeVar =
+ CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()),
+ "should-free-exnobj.var");
+ CGF.InitTempAlloca(ShouldFreeVar,
+ llvm::ConstantInt::getFalse(CGF.getLLVMContext()));
+
+ // A variable holding the exception pointer. This is necessary
+ // because the throw expression does not necessarily dominate the
+ // cleanup, for example if it appears in a conditional expression.
+ llvm::AllocaInst *ExnLocVar =
+ CGF.CreateTempAlloca(ExnLoc->getType(), "exnobj.var");
+
+ llvm::BasicBlock *SavedInvokeDest = CGF.getInvokeDest();
+ {
+ CodeGenFunction::EHCleanupBlock Cleanup(CGF);
+ llvm::BasicBlock *FreeBB = CGF.createBasicBlock("free-exnobj");
+ llvm::BasicBlock *DoneBB = CGF.createBasicBlock("free-exnobj.done");
+
+ llvm::Value *ShouldFree = CGF.Builder.CreateLoad(ShouldFreeVar,
+ "should-free-exnobj");
+ CGF.Builder.CreateCondBr(ShouldFree, FreeBB, DoneBB);
+ CGF.EmitBlock(FreeBB);
+ llvm::Value *ExnLocLocal = CGF.Builder.CreateLoad(ExnLocVar, "exnobj");
+ CGF.Builder.CreateCall(getFreeExceptionFn(CGF), ExnLocLocal);
+ CGF.EmitBlock(DoneBB);
}
+ llvm::BasicBlock *Cleanup = CGF.getInvokeDest();
+
+ CGF.Builder.CreateStore(ExnLoc, ExnLocVar);
+ CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()),
+ ShouldFreeVar);
+
+ // __cxa_allocate_exception returns a void*; we need to cast this
+ // to the appropriate type for the object.
+ const llvm::Type *Ty = CGF.ConvertType(E->getType())->getPointerTo();
+ llvm::Value *TypedExnLoc = CGF.Builder.CreateBitCast(ExnLoc, Ty);
+
+ // FIXME: this isn't quite right! If there's a final unelided call
+ // to a copy constructor, then according to [except.terminate]p1 we
+ // must call std::terminate() if that constructor throws, because
+ // technically that copy occurs after the exception expression is
+ // evaluated but before the exception is caught. But the best way
+ // to handle that is to teach EmitAggExpr to do the final copy
+ // differently if it can't be elided.
+ CGF.EmitAnyExprToMem(E, TypedExnLoc, /*Volatile*/ false);
+
+ CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()),
+ ShouldFreeVar);
+
+ // Pop the cleanup block if it's still the top of the cleanup stack.
+ // Otherwise, temporaries have been created and our cleanup will get
+ // properly removed in time.
+ // TODO: this is not very resilient.
+ if (CGF.getInvokeDest() == Cleanup)
+ CGF.setInvokeDest(SavedInvokeDest);
}
// CopyObject - Utility to copy an object. Calls copy constructor as necessary.
@@ -270,7 +259,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
// Now allocate the exception object.
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
- uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8;
+ uint64_t TypeSize = getContext().getTypeSizeInChars(ThrowType).getQuantity();
llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this);
llvm::Value *ExceptionPtr =
@@ -278,17 +267,24 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
llvm::ConstantInt::get(SizeTy, TypeSize),
"exception");
- llvm::Value *ExceptionPtrPtr =
- CreateTempAlloca(ExceptionPtr->getType(), "exception.ptr");
- Builder.CreateStore(ExceptionPtr, ExceptionPtrPtr);
-
-
- CopyObject(*this, E->getSubExpr(), ExceptionPtr, ExceptionPtrPtr);
+ EmitAnyExprToExn(*this, E->getSubExpr(), ExceptionPtr);
// Now throw the exception.
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
- llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType);
- llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy);
+ llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType, true);
+
+ // The address of the destructor. If the exception type has a
+ // trivial destructor (or isn't a record), we just pass null.
+ llvm::Constant *Dtor = 0;
+ if (const RecordType *RecordTy = ThrowType->getAs<RecordType>()) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (!Record->hasTrivialDestructor()) {
+ CXXDestructorDecl *DtorD = Record->getDestructor(getContext());
+ Dtor = CGM.GetAddrOfCXXDestructor(DtorD, Dtor_Complete);
+ Dtor = llvm::ConstantExpr::getBitCast(Dtor, Int8PtrTy);
+ }
+ }
+ if (!Dtor) Dtor = llvm::Constant::getNullValue(Int8PtrTy);
if (getInvokeDest()) {
llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
@@ -375,7 +371,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
QualType Ty = Proto->getExceptionType(i);
QualType ExceptType
= Ty.getNonReferenceType().getUnqualifiedType();
- llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType);
+ llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType, true);
SelectorArgs.push_back(EHType);
}
if (Proto->getNumExceptions())
@@ -498,7 +494,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
// are ignored.
QualType CaughtType = C->getCaughtType().getNonReferenceType();
llvm::Value *EHTypeInfo
- = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType());
+ = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType(), true);
SelectorArgs.push_back(EHTypeInfo);
} else {
// null indicates catch all
@@ -649,38 +645,46 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
}
CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
- llvm::BasicBlock *Cont1 = CGF.createBasicBlock("cont");
- CGF.EmitBranch(Cont1);
CGF.setInvokeDest(PreviousInvokeDest);
+ llvm::BasicBlock *EndOfCleanup = CGF.Builder.GetInsertBlock();
- CGF.EmitBlock(CleanupHandler);
-
+ // Jump to the beginning of the cleanup.
+ CGF.Builder.SetInsertPoint(CleanupHandler, CleanupHandler->begin());
+
+ // The libstdc++ personality function.
+ // TODO: generalize to work with other libraries.
llvm::Constant *Personality =
CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
(CGF.VMContext),
true),
"__gxx_personality_v0");
Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty);
+
+ // %exception = call i8* @llvm.eh.exception()
+ // Magic intrinsic which tells gives us a handle to the caught
+ // exception.
llvm::Value *llvm_eh_exception =
CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
- llvm::Value *llvm_eh_selector =
- CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
-
llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
- const llvm::IntegerType *Int8Ty;
- const llvm::PointerType *PtrToInt8Ty;
- Int8Ty = llvm::Type::getInt8Ty(CGF.VMContext);
- // C string type. Used in lots of places.
- PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
- llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
+
+ llvm::Constant *Null = llvm::ConstantPointerNull::get(CGF.PtrToInt8Ty);
+
+ // %ignored = call i32 @llvm.eh.selector(i8* %exception,
+ // i8* @__gxx_personality_v0,
+ // i8* null)
+ // Magic intrinsic which tells LLVM that this invoke landing pad is
+ // just a cleanup block.
llvm::Value *Args[] = { Exc, Personality, Null };
+ llvm::Value *llvm_eh_selector =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
CGF.Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args));
- CGF.EmitBlock(CleanupEntryBB);
-
- CGF.EmitBlock(Cont1);
+ // And then we fall through into the code that the user put there.
+ // Jump back to the end of the cleanup.
+ CGF.Builder.SetInsertPoint(EndOfCleanup);
+ // Rethrow the exception.
if (CGF.getInvokeDest()) {
llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont,
@@ -688,10 +692,15 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
CGF.EmitBlock(Cont);
} else
CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc);
-
CGF.Builder.CreateUnreachable();
- CGF.EmitBlock(Cont);
+ // Resume inserting where we started, but put the new cleanup
+ // handler in place.
+ if (PreviousInsertionBlock)
+ CGF.Builder.SetInsertPoint(PreviousInsertionBlock);
+ else
+ CGF.Builder.ClearInsertionPoint();
+
if (CGF.Exceptions)
CGF.setInvokeDest(CleanupHandler);
}
@@ -700,12 +709,11 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
if (TerminateHandler)
return TerminateHandler;
- llvm::BasicBlock *Cont = 0;
-
- if (HaveInsertPoint()) {
- Cont = createBasicBlock("cont");
- EmitBranch(Cont);
- }
+ // We don't want to change anything at the current location, so
+ // save it aside and clear the insert point.
+ llvm::BasicBlock *SavedInsertBlock = Builder.GetInsertBlock();
+ llvm::BasicBlock::iterator SavedInsertPoint = Builder.GetInsertPoint();
+ Builder.ClearInsertionPoint();
llvm::Constant *Personality =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
@@ -735,11 +743,8 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
TerminateCall->setDoesNotThrow();
Builder.CreateUnreachable();
- // Clear the insertion point to indicate we are in unreachable code.
- Builder.ClearInsertionPoint();
-
- if (Cont)
- EmitBlock(Cont);
+ // Restore the saved insertion state.
+ Builder.SetInsertPoint(SavedInsertBlock, SavedInsertPoint);
return TerminateHandler;
}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 0aa4438..9ade916 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -37,6 +37,13 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty,
return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt);
}
+void CodeGenFunction::InitTempAlloca(llvm::AllocaInst *Var,
+ llvm::Value *Init) {
+ llvm::StoreInst *Store = new llvm::StoreInst(Init, Var);
+ llvm::BasicBlock *Block = AllocaInsertPt->getParent();
+ Block->getInstList().insertAfter(&*AllocaInsertPt, Store);
+}
+
llvm::Value *CodeGenFunction::CreateIRTemp(QualType Ty,
const llvm::Twine &Name) {
llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertType(Ty), Name);
@@ -111,6 +118,23 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E,
IsInitializer);
}
+/// EmitAnyExprToMem - Evaluate an expression into a given memory
+/// location.
+void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
+ llvm::Value *Location,
+ bool IsLocationVolatile,
+ bool IsInit) {
+ if (E->getType()->isComplexType())
+ EmitComplexExprIntoAddr(E, Location, IsLocationVolatile);
+ else if (hasAggregateLLVMType(E->getType()))
+ EmitAggExpr(E, Location, IsLocationVolatile, /*Ignore*/ false, IsInit);
+ else {
+ RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false));
+ LValue LV = LValue::MakeAddr(Location, MakeQualifiers(E->getType()));
+ EmitStoreThroughLValue(RV, LV, E->getType());
+ }
+}
+
RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
bool IsInitializer) {
bool ShouldDestroyTemporaries = false;
@@ -150,16 +174,15 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
PopCXXTemporary();
}
} else {
- const CXXRecordDecl *BaseClassDecl = 0;
+ const CXXBaseSpecifierArray *BasePath = 0;
const CXXRecordDecl *DerivedClassDecl = 0;
if (const CastExpr *CE =
dyn_cast<CastExpr>(E->IgnoreParenNoopCasts(getContext()))) {
if (CE->getCastKind() == CastExpr::CK_DerivedToBase) {
E = CE->getSubExpr();
-
- BaseClassDecl =
- cast<CXXRecordDecl>(CE->getType()->getAs<RecordType>()->getDecl());
+
+ BasePath = &CE->getBasePath();
DerivedClassDecl =
cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl());
}
@@ -185,6 +208,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
{
DelayedCleanupBlock Scope(*this);
EmitCXXDestructorCall(Dtor, Dtor_Complete,
+ /*ForVirtualBase=*/false,
Val.getAggregateAddr());
// Make sure to jump to the exit block.
@@ -193,6 +217,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
if (Exceptions) {
EHCleanupBlock Cleanup(*this);
EmitCXXDestructorCall(Dtor, Dtor_Complete,
+ /*ForVirtualBase=*/false,
Val.getAggregateAddr());
}
}
@@ -201,10 +226,10 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
}
// Check if need to perform the derived-to-base cast.
- if (BaseClassDecl) {
+ if (BasePath) {
llvm::Value *Derived = Val.getAggregateAddr();
llvm::Value *Base =
- GetAddressOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl,
+ GetAddressOfBaseClass(Derived, DerivedClassDecl, *BasePath,
/*NullCheckValue=*/false);
return RValue::get(Base);
}
@@ -240,18 +265,15 @@ void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) {
if (!CatchUndefined)
return;
- const llvm::IntegerType *Size_tTy
+ const llvm::Type *Size_tTy
= llvm::IntegerType::get(VMContext, LLVMPointerWidth);
Address = Builder.CreateBitCast(Address, PtrToInt8Ty);
- const llvm::Type *ResType[] = {
- Size_tTy
- };
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, ResType, 1);
- const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(
- CGM.getTypes().ConvertType(CGM.getContext().IntTy));
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, &Size_tTy, 1);
+ const llvm::IntegerType *Int1Ty = llvm::IntegerType::get(VMContext, 1);
+
// In time, people may want to control this and use a 1 here.
- llvm::Value *Arg = llvm::ConstantInt::get(IntTy, 0);
+ llvm::Value *Arg = llvm::ConstantInt::get(Int1Ty, 0);
llvm::Value *C = Builder.CreateCall2(F, Address, Arg);
llvm::BasicBlock *Cont = createBasicBlock();
llvm::BasicBlock *Check = createBasicBlock();
@@ -457,6 +479,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitObjCIsaExpr(cast<ObjCIsaExpr>(E));
case Expr::BinaryOperatorClass:
return EmitBinaryOperatorLValue(cast<BinaryOperator>(E));
+ case Expr::CompoundAssignOperatorClass:
+ return EmitCompoundAssignOperatorLValue(cast<CompoundAssignOperator>(E));
case Expr::CallExprClass:
case Expr::CXXMemberCallExprClass:
case Expr::CXXOperatorCallExprClass:
@@ -606,63 +630,73 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) {
RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV,
QualType ExprType) {
const CGBitFieldInfo &Info = LV.getBitFieldInfo();
- unsigned StartBit = Info.Start;
- unsigned BitfieldSize = Info.Size;
- llvm::Value *Ptr = LV.getBitFieldAddr();
- const llvm::Type *EltTy =
- cast<llvm::PointerType>(Ptr->getType())->getElementType();
- unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy);
+ // Get the output type.
+ const llvm::Type *ResLTy = ConvertType(ExprType);
+ unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy);
- // In some cases the bitfield may straddle two memory locations. Currently we
- // load the entire bitfield, then do the magic to sign-extend it if
- // necessary. This results in somewhat more code than necessary for the common
- // case (one load), since two shifts accomplish both the masking and sign
- // extension.
- unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit);
- llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(), "tmp");
+ // Compute the result as an OR of all of the individual component accesses.
+ llvm::Value *Res = 0;
+ for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) {
+ const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i);
- // Shift to proper location.
- if (StartBit)
- Val = Builder.CreateLShr(Val, StartBit, "bf.lo");
+ // Get the field pointer.
+ llvm::Value *Ptr = LV.getBitFieldBaseAddr();
- // Mask off unused bits.
- llvm::Constant *LowMask = llvm::ConstantInt::get(VMContext,
- llvm::APInt::getLowBitsSet(EltTySize, LowBits));
- Val = Builder.CreateAnd(Val, LowMask, "bf.lo.cleared");
+ // Only offset by the field index if used, so that incoming values are not
+ // required to be structures.
+ if (AI.FieldIndex)
+ Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field");
- // Fetch the high bits if necessary.
- if (LowBits < BitfieldSize) {
- unsigned HighBits = BitfieldSize - LowBits;
- llvm::Value *HighPtr = Builder.CreateGEP(Ptr, llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(VMContext), 1), "bf.ptr.hi");
- llvm::Value *HighVal = Builder.CreateLoad(HighPtr,
- LV.isVolatileQualified(),
- "tmp");
+ // Offset by the byte offset, if used.
+ if (AI.FieldByteOffset) {
+ const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext);
+ Ptr = Builder.CreateBitCast(Ptr, i8PTy);
+ Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset,"bf.field.offs");
+ }
- // Mask off unused bits.
- llvm::Constant *HighMask = llvm::ConstantInt::get(VMContext,
- llvm::APInt::getLowBitsSet(EltTySize, HighBits));
- HighVal = Builder.CreateAnd(HighVal, HighMask, "bf.lo.cleared");
+ // Cast to the access type.
+ const llvm::Type *PTy = llvm::Type::getIntNPtrTy(VMContext, AI.AccessWidth,
+ ExprType.getAddressSpace());
+ Ptr = Builder.CreateBitCast(Ptr, PTy);
- // Shift to proper location and or in to bitfield value.
- HighVal = Builder.CreateShl(HighVal, LowBits);
- Val = Builder.CreateOr(Val, HighVal, "bf.val");
- }
+ // Perform the load.
+ llvm::LoadInst *Load = Builder.CreateLoad(Ptr, LV.isVolatileQualified());
+ if (AI.AccessAlignment)
+ Load->setAlignment(AI.AccessAlignment);
- // Sign extend if necessary.
- if (Info.IsSigned) {
- llvm::Value *ExtraBits = llvm::ConstantInt::get(EltTy,
- EltTySize - BitfieldSize);
- Val = Builder.CreateAShr(Builder.CreateShl(Val, ExtraBits),
- ExtraBits, "bf.val.sext");
+ // Shift out unused low bits and mask out unused high bits.
+ llvm::Value *Val = Load;
+ if (AI.FieldBitStart)
+ Val = Builder.CreateLShr(Load, AI.FieldBitStart);
+ Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(AI.AccessWidth,
+ AI.TargetBitWidth),
+ "bf.clear");
+
+ // Extend or truncate to the target size.
+ if (AI.AccessWidth < ResSizeInBits)
+ Val = Builder.CreateZExt(Val, ResLTy);
+ else if (AI.AccessWidth > ResSizeInBits)
+ Val = Builder.CreateTrunc(Val, ResLTy);
+
+ // Shift into place, and OR into the result.
+ if (AI.TargetBitOffset)
+ Val = Builder.CreateShl(Val, AI.TargetBitOffset);
+ Res = Res ? Builder.CreateOr(Res, Val) : Val;
}
- // The bitfield type and the normal type differ when the storage sizes differ
- // (currently just _Bool).
- Val = Builder.CreateIntCast(Val, ConvertType(ExprType), false, "tmp");
+ // If the bit-field is signed, perform the sign-extension.
+ //
+ // FIXME: This can easily be folded into the load of the high bits, which
+ // could also eliminate the mask of high bits in some situations.
+ if (Info.isSigned()) {
+ unsigned ExtraBits = ResSizeInBits - Info.getSize();
+ if (ExtraBits)
+ Res = Builder.CreateAShr(Builder.CreateShl(Res, ExtraBits),
+ ExtraBits, "bf.val.sext");
+ }
- return RValue::get(Val);
+ return RValue::get(Res);
}
RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
@@ -783,88 +817,103 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
QualType Ty,
llvm::Value **Result) {
const CGBitFieldInfo &Info = Dst.getBitFieldInfo();
- unsigned StartBit = Info.Start;
- unsigned BitfieldSize = Info.Size;
- llvm::Value *Ptr = Dst.getBitFieldAddr();
- const llvm::Type *EltTy =
- cast<llvm::PointerType>(Ptr->getType())->getElementType();
- unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy);
+ // Get the output type.
+ const llvm::Type *ResLTy = ConvertTypeForMem(Ty);
+ unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy);
- // Get the new value, cast to the appropriate type and masked to exactly the
- // size of the bit-field.
+ // Get the source value, truncated to the width of the bit-field.
llvm::Value *SrcVal = Src.getScalarVal();
- llvm::Value *NewVal = Builder.CreateIntCast(SrcVal, EltTy, false, "tmp");
- llvm::Constant *Mask = llvm::ConstantInt::get(VMContext,
- llvm::APInt::getLowBitsSet(EltTySize, BitfieldSize));
- NewVal = Builder.CreateAnd(NewVal, Mask, "bf.value");
+
+ if (Ty->isBooleanType())
+ SrcVal = Builder.CreateIntCast(SrcVal, ResLTy, /*IsSigned=*/false);
+
+ SrcVal = Builder.CreateAnd(SrcVal, llvm::APInt::getLowBitsSet(ResSizeInBits,
+ Info.getSize()),
+ "bf.value");
// Return the new value of the bit-field, if requested.
if (Result) {
// Cast back to the proper type for result.
- const llvm::Type *SrcTy = SrcVal->getType();
- llvm::Value *SrcTrunc = Builder.CreateIntCast(NewVal, SrcTy, false,
- "bf.reload.val");
+ const llvm::Type *SrcTy = Src.getScalarVal()->getType();
+ llvm::Value *ReloadVal = Builder.CreateIntCast(SrcVal, SrcTy, false,
+ "bf.reload.val");
// Sign extend if necessary.
- if (Info.IsSigned) {
- unsigned SrcTySize = CGM.getTargetData().getTypeSizeInBits(SrcTy);
- llvm::Value *ExtraBits = llvm::ConstantInt::get(SrcTy,
- SrcTySize - BitfieldSize);
- SrcTrunc = Builder.CreateAShr(Builder.CreateShl(SrcTrunc, ExtraBits),
- ExtraBits, "bf.reload.sext");
+ if (Info.isSigned()) {
+ unsigned ExtraBits = ResSizeInBits - Info.getSize();
+ if (ExtraBits)
+ ReloadVal = Builder.CreateAShr(Builder.CreateShl(ReloadVal, ExtraBits),
+ ExtraBits, "bf.reload.sext");
}
- *Result = SrcTrunc;
+ *Result = ReloadVal;
}
- // In some cases the bitfield may straddle two memory locations. Emit the low
- // part first and check to see if the high needs to be done.
- unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit);
- llvm::Value *LowVal = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(),
- "bf.prev.low");
-
- // Compute the mask for zero-ing the low part of this bitfield.
- llvm::Constant *InvMask =
- llvm::ConstantInt::get(VMContext,
- ~llvm::APInt::getBitsSet(EltTySize, StartBit, StartBit + LowBits));
+ // Iterate over the components, writing each piece to memory.
+ for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) {
+ const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i);
- // Compute the new low part as
- // LowVal = (LowVal & InvMask) | (NewVal << StartBit),
- // with the shift of NewVal implicitly stripping the high bits.
- llvm::Value *NewLowVal =
- Builder.CreateShl(NewVal, StartBit, "bf.value.lo");
- LowVal = Builder.CreateAnd(LowVal, InvMask, "bf.prev.lo.cleared");
- LowVal = Builder.CreateOr(LowVal, NewLowVal, "bf.new.lo");
+ // Get the field pointer.
+ llvm::Value *Ptr = Dst.getBitFieldBaseAddr();
- // Write back.
- Builder.CreateStore(LowVal, Ptr, Dst.isVolatileQualified());
+ // Only offset by the field index if used, so that incoming values are not
+ // required to be structures.
+ if (AI.FieldIndex)
+ Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field");
- // If the low part doesn't cover the bitfield emit a high part.
- if (LowBits < BitfieldSize) {
- unsigned HighBits = BitfieldSize - LowBits;
- llvm::Value *HighPtr = Builder.CreateGEP(Ptr, llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(VMContext), 1), "bf.ptr.hi");
- llvm::Value *HighVal = Builder.CreateLoad(HighPtr,
- Dst.isVolatileQualified(),
- "bf.prev.hi");
-
- // Compute the mask for zero-ing the high part of this bitfield.
- llvm::Constant *InvMask =
- llvm::ConstantInt::get(VMContext, ~llvm::APInt::getLowBitsSet(EltTySize,
- HighBits));
+ // Offset by the byte offset, if used.
+ if (AI.FieldByteOffset) {
+ const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext);
+ Ptr = Builder.CreateBitCast(Ptr, i8PTy);
+ Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset,"bf.field.offs");
+ }
- // Compute the new high part as
- // HighVal = (HighVal & InvMask) | (NewVal lshr LowBits),
- // where the high bits of NewVal have already been cleared and the
- // shift stripping the low bits.
- llvm::Value *NewHighVal =
- Builder.CreateLShr(NewVal, LowBits, "bf.value.high");
- HighVal = Builder.CreateAnd(HighVal, InvMask, "bf.prev.hi.cleared");
- HighVal = Builder.CreateOr(HighVal, NewHighVal, "bf.new.hi");
+ // Cast to the access type.
+ const llvm::Type *PTy = llvm::Type::getIntNPtrTy(VMContext, AI.AccessWidth,
+ Ty.getAddressSpace());
+ Ptr = Builder.CreateBitCast(Ptr, PTy);
+
+ // Extract the piece of the bit-field value to write in this access, limited
+ // to the values that are part of this access.
+ llvm::Value *Val = SrcVal;
+ if (AI.TargetBitOffset)
+ Val = Builder.CreateLShr(Val, AI.TargetBitOffset);
+ Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(ResSizeInBits,
+ AI.TargetBitWidth));
+
+ // Extend or truncate to the access size.
+ const llvm::Type *AccessLTy =
+ llvm::Type::getIntNTy(VMContext, AI.AccessWidth);
+ if (ResSizeInBits < AI.AccessWidth)
+ Val = Builder.CreateZExt(Val, AccessLTy);
+ else if (ResSizeInBits > AI.AccessWidth)
+ Val = Builder.CreateTrunc(Val, AccessLTy);
+
+ // Shift into the position in memory.
+ if (AI.FieldBitStart)
+ Val = Builder.CreateShl(Val, AI.FieldBitStart);
+
+ // If necessary, load and OR in bits that are outside of the bit-field.
+ if (AI.TargetBitWidth != AI.AccessWidth) {
+ llvm::LoadInst *Load = Builder.CreateLoad(Ptr, Dst.isVolatileQualified());
+ if (AI.AccessAlignment)
+ Load->setAlignment(AI.AccessAlignment);
+
+ // Compute the mask for zeroing the bits that are part of the bit-field.
+ llvm::APInt InvMask =
+ ~llvm::APInt::getBitsSet(AI.AccessWidth, AI.FieldBitStart,
+ AI.FieldBitStart + AI.TargetBitWidth);
+
+ // Apply the mask and OR in to the value to write.
+ Val = Builder.CreateOr(Builder.CreateAnd(Load, InvMask), Val);
+ }
- // Write back.
- Builder.CreateStore(HighVal, HighPtr, Dst.isVolatileQualified());
+ // Write the value.
+ llvm::StoreInst *Store = Builder.CreateStore(Val, Ptr,
+ Dst.isVolatileQualified());
+ if (AI.AccessAlignment)
+ Store->setAlignment(AI.AccessAlignment);
}
}
@@ -1084,6 +1133,9 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
bool NonGCable = VD->hasLocalStorage() && !VD->hasAttr<BlocksAttr>();
llvm::Value *V = LocalDeclMap[VD];
+ if (!V && getContext().getLangOptions().CPlusPlus &&
+ VD->isStaticLocal())
+ V = CGM.getStaticLocalDeclAddress(VD);
assert(V && "DeclRefExpr not entered in LocalDeclMap?");
Qualifiers Quals = MakeQualifiers(E->getType());
@@ -1474,19 +1526,7 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue,
const CGRecordLayout &RL =
CGM.getTypes().getCGRecordLayout(Field->getParent());
const CGBitFieldInfo &Info = RL.getBitFieldInfo(Field);
-
- // FIXME: CodeGenTypes should expose a method to get the appropriate type for
- // FieldTy (the appropriate type is ABI-dependent).
- const llvm::Type *FieldTy =
- CGM.getTypes().ConvertTypeForMem(Field->getType());
- const llvm::PointerType *BaseTy =
- cast<llvm::PointerType>(BaseValue->getType());
- unsigned AS = BaseTy->getAddressSpace();
- BaseValue = Builder.CreateBitCast(BaseValue,
- llvm::PointerType::get(FieldTy, AS));
- llvm::Value *V = Builder.CreateConstGEP1_32(BaseValue, Info.FieldNo);
-
- return LValue::MakeBitfield(V, Info,
+ return LValue::MakeBitfield(BaseValue, Info,
Field->getType().getCVRQualifiers()|CVRQualifiers);
}
@@ -1548,12 +1588,7 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){
const Expr* InitExpr = E->getInitializer();
LValue Result = LValue::MakeAddr(DeclPtr, MakeQualifiers(E->getType()));
- if (E->getType()->isComplexType())
- EmitComplexExprIntoAddr(InitExpr, DeclPtr, false);
- else if (hasAggregateLLVMType(E->getType()))
- EmitAnyExpr(InitExpr, DeclPtr, false);
- else
- EmitStoreThroughLValue(EmitAnyExpr(InitExpr), Result, E->getType());
+ EmitAnyExprToMem(InitExpr, DeclPtr, /*Volatile*/ false);
return Result;
}
@@ -1647,27 +1682,19 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
E->getSubExpr()->getType()->getAs<RecordType>();
CXXRecordDecl *DerivedClassDecl =
cast<CXXRecordDecl>(DerivedClassTy->getDecl());
-
- const RecordType *BaseClassTy = E->getType()->getAs<RecordType>();
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseClassTy->getDecl());
LValue LV = EmitLValue(E->getSubExpr());
// Perform the derived-to-base conversion
llvm::Value *Base =
GetAddressOfBaseClass(LV.getAddress(), DerivedClassDecl,
- BaseClassDecl, /*NullCheckValue=*/false);
+ E->getBasePath(), /*NullCheckValue=*/false);
return LValue::MakeAddr(Base, MakeQualifiers(E->getType()));
}
case CastExpr::CK_ToUnion:
return EmitAggExprToLValue(E);
case CastExpr::CK_BaseToDerived: {
- const RecordType *BaseClassTy =
- E->getSubExpr()->getType()->getAs<RecordType>();
- CXXRecordDecl *BaseClassDecl =
- cast<CXXRecordDecl>(BaseClassTy->getDecl());
-
const RecordType *DerivedClassTy = E->getType()->getAs<RecordType>();
CXXRecordDecl *DerivedClassDecl =
cast<CXXRecordDecl>(DerivedClassTy->getDecl());
@@ -1676,8 +1703,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
// Perform the base-to-derived conversion
llvm::Value *Derived =
- GetAddressOfDerivedClass(LV.getAddress(), BaseClassDecl,
- DerivedClassDecl, /*NullCheckValue=*/false);
+ GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl,
+ E->getBasePath(),/*NullCheckValue=*/false);
return LValue::MakeAddr(Derived, MakeQualifiers(E->getType()));
}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 4d5160f..d1b0dff 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -263,7 +263,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
std::swap(DerivedDecl, BaseDecl);
if (llvm::Constant *Adj =
- CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) {
+ CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, E->getBasePath())) {
if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj");
else
@@ -321,6 +321,11 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) {
(void) MPT;
assert(MPT->getPointeeType()->isFunctionProtoType() &&
"Unexpected member pointer type!");
+
+ // The creation of member function pointers has no side effects; if
+ // there is no destination pointer, we have nothing to do.
+ if (!DestPtr)
+ return;
const DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr());
const CXXMethodDecl *MD =
@@ -329,17 +334,23 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) {
const llvm::Type *PtrDiffTy =
CGF.ConvertType(CGF.getContext().getPointerDiffType());
+
llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "dst.ptr");
llvm::Value *FuncPtr;
if (MD->isVirtual()) {
- int64_t Index = CGF.CGM.getVTables().getMethodVtableIndex(MD);
+ int64_t Index = CGF.CGM.getVTables().getMethodVTableIndex(MD);
+ // FIXME: We shouldn't use / 8 here.
+ uint64_t PointerWidthInBytes =
+ CGF.CGM.getContext().Target.getPointerWidth(0) / 8;
+
// Itanium C++ ABI 2.3:
// For a non-virtual function, this field is a simple function pointer.
// For a virtual function, it is 1 plus the virtual table offset
// (in bytes) of the function, represented as a ptrdiff_t.
- FuncPtr = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1);
+ FuncPtr = llvm::ConstantInt::get(PtrDiffTy,
+ (Index * PointerWidthInBytes) + 1);
} else {
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
const llvm::Type *Ty =
@@ -738,6 +749,14 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
bool isVolatile) {
assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
+ // Ignore empty classes in C++.
+ if (getContext().getLangOptions().CPlusPlus) {
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ if (cast<CXXRecordDecl>(RT->getDecl())->isEmpty())
+ return;
+ }
+ }
+
// Aggregate assignment turns into llvm.memcpy. This is almost valid per
// C99 6.5.16.1p3, which states "If the value being stored in an object is
// read from another object that overlaps in anyway the storage of the first
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 1fd1da8..b57cdc9 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -205,20 +205,20 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual);
EmitBlock(FnVirtual);
- const llvm::Type *VtableTy =
+ const llvm::Type *VTableTy =
FTy->getPointerTo()->getPointerTo();
- llvm::Value *Vtable = Builder.CreateBitCast(This, VtableTy->getPointerTo());
- Vtable = Builder.CreateLoad(Vtable);
+ llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy->getPointerTo());
+ VTable = Builder.CreateLoad(VTable);
- Vtable = Builder.CreateBitCast(Vtable, Int8PtrTy);
- llvm::Value *VtableOffset =
+ VTable = Builder.CreateBitCast(VTable, Int8PtrTy);
+ llvm::Value *VTableOffset =
Builder.CreateSub(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1));
- Vtable = Builder.CreateGEP(Vtable, VtableOffset, "fn");
- Vtable = Builder.CreateBitCast(Vtable, VtableTy);
+ VTable = Builder.CreateGEP(VTable, VTableOffset, "fn");
+ VTable = Builder.CreateBitCast(VTable, VTableTy);
- llvm::Value *VirtualFn = Builder.CreateLoad(Vtable, "virtualfn");
+ llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn");
EmitBranch(FnEnd);
EmitBlock(FnNonVirtual);
@@ -316,17 +316,22 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(Dest, BasePtr);
+ Builder.CreateBitCast(Dest, BasePtr);
EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
E->arg_begin(), E->arg_end());
}
- else
+ else {
+ CXXCtorType Type =
+ (E->getConstructionKind() == CXXConstructExpr::CK_Complete)
+ ? Ctor_Complete : Ctor_Base;
+ bool ForVirtualBase =
+ E->getConstructionKind() == CXXConstructExpr::CK_VirtualBase;
+
// Call the constructor.
- EmitCXXConstructorCall(CD,
- E->isBaseInitialization()? Ctor_Base : Ctor_Complete,
- Dest,
+ EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest,
E->arg_begin(), E->arg_end());
+ }
}
static CharUnits CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) {
@@ -460,18 +465,20 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
llvm::Value *NewPtr,
llvm::Value *NumElements) {
if (E->isArray()) {
- if (CXXConstructorDecl *Ctor = E->getConstructor())
- CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
- E->constructor_arg_begin(),
- E->constructor_arg_end());
- return;
+ if (CXXConstructorDecl *Ctor = E->getConstructor()) {
+ if (!Ctor->getParent()->hasTrivialConstructor())
+ CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
+ E->constructor_arg_begin(),
+ E->constructor_arg_end());
+ return;
+ }
}
QualType AllocType = E->getAllocatedType();
if (CXXConstructorDecl *Ctor = E->getConstructor()) {
- CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr,
- E->constructor_arg_begin(),
+ CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false,
+ NewPtr, E->constructor_arg_begin(),
E->constructor_arg_end());
return;
@@ -760,7 +767,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
// The dtor took care of deleting the object.
ShouldCallDelete = false;
} else
- EmitCXXDestructorCall(Dtor, Dtor_Complete, Ptr);
+ EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
+ Ptr);
}
}
}
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 172a77d..2595ff0 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -27,359 +27,387 @@
using namespace clang;
using namespace CodeGen;
-namespace {
+//===----------------------------------------------------------------------===//
+// ConstStructBuilder
+//===----------------------------------------------------------------------===//
+
+namespace {
class ConstStructBuilder {
CodeGenModule &CGM;
CodeGenFunction *CGF;
bool Packed;
-
unsigned NextFieldOffsetInBytes;
-
unsigned LLVMStructAlignment;
-
std::vector<llvm::Constant *> Elements;
-
+public:
+ static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF,
+ InitListExpr *ILE);
+
+private:
ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF)
: CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0),
LLVMStructAlignment(1) { }
bool AppendField(const FieldDecl *Field, uint64_t FieldOffset,
- const Expr *InitExpr) {
- uint64_t FieldOffsetInBytes = FieldOffset / 8;
+ llvm::Constant *InitExpr);
- assert(NextFieldOffsetInBytes <= FieldOffsetInBytes
- && "Field offset mismatch!");
+ bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
+ llvm::Constant *InitExpr);
- // Emit the field.
- llvm::Constant *C = CGM.EmitConstantExpr(InitExpr, Field->getType(), CGF);
- if (!C)
- return false;
+ void AppendPadding(uint64_t NumBytes);
- unsigned FieldAlignment = getAlignment(C);
+ void AppendTailPadding(uint64_t RecordSize);
- // Round up the field offset to the alignment of the field type.
- uint64_t AlignedNextFieldOffsetInBytes =
- llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment);
+ void ConvertStructToPacked();
+
+ bool Build(InitListExpr *ILE);
- if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) {
- assert(!Packed && "Alignment is wrong even with a packed struct!");
+ unsigned getAlignment(const llvm::Constant *C) const {
+ if (Packed) return 1;
+ return CGM.getTargetData().getABITypeAlignment(C->getType());
+ }
- // Convert the struct to a packed struct.
- ConvertStructToPacked();
-
- AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
- }
+ uint64_t getSizeInBytes(const llvm::Constant *C) const {
+ return CGM.getTargetData().getTypeAllocSize(C->getType());
+ }
+};
- if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) {
- // We need to append padding.
- AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes);
+bool ConstStructBuilder::
+AppendField(const FieldDecl *Field, uint64_t FieldOffset,
+ llvm::Constant *InitCst) {
+ uint64_t FieldOffsetInBytes = FieldOffset / 8;
- assert(NextFieldOffsetInBytes == FieldOffsetInBytes &&
- "Did not add enough padding!");
+ assert(NextFieldOffsetInBytes <= FieldOffsetInBytes
+ && "Field offset mismatch!");
- AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
- }
+ // Emit the field.
+ if (!InitCst)
+ return false;
- // Add the field.
- Elements.push_back(C);
- NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + getSizeInBytes(C);
-
- if (Packed)
- assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!");
- else
- LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment);
+ unsigned FieldAlignment = getAlignment(InitCst);
- return true;
- }
+ // Round up the field offset to the alignment of the field type.
+ uint64_t AlignedNextFieldOffsetInBytes =
+ llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment);
- bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
- const Expr *InitExpr) {
- llvm::ConstantInt *CI =
- cast_or_null<llvm::ConstantInt>(CGM.EmitConstantExpr(InitExpr,
- Field->getType(),
- CGF));
- // FIXME: Can this ever happen?
- if (!CI)
- return false;
-
- if (FieldOffset > NextFieldOffsetInBytes * 8) {
- // We need to add padding.
- uint64_t NumBytes =
- llvm::RoundUpToAlignment(FieldOffset -
- NextFieldOffsetInBytes * 8, 8) / 8;
+ if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) {
+ assert(!Packed && "Alignment is wrong even with a packed struct!");
- AppendPadding(NumBytes);
- }
+ // Convert the struct to a packed struct.
+ ConvertStructToPacked();
+
+ AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
+ }
- uint64_t FieldSize =
- Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue();
+ if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) {
+ // We need to append padding.
+ AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes);
- llvm::APInt FieldValue = CI->getValue();
+ assert(NextFieldOffsetInBytes == FieldOffsetInBytes &&
+ "Did not add enough padding!");
- // Promote the size of FieldValue if necessary
- // FIXME: This should never occur, but currently it can because initializer
- // constants are cast to bool, and because clang is not enforcing bitfield
- // width limits.
- if (FieldSize > FieldValue.getBitWidth())
- FieldValue.zext(FieldSize);
+ AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
+ }
- // Truncate the size of FieldValue to the bit field size.
- if (FieldSize < FieldValue.getBitWidth())
- FieldValue.trunc(FieldSize);
+ // Add the field.
+ Elements.push_back(InitCst);
+ NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes +
+ getSizeInBytes(InitCst);
+
+ if (Packed)
+ assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!");
+ else
+ LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment);
- if (FieldOffset < NextFieldOffsetInBytes * 8) {
- // Either part of the field or the entire field can go into the previous
- // byte.
- assert(!Elements.empty() && "Elements can't be empty!");
+ return true;
+}
- unsigned BitsInPreviousByte =
- NextFieldOffsetInBytes * 8 - FieldOffset;
+bool ConstStructBuilder::
+ AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
+ llvm::Constant *InitCst) {
+ llvm::ConstantInt *CI = cast_or_null<llvm::ConstantInt>(InitCst);
+ // FIXME: Can this ever happen?
+ if (!CI)
+ return false;
- bool FitsCompletelyInPreviousByte =
- BitsInPreviousByte >= FieldValue.getBitWidth();
+ if (FieldOffset > NextFieldOffsetInBytes * 8) {
+ // We need to add padding.
+ uint64_t NumBytes =
+ llvm::RoundUpToAlignment(FieldOffset -
+ NextFieldOffsetInBytes * 8, 8) / 8;
- llvm::APInt Tmp = FieldValue;
+ AppendPadding(NumBytes);
+ }
- if (!FitsCompletelyInPreviousByte) {
- unsigned NewFieldWidth = FieldSize - BitsInPreviousByte;
+ uint64_t FieldSize =
+ Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue();
- if (CGM.getTargetData().isBigEndian()) {
- Tmp = Tmp.lshr(NewFieldWidth);
- Tmp.trunc(BitsInPreviousByte);
+ llvm::APInt FieldValue = CI->getValue();
- // We want the remaining high bits.
- FieldValue.trunc(NewFieldWidth);
- } else {
- Tmp.trunc(BitsInPreviousByte);
+ // Promote the size of FieldValue if necessary
+ // FIXME: This should never occur, but currently it can because initializer
+ // constants are cast to bool, and because clang is not enforcing bitfield
+ // width limits.
+ if (FieldSize > FieldValue.getBitWidth())
+ FieldValue.zext(FieldSize);
- // We want the remaining low bits.
- FieldValue = FieldValue.lshr(BitsInPreviousByte);
- FieldValue.trunc(NewFieldWidth);
- }
- }
+ // Truncate the size of FieldValue to the bit field size.
+ if (FieldSize < FieldValue.getBitWidth())
+ FieldValue.trunc(FieldSize);
- Tmp.zext(8);
- if (CGM.getTargetData().isBigEndian()) {
- if (FitsCompletelyInPreviousByte)
- Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth());
- } else {
- Tmp = Tmp.shl(8 - BitsInPreviousByte);
- }
+ if (FieldOffset < NextFieldOffsetInBytes * 8) {
+ // Either part of the field or the entire field can go into the previous
+ // byte.
+ assert(!Elements.empty() && "Elements can't be empty!");
- // Or in the bits that go into the previous byte.
- if (llvm::ConstantInt *Val = dyn_cast<llvm::ConstantInt>(Elements.back()))
- Tmp |= Val->getValue();
- else
- assert(isa<llvm::UndefValue>(Elements.back()));
+ unsigned BitsInPreviousByte =
+ NextFieldOffsetInBytes * 8 - FieldOffset;
- Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp);
+ bool FitsCompletelyInPreviousByte =
+ BitsInPreviousByte >= FieldValue.getBitWidth();
- if (FitsCompletelyInPreviousByte)
- return true;
- }
+ llvm::APInt Tmp = FieldValue;
- while (FieldValue.getBitWidth() > 8) {
- llvm::APInt Tmp;
+ if (!FitsCompletelyInPreviousByte) {
+ unsigned NewFieldWidth = FieldSize - BitsInPreviousByte;
if (CGM.getTargetData().isBigEndian()) {
- // We want the high bits.
- Tmp = FieldValue;
- Tmp = Tmp.lshr(Tmp.getBitWidth() - 8);
- Tmp.trunc(8);
+ Tmp = Tmp.lshr(NewFieldWidth);
+ Tmp.trunc(BitsInPreviousByte);
+
+ // We want the remaining high bits.
+ FieldValue.trunc(NewFieldWidth);
} else {
- // We want the low bits.
- Tmp = FieldValue;
- Tmp.trunc(8);
+ Tmp.trunc(BitsInPreviousByte);
- FieldValue = FieldValue.lshr(8);
+ // We want the remaining low bits.
+ FieldValue = FieldValue.lshr(BitsInPreviousByte);
+ FieldValue.trunc(NewFieldWidth);
}
-
- Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp));
- NextFieldOffsetInBytes++;
-
- FieldValue.trunc(FieldValue.getBitWidth() - 8);
}
- assert(FieldValue.getBitWidth() > 0 &&
- "Should have at least one bit left!");
- assert(FieldValue.getBitWidth() <= 8 &&
- "Should not have more than a byte left!");
+ Tmp.zext(8);
+ if (CGM.getTargetData().isBigEndian()) {
+ if (FitsCompletelyInPreviousByte)
+ Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth());
+ } else {
+ Tmp = Tmp.shl(8 - BitsInPreviousByte);
+ }
- if (FieldValue.getBitWidth() < 8) {
- if (CGM.getTargetData().isBigEndian()) {
- unsigned BitWidth = FieldValue.getBitWidth();
+ // Or in the bits that go into the previous byte.
+ if (llvm::ConstantInt *Val = dyn_cast<llvm::ConstantInt>(Elements.back()))
+ Tmp |= Val->getValue();
+ else
+ assert(isa<llvm::UndefValue>(Elements.back()));
- FieldValue.zext(8);
- FieldValue = FieldValue << (8 - BitWidth);
- } else
- FieldValue.zext(8);
- }
+ Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp);
- // Append the last element.
- Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(),
- FieldValue));
- NextFieldOffsetInBytes++;
- return true;
+ if (FitsCompletelyInPreviousByte)
+ return true;
}
- void AppendPadding(uint64_t NumBytes) {
- if (!NumBytes)
- return;
+ while (FieldValue.getBitWidth() > 8) {
+ llvm::APInt Tmp;
+
+ if (CGM.getTargetData().isBigEndian()) {
+ // We want the high bits.
+ Tmp = FieldValue;
+ Tmp = Tmp.lshr(Tmp.getBitWidth() - 8);
+ Tmp.trunc(8);
+ } else {
+ // We want the low bits.
+ Tmp = FieldValue;
+ Tmp.trunc(8);
- const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
- if (NumBytes > 1)
- Ty = llvm::ArrayType::get(Ty, NumBytes);
+ FieldValue = FieldValue.lshr(8);
+ }
- llvm::Constant *C = llvm::UndefValue::get(Ty);
- Elements.push_back(C);
- assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!");
+ Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp));
+ NextFieldOffsetInBytes++;
- NextFieldOffsetInBytes += getSizeInBytes(C);
+ FieldValue.trunc(FieldValue.getBitWidth() - 8);
}
- void AppendTailPadding(uint64_t RecordSize) {
- assert(RecordSize % 8 == 0 && "Invalid record size!");
+ assert(FieldValue.getBitWidth() > 0 &&
+ "Should have at least one bit left!");
+ assert(FieldValue.getBitWidth() <= 8 &&
+ "Should not have more than a byte left!");
- uint64_t RecordSizeInBytes = RecordSize / 8;
- assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!");
+ if (FieldValue.getBitWidth() < 8) {
+ if (CGM.getTargetData().isBigEndian()) {
+ unsigned BitWidth = FieldValue.getBitWidth();
- unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes;
- AppendPadding(NumPadBytes);
+ FieldValue.zext(8);
+ FieldValue = FieldValue << (8 - BitWidth);
+ } else
+ FieldValue.zext(8);
}
- void ConvertStructToPacked() {
- std::vector<llvm::Constant *> PackedElements;
- uint64_t ElementOffsetInBytes = 0;
+ // Append the last element.
+ Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(),
+ FieldValue));
+ NextFieldOffsetInBytes++;
+ return true;
+}
- for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
- llvm::Constant *C = Elements[i];
+void ConstStructBuilder::AppendPadding(uint64_t NumBytes) {
+ if (!NumBytes)
+ return;
- unsigned ElementAlign =
- CGM.getTargetData().getABITypeAlignment(C->getType());
- uint64_t AlignedElementOffsetInBytes =
- llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign);
+ const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
+ if (NumBytes > 1)
+ Ty = llvm::ArrayType::get(Ty, NumBytes);
- if (AlignedElementOffsetInBytes > ElementOffsetInBytes) {
- // We need some padding.
- uint64_t NumBytes =
- AlignedElementOffsetInBytes - ElementOffsetInBytes;
+ llvm::Constant *C = llvm::UndefValue::get(Ty);
+ Elements.push_back(C);
+ assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!");
- const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
- if (NumBytes > 1)
- Ty = llvm::ArrayType::get(Ty, NumBytes);
+ NextFieldOffsetInBytes += getSizeInBytes(C);
+}
- llvm::Constant *Padding = llvm::UndefValue::get(Ty);
- PackedElements.push_back(Padding);
- ElementOffsetInBytes += getSizeInBytes(Padding);
- }
+void ConstStructBuilder::AppendTailPadding(uint64_t RecordSize) {
+ assert(RecordSize % 8 == 0 && "Invalid record size!");
- PackedElements.push_back(C);
- ElementOffsetInBytes += getSizeInBytes(C);
- }
+ uint64_t RecordSizeInBytes = RecordSize / 8;
+ assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!");
- assert(ElementOffsetInBytes == NextFieldOffsetInBytes &&
- "Packing the struct changed its size!");
+ unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes;
+ AppendPadding(NumPadBytes);
+}
- Elements = PackedElements;
- LLVMStructAlignment = 1;
- Packed = true;
- }
-
- bool Build(InitListExpr *ILE) {
- RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
-
- unsigned FieldNo = 0;
- unsigned ElementNo = 0;
- for (RecordDecl::field_iterator Field = RD->field_begin(),
- FieldEnd = RD->field_end();
- ElementNo < ILE->getNumInits() && Field != FieldEnd;
- ++Field, ++FieldNo) {
- if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field)
- continue;
-
- if (Field->isBitField()) {
- if (!Field->getIdentifier())
- continue;
-
- if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo),
- ILE->getInit(ElementNo)))
- return false;
- } else {
- if (!AppendField(*Field, Layout.getFieldOffset(FieldNo),
- ILE->getInit(ElementNo)))
- return false;
- }
+void ConstStructBuilder::ConvertStructToPacked() {
+ std::vector<llvm::Constant *> PackedElements;
+ uint64_t ElementOffsetInBytes = 0;
- ElementNo++;
- }
+ for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
+ llvm::Constant *C = Elements[i];
- uint64_t LayoutSizeInBytes = Layout.getSize() / 8;
+ unsigned ElementAlign =
+ CGM.getTargetData().getABITypeAlignment(C->getType());
+ uint64_t AlignedElementOffsetInBytes =
+ llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign);
- if (NextFieldOffsetInBytes > LayoutSizeInBytes) {
- // If the struct is bigger than the size of the record type,
- // we must have a flexible array member at the end.
- assert(RD->hasFlexibleArrayMember() &&
- "Must have flexible array member if struct is bigger than type!");
-
- // No tail padding is necessary.
- return true;
- }
+ if (AlignedElementOffsetInBytes > ElementOffsetInBytes) {
+ // We need some padding.
+ uint64_t NumBytes =
+ AlignedElementOffsetInBytes - ElementOffsetInBytes;
- uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes,
- LLVMStructAlignment);
+ const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
+ if (NumBytes > 1)
+ Ty = llvm::ArrayType::get(Ty, NumBytes);
- // Check if we need to convert the struct to a packed struct.
- if (NextFieldOffsetInBytes <= LayoutSizeInBytes &&
- LLVMSizeInBytes > LayoutSizeInBytes) {
- assert(!Packed && "Size mismatch!");
-
- ConvertStructToPacked();
- assert(NextFieldOffsetInBytes == LayoutSizeInBytes &&
- "Converting to packed did not help!");
+ llvm::Constant *Padding = llvm::UndefValue::get(Ty);
+ PackedElements.push_back(Padding);
+ ElementOffsetInBytes += getSizeInBytes(Padding);
}
- // Append tail padding if necessary.
- AppendTailPadding(Layout.getSize());
-
- assert(Layout.getSize() / 8 == NextFieldOffsetInBytes &&
- "Tail padding mismatch!");
-
- return true;
+ PackedElements.push_back(C);
+ ElementOffsetInBytes += getSizeInBytes(C);
}
- unsigned getAlignment(const llvm::Constant *C) const {
- if (Packed)
- return 1;
+ assert(ElementOffsetInBytes == NextFieldOffsetInBytes &&
+ "Packing the struct changed its size!");
- return CGM.getTargetData().getABITypeAlignment(C->getType());
+ Elements = PackedElements;
+ LLVMStructAlignment = 1;
+ Packed = true;
+}
+
+bool ConstStructBuilder::Build(InitListExpr *ILE) {
+ RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+
+ unsigned FieldNo = 0;
+ unsigned ElementNo = 0;
+ for (RecordDecl::field_iterator Field = RD->field_begin(),
+ FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
+
+ // If this is a union, skip all the fields that aren't being initialized.
+ if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field)
+ continue;
+
+ // Don't emit anonymous bitfields, they just affect layout.
+ if (Field->isBitField() && !Field->getIdentifier())
+ continue;
+
+ // Get the initializer. A struct can include fields without initializers,
+ // we just use explicit null values for them.
+ llvm::Constant *EltInit;
+ if (ElementNo < ILE->getNumInits())
+ EltInit = CGM.EmitConstantExpr(ILE->getInit(ElementNo++),
+ Field->getType(), CGF);
+ else
+ EltInit = CGM.EmitNullConstant(Field->getType());
+
+ if (!Field->isBitField()) {
+ // Handle non-bitfield members.
+ if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), EltInit))
+ return false;
+ } else {
+ // Otherwise we have a bitfield.
+ if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo), EltInit))
+ return false;
+ }
}
- uint64_t getSizeInBytes(const llvm::Constant *C) const {
- return CGM.getTargetData().getTypeAllocSize(C->getType());
+ uint64_t LayoutSizeInBytes = Layout.getSize() / 8;
+
+ if (NextFieldOffsetInBytes > LayoutSizeInBytes) {
+ // If the struct is bigger than the size of the record type,
+ // we must have a flexible array member at the end.
+ assert(RD->hasFlexibleArrayMember() &&
+ "Must have flexible array member if struct is bigger than type!");
+
+ // No tail padding is necessary.
+ return true;
}
-public:
- static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF,
- InitListExpr *ILE) {
- ConstStructBuilder Builder(CGM, CGF);
+ uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes,
+ LLVMStructAlignment);
- if (!Builder.Build(ILE))
- return 0;
+ // Check if we need to convert the struct to a packed struct.
+ if (NextFieldOffsetInBytes <= LayoutSizeInBytes &&
+ LLVMSizeInBytes > LayoutSizeInBytes) {
+ assert(!Packed && "Size mismatch!");
+
+ ConvertStructToPacked();
+ assert(NextFieldOffsetInBytes <= LayoutSizeInBytes &&
+ "Converting to packed did not help!");
+ }
- llvm::Constant *Result =
- llvm::ConstantStruct::get(CGM.getLLVMContext(),
- Builder.Elements, Builder.Packed);
+ // Append tail padding if necessary.
+ AppendTailPadding(Layout.getSize());
- assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes,
- Builder.getAlignment(Result)) ==
- Builder.getSizeInBytes(Result) && "Size mismatch!");
+ assert(Layout.getSize() / 8 == NextFieldOffsetInBytes &&
+ "Tail padding mismatch!");
- return Result;
- }
-};
+ return true;
+}
+
+llvm::Constant *ConstStructBuilder::
+ BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, InitListExpr *ILE) {
+ ConstStructBuilder Builder(CGM, CGF);
+
+ if (!Builder.Build(ILE))
+ return 0;
+
+ llvm::Constant *Result =
+ llvm::ConstantStruct::get(CGM.getLLVMContext(),
+ Builder.Elements, Builder.Packed);
+
+ assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes,
+ Builder.getAlignment(Result)) ==
+ Builder.getSizeInBytes(Result) && "Size mismatch!");
+
+ return Result;
+}
+
+//===----------------------------------------------------------------------===//
+// ConstExprEmitter
+//===----------------------------------------------------------------------===//
+
class ConstExprEmitter :
public StmtVisitor<ConstExprEmitter, llvm::Constant*> {
CodeGenModule &CGM;
@@ -418,13 +446,18 @@ public:
// Get the function pointer (or index if this is a virtual function).
if (MD->isVirtual()) {
- uint64_t Index = CGM.getVTables().getMethodVtableIndex(MD);
+ uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD);
+ // FIXME: We shouldn't use / 8 here.
+ uint64_t PointerWidthInBytes =
+ CGM.getContext().Target.getPointerWidth(0) / 8;
+
// Itanium C++ ABI 2.3:
// For a non-virtual function, this field is a simple function pointer.
// For a virtual function, it is 1 plus the virtual table offset
// (in bytes) of the function, represented as a ptrdiff_t.
- Values[0] = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1);
+ Values[0] = llvm::ConstantInt::get(PtrDiffTy,
+ (Index * PointerWidthInBytes) + 1);
} else {
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
const llvm::Type *Ty =
@@ -528,8 +561,6 @@ public:
const MemberPointerType *DestTy =
E->getType()->getAs<MemberPointerType>();
- const CXXRecordDecl *BaseClass =
- cast<CXXRecordDecl>(cast<RecordType>(SrcTy->getClass())->getDecl());
const CXXRecordDecl *DerivedClass =
cast<CXXRecordDecl>(cast<RecordType>(DestTy->getClass())->getDecl());
@@ -543,7 +574,7 @@ public:
// Check if we need to update the adjustment.
if (llvm::Constant *Offset =
- CGM.GetNonVirtualBaseClassOffset(DerivedClass, BaseClass)) {
+ CGM.GetNonVirtualBaseClassOffset(DerivedClass, E->getBasePath())) {
llvm::Constant *Values[2];
Values[0] = CS->getOperand(0);
@@ -587,17 +618,15 @@ public:
}
llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) {
- std::vector<llvm::Constant*> Elts;
- const llvm::ArrayType *AType =
- cast<llvm::ArrayType>(ConvertType(ILE->getType()));
unsigned NumInitElements = ILE->getNumInits();
- // FIXME: Check for wide strings
- // FIXME: Check for NumInitElements exactly equal to 1??
- if (NumInitElements > 0 &&
+ if (NumInitElements == 1 &&
(isa<StringLiteral>(ILE->getInit(0)) ||
- isa<ObjCEncodeExpr>(ILE->getInit(0))) &&
- ILE->getType()->getArrayElementTypeNoTypeQual()->isCharType())
+ isa<ObjCEncodeExpr>(ILE->getInit(0))))
return Visit(ILE->getInit(0));
+
+ std::vector<llvm::Constant*> Elts;
+ const llvm::ArrayType *AType =
+ cast<llvm::ArrayType>(ConvertType(ILE->getType()));
const llvm::Type *ElemTy = AType->getElementType();
unsigned NumElements = AType->getNumElements();
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index d1c0f8d..9849688 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -133,6 +133,7 @@ public:
CGF.getContext().typesAreCompatible(
E->getArgType1(), E->getArgType2()));
}
+ Value *VisitOffsetOfExpr(const OffsetOfExpr *E);
Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E);
Value *VisitAddrLabelExpr(const AddrLabelExpr *E) {
llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel());
@@ -242,7 +243,7 @@ public:
return Visit(E->getSubExpr());
}
Value *VisitUnaryOffsetOf(const UnaryOperator *E);
-
+
// C++
Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
return Visit(DAE->getExpr());
@@ -314,6 +315,10 @@ public:
}
BinOpInfo EmitBinOps(const BinaryOperator *E);
+ LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
+ Value *(ScalarExprEmitter::*F)(const BinOpInfo &),
+ Value *&BitFieldResult);
+
Value *EmitCompoundAssign(const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*F)(const BinOpInfo &));
@@ -818,16 +823,12 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
return Visit(const_cast<Expr*>(E));
case CastExpr::CK_BaseToDerived: {
- const CXXRecordDecl *BaseClassDecl =
- E->getType()->getCXXRecordDeclForPointerType();
const CXXRecordDecl *DerivedClassDecl =
DestTy->getCXXRecordDeclForPointerType();
- Value *Src = Visit(const_cast<Expr*>(E));
-
- bool NullCheckValue = ShouldNullCheckClassCastValue(CE);
- return CGF.GetAddressOfDerivedClass(Src, BaseClassDecl, DerivedClassDecl,
- NullCheckValue);
+ return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl,
+ CE->getBasePath(),
+ ShouldNullCheckClassCastValue(CE));
}
case CastExpr::CK_UncheckedDerivedToBase:
case CastExpr::CK_DerivedToBase: {
@@ -836,15 +837,9 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
CXXRecordDecl *DerivedClassDecl =
cast<CXXRecordDecl>(DerivedClassTy->getDecl());
- const RecordType *BaseClassTy =
- DestTy->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseClassTy->getDecl());
-
- Value *Src = Visit(const_cast<Expr*>(E));
-
- bool NullCheckValue = ShouldNullCheckClassCastValue(CE);
- return CGF.GetAddressOfBaseClass(Src, DerivedClassDecl, BaseClassDecl,
- NullCheckValue);
+ return CGF.GetAddressOfBaseClass(Visit(E), DerivedClassDecl,
+ CE->getBasePath(),
+ ShouldNullCheckClassCastValue(CE));
}
case CastExpr::CK_Dynamic: {
Value *V = Visit(const_cast<Expr*>(E));
@@ -894,7 +889,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
std::swap(DerivedDecl, BaseDecl);
if (llvm::Constant *Adj =
- CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) {
+ CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl,
+ CE->getBasePath())) {
if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
Src = Builder.CreateSub(Src, Adj, "adj");
else
@@ -1035,6 +1031,21 @@ Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
return Builder.CreateZExt(BoolVal, ConvertType(E->getType()), "lnot.ext");
}
+Value *ScalarExprEmitter::VisitOffsetOfExpr(const OffsetOfExpr *E) {
+ Expr::EvalResult Result;
+ if(E->Evaluate(Result, CGF.getContext()))
+ return llvm::ConstantInt::get(VMContext, Result.Val.getInt());
+
+ // FIXME: Cannot support code generation for non-constant offsetof.
+ unsigned DiagID = CGF.CGM.getDiags().getCustomDiagID(Diagnostic::Error,
+ "cannot compile non-constant __builtin_offsetof");
+ CGF.CGM.getDiags().Report(CGF.getContext().getFullLoc(E->getLocStart()),
+ DiagID)
+ << E->getSourceRange();
+
+ return llvm::Constant::getNullValue(ConvertType(E->getType()));
+}
+
/// VisitSizeOfAlignOfExpr - Return the size or alignment of the type of
/// argument of the sizeof expression as an integer.
Value *
@@ -1103,22 +1114,24 @@ BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) {
return Result;
}
-Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
- Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
- bool Ignore = TestAndClearIgnoreResultAssign();
+LValue ScalarExprEmitter::EmitCompoundAssignLValue(
+ const CompoundAssignOperator *E,
+ Value *(ScalarExprEmitter::*Func)(const BinOpInfo &),
+ Value *&BitFieldResult) {
QualType LHSTy = E->getLHS()->getType();
-
+ BitFieldResult = 0;
BinOpInfo OpInfo;
-
+
if (E->getComputationResultType()->isAnyComplexType()) {
// This needs to go through the complex expression emitter, but it's a tad
// complicated to do that... I'm leaving it out for now. (Note that we do
// actually need the imaginary part of the RHS for multiplication and
// division.)
CGF.ErrorUnsupported(E, "complex compound assignment");
- return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
+ llvm::UndefValue::get(CGF.ConvertType(E->getType()));
+ return LValue();
}
-
+
// Emit the RHS first. __block variables need to have the rhs evaluated
// first, plus this should improve codegen a little.
OpInfo.RHS = Visit(E->getRHS());
@@ -1129,13 +1142,13 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy);
OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy,
E->getComputationLHSType());
-
+
// Expand the binary operator.
Value *Result = (this->*Func)(OpInfo);
-
+
// Convert the result back to the LHS type.
Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy);
-
+
// Store the result value into the LHS lvalue. Bit-fields are handled
// specially because the result is altered by the store, i.e., [C99 6.5.16p1]
// 'An assignment expression has the value of the left operand after the
@@ -1144,11 +1157,23 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
if (!LHSLV.isVolatileQualified()) {
CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy,
&Result);
- return Result;
+ BitFieldResult = Result;
+ return LHSLV;
} else
CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy);
} else
CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, LHSTy);
+ return LHSLV;
+}
+
+Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
+ Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
+ bool Ignore = TestAndClearIgnoreResultAssign();
+ Value *BitFieldResult;
+ LValue LHSLV = EmitCompoundAssignLValue(E, Func, BitFieldResult);
+ if (BitFieldResult)
+ return BitFieldResult;
+
if (Ignore)
return 0;
return EmitLoadOfLValue(LHSLV, E->getType());
@@ -1914,3 +1939,53 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
return LV;
}
+
+LValue CodeGenFunction::EmitCompoundAssignOperatorLValue(
+ const CompoundAssignOperator *E) {
+ ScalarExprEmitter Scalar(*this);
+ Value *BitFieldResult = 0;
+ switch (E->getOpcode()) {
+#define COMPOUND_OP(Op) \
+ case BinaryOperator::Op##Assign: \
+ return Scalar.EmitCompoundAssignLValue(E, &ScalarExprEmitter::Emit##Op, \
+ BitFieldResult)
+ COMPOUND_OP(Mul);
+ COMPOUND_OP(Div);
+ COMPOUND_OP(Rem);
+ COMPOUND_OP(Add);
+ COMPOUND_OP(Sub);
+ COMPOUND_OP(Shl);
+ COMPOUND_OP(Shr);
+ COMPOUND_OP(And);
+ COMPOUND_OP(Xor);
+ COMPOUND_OP(Or);
+#undef COMPOUND_OP
+
+ case BinaryOperator::PtrMemD:
+ case BinaryOperator::PtrMemI:
+ case BinaryOperator::Mul:
+ case BinaryOperator::Div:
+ case BinaryOperator::Rem:
+ case BinaryOperator::Add:
+ case BinaryOperator::Sub:
+ case BinaryOperator::Shl:
+ case BinaryOperator::Shr:
+ case BinaryOperator::LT:
+ case BinaryOperator::GT:
+ case BinaryOperator::LE:
+ case BinaryOperator::GE:
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ case BinaryOperator::And:
+ case BinaryOperator::Xor:
+ case BinaryOperator::Or:
+ case BinaryOperator::LAnd:
+ case BinaryOperator::LOr:
+ case BinaryOperator::Assign:
+ case BinaryOperator::Comma:
+ assert(false && "Not valid compound assignment operators");
+ break;
+ }
+
+ llvm_unreachable("Unhandled compound assignment operator");
+}
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 206d438..3359250 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -53,31 +53,36 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
// arguments in generic code.
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
- const Expr *ReceiverExpr = E->getReceiver();
bool isSuperMessage = false;
bool isClassMessage = false;
+ ObjCInterfaceDecl *OID = 0;
// Find the receiver
- llvm::Value *Receiver;
- if (!ReceiverExpr) {
- const ObjCInterfaceDecl *OID = E->getClassInfo().Decl;
-
- // Very special case, super send in class method. The receiver is
- // self (the class object) and the send uses super semantics.
- if (!OID) {
- assert(E->getClassName()->isStr("super") &&
- "Unexpected missing class interface in message send.");
- isSuperMessage = true;
- Receiver = LoadObjCSelf();
- } else {
- Receiver = Runtime.GetClass(Builder, OID);
- }
-
+ llvm::Value *Receiver = 0;
+ switch (E->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ Receiver = EmitScalarExpr(E->getInstanceReceiver());
+ break;
+
+ case ObjCMessageExpr::Class: {
+ const ObjCInterfaceType *IFace
+ = E->getClassReceiver()->getAs<ObjCInterfaceType>();
+ OID = IFace->getDecl();
+ assert(IFace && "Invalid Objective-C class message send");
+ Receiver = Runtime.GetClass(Builder, OID);
isClassMessage = true;
- } else if (isa<ObjCSuperExpr>(E->getReceiver())) {
+ break;
+ }
+
+ case ObjCMessageExpr::SuperInstance:
+ Receiver = LoadObjCSelf();
isSuperMessage = true;
+ break;
+
+ case ObjCMessageExpr::SuperClass:
Receiver = LoadObjCSelf();
- } else {
- Receiver = EmitScalarExpr(E->getReceiver());
+ isSuperMessage = true;
+ isClassMessage = true;
+ break;
}
CallArgList Args;
@@ -98,7 +103,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
}
return Runtime.GenerateMessageSend(*this, E->getType(), E->getSelector(),
- Receiver, isClassMessage, Args,
+ Receiver, Args, OID,
E->getMethodDecl());
}
@@ -148,19 +153,21 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) {
ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl();
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
+ bool IsAtomic =
+ !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic);
ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
assert(OMD && "Invalid call to generate getter (empty method)");
// FIXME: This is rather murky, we create this here since they will not have
// been created by Sema for us.
OMD->createImplicitParams(getContext(), IMP->getClassInterface());
StartObjCMethod(OMD, IMP->getClassInterface());
-
+
// Determine if we should use an objc_getProperty call for
// this. Non-atomic properties are directly evaluated.
// atomic 'copy' and 'retain' properties are also directly
// evaluated in gc-only mode.
if (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly &&
- !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) &&
+ IsAtomic &&
(PD->getSetterKind() == ObjCPropertyDecl::Copy ||
PD->getSetterKind() == ObjCPropertyDecl::Retain)) {
llvm::Value *GetPropertyFn =
@@ -208,7 +215,44 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
StoreComplexToAddr(Pair, ReturnValue, LV.isVolatileQualified());
}
else if (hasAggregateLLVMType(Ivar->getType())) {
- EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType());
+ bool IsStrong = false;
+ if ((IsAtomic || (IsStrong = IvarTypeWithAggrGCObjects(Ivar->getType())))
+ && CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect
+ && CGM.getObjCRuntime().GetCopyStructFunction()) {
+ llvm::Value *GetCopyStructFn =
+ CGM.getObjCRuntime().GetCopyStructFunction();
+ CodeGenTypes &Types = CGM.getTypes();
+ // objc_copyStruct (ReturnValue, &structIvar,
+ // sizeof (Type of Ivar), isAtomic, false);
+ CallArgList Args;
+ RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue,
+ Types.ConvertType(getContext().VoidPtrTy)));
+ Args.push_back(std::make_pair(RV, getContext().VoidPtrTy));
+ RV = RValue::get(Builder.CreateBitCast(LV.getAddress(),
+ Types.ConvertType(getContext().VoidPtrTy)));
+ Args.push_back(std::make_pair(RV, getContext().VoidPtrTy));
+ // sizeof (Type of Ivar)
+ uint64_t Size = getContext().getTypeSize(Ivar->getType()) / 8;
+ llvm::Value *SizeVal =
+ llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), Size);
+ Args.push_back(std::make_pair(RValue::get(SizeVal),
+ getContext().LongTy));
+ llvm::Value *isAtomic =
+ llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy),
+ IsAtomic ? 1 : 0);
+ Args.push_back(std::make_pair(RValue::get(isAtomic),
+ getContext().BoolTy));
+ llvm::Value *hasStrong =
+ llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy),
+ IsStrong ? 1 : 0);
+ Args.push_back(std::make_pair(RValue::get(hasStrong),
+ getContext().BoolTy));
+ EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
+ FunctionType::ExtInfo()),
+ GetCopyStructFn, ReturnValueSlot(), Args);
+ }
+ else
+ EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType());
} else {
CodeGenTypes &Types = CGM.getTypes();
RValue RV = EmitLoadOfLValue(LV, Ivar->getType());
@@ -289,6 +333,41 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
FunctionType::ExtInfo()),
SetPropertyFn,
ReturnValueSlot(), Args);
+ } else if (IsAtomic && hasAggregateLLVMType(Ivar->getType()) &&
+ !Ivar->getType()->isAnyComplexType() &&
+ IndirectObjCSetterArg(*CurFnInfo)
+ && CGM.getObjCRuntime().GetCopyStructFunction()) {
+ // objc_copyStruct (&structIvar, &Arg,
+ // sizeof (struct something), true, false);
+ llvm::Value *GetCopyStructFn =
+ CGM.getObjCRuntime().GetCopyStructFunction();
+ CodeGenTypes &Types = CGM.getTypes();
+ CallArgList Args;
+ LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0);
+ RValue RV = RValue::get(Builder.CreateBitCast(LV.getAddress(),
+ Types.ConvertType(getContext().VoidPtrTy)));
+ Args.push_back(std::make_pair(RV, getContext().VoidPtrTy));
+ llvm::Value *Arg = LocalDeclMap[*OMD->param_begin()];
+ llvm::Value *ArgAsPtrTy =
+ Builder.CreateBitCast(Arg,
+ Types.ConvertType(getContext().VoidPtrTy));
+ RV = RValue::get(ArgAsPtrTy);
+ Args.push_back(std::make_pair(RV, getContext().VoidPtrTy));
+ // sizeof (Type of Ivar)
+ uint64_t Size = getContext().getTypeSize(Ivar->getType()) / 8;
+ llvm::Value *SizeVal =
+ llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), Size);
+ Args.push_back(std::make_pair(RValue::get(SizeVal),
+ getContext().LongTy));
+ llvm::Value *True =
+ llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1);
+ Args.push_back(std::make_pair(RValue::get(True), getContext().BoolTy));
+ llvm::Value *False =
+ llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0);
+ Args.push_back(std::make_pair(RValue::get(False), getContext().BoolTy));
+ EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
+ FunctionType::ExtInfo()),
+ GetCopyStructFn, ReturnValueSlot(), Args);
} else {
// FIXME: Find a clean way to avoid AST node creation.
SourceLocation Loc = PD->getLocation();
@@ -304,7 +383,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
if (getContext().getCanonicalType(Ivar->getType()) !=
getContext().getCanonicalType(ArgDecl->getType())) {
ImplicitCastExpr ArgCasted(Ivar->getType(), CastExpr::CK_BitCast, &Arg,
- false);
+ CXXBaseSpecifierArray(), false);
BinaryOperator Assign(&IvarRef, &ArgCasted, BinaryOperator::Assign,
Ivar->getType(), Loc);
EmitStmt(&Assign);
@@ -318,6 +397,83 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
FinishFunction();
}
+void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
+ ObjCMethodDecl *MD,
+ bool ctor) {
+ llvm::SmallVector<CXXBaseOrMemberInitializer *, 8> IvarInitializers;
+ MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface());
+ StartObjCMethod(MD, IMP->getClassInterface());
+ for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(),
+ E = IMP->init_end(); B != E; ++B) {
+ CXXBaseOrMemberInitializer *Member = (*B);
+ IvarInitializers.push_back(Member);
+ }
+ if (ctor) {
+ for (unsigned I = 0, E = IvarInitializers.size(); I != E; ++I) {
+ CXXBaseOrMemberInitializer *IvarInit = IvarInitializers[I];
+ FieldDecl *Field = IvarInit->getMember();
+ QualType FieldType = Field->getType();
+ ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
+ LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
+ LoadObjCSelf(), Ivar, 0);
+ EmitAggExpr(IvarInit->getInit(), LV.getAddress(),
+ LV.isVolatileQualified(), false, true);
+ }
+ // constructor returns 'self'.
+ CodeGenTypes &Types = CGM.getTypes();
+ QualType IdTy(CGM.getContext().getObjCIdType());
+ llvm::Value *SelfAsId =
+ Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy));
+ EmitReturnOfRValue(RValue::get(SelfAsId), IdTy);
+ }
+ else {
+ // dtor
+ for (size_t i = IvarInitializers.size(); i > 0; --i) {
+ FieldDecl *Field = IvarInitializers[i - 1]->getMember();
+ QualType FieldType = Field->getType();
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = getContext().getBaseElementType(FieldType);
+
+ ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
+ LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
+ LoadObjCSelf(), Ivar, 0);
+ const RecordType *RT = FieldType->getAs<RecordType>();
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (Array) {
+ const llvm::Type *BasePtr = ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ Builder.CreateBitCast(LV.getAddress(), BasePtr);
+ EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()),
+ Array, BaseAddrPtr);
+ }
+ else
+ EmitCXXDestructorCall(FieldClassDecl->getDestructor(CGM.getContext()),
+ Dtor_Complete, /*ForVirtualBase=*/false,
+ LV.getAddress());
+ }
+ }
+ FinishFunction();
+}
+
+bool CodeGenFunction::IndirectObjCSetterArg(const CGFunctionInfo &FI) {
+ CGFunctionInfo::const_arg_iterator it = FI.arg_begin();
+ it++; it++;
+ const ABIArgInfo &AI = it->info;
+ // FIXME. Is this sufficient check?
+ return (AI.getKind() == ABIArgInfo::Indirect);
+}
+
+bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) {
+ if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC)
+ return false;
+ if (const RecordType *FDTTy = Ty.getTypePtr()->getAs<RecordType>())
+ return FDTTy->getDecl()->hasObjectMember();
+ return false;
+}
+
llvm::Value *CodeGenFunction::LoadObjCSelf() {
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
// See if we need to lazily forward self inside a block literal.
@@ -360,7 +516,7 @@ RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) {
return CGM.getObjCRuntime().
GenerateMessageSend(*this, Exp->getType(), S,
EmitScalarExpr(E->getBase()),
- false, CallArgList());
+ CallArgList());
} else {
const ObjCImplicitSetterGetterRefExpr *KE =
cast<ObjCImplicitSetterGetterRefExpr>(Exp);
@@ -376,7 +532,7 @@ RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) {
return CGM.getObjCRuntime().
GenerateMessageSend(*this, Exp->getType(), S,
Receiver,
- KE->getInterfaceDecl() != 0, CallArgList());
+ CallArgList(), KE->getInterfaceDecl());
}
}
@@ -413,7 +569,7 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp,
Args.push_back(std::make_pair(Src, E->getType()));
CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S,
EmitScalarExpr(E->getBase()),
- false, Args);
+ Args);
} else if (const ObjCImplicitSetterGetterRefExpr *E =
dyn_cast<ObjCImplicitSetterGetterRefExpr>(Exp)) {
Selector S = E->getSetterMethod()->getSelector();
@@ -430,7 +586,7 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp,
Args.push_back(std::make_pair(Src, E->getType()));
CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S,
Receiver,
- E->getInterfaceDecl() != 0, Args);
+ Args, E->getInterfaceDecl());
} else
assert (0 && "bad expression node in EmitObjCPropertySet");
}
@@ -498,7 +654,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
CGM.getObjCRuntime().GenerateMessageSend(*this,
getContext().UnsignedLongTy,
FastEnumSel,
- Collection, false, Args);
+ Collection, Args);
llvm::Value *LimitPtr = CreateMemTemp(getContext().UnsignedLongTy,
"limit.ptr");
@@ -623,7 +779,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
CGM.getObjCRuntime().GenerateMessageSend(*this,
getContext().UnsignedLongTy,
FastEnumSel,
- Collection, false, Args);
+ Collection, Args);
Builder.CreateStore(CountRV.getScalarVal(), LimitPtr);
Limit = Builder.CreateLoad(LimitPtr);
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index d445200..3c51b7e 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -26,6 +26,7 @@
#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
+#include "llvm/LLVMContext.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/Compiler.h"
@@ -81,6 +82,8 @@ private:
llvm::Constant *Zeros[2];
llvm::Constant *NULLPtr;
llvm::LLVMContext &VMContext;
+ /// Metadata kind used to tie method lookups to message sends.
+ unsigned msgSendMDKind;
private:
llvm::Constant *GenerateIvarList(
const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames,
@@ -112,7 +115,8 @@ private:
llvm::Constant *Methods,
llvm::Constant *Protocols,
llvm::Constant *IvarOffsets,
- llvm::Constant *Properties);
+ llvm::Constant *Properties,
+ bool isMeta=false);
llvm::Constant *GenerateProtocolMethodList(
const llvm::SmallVectorImpl<llvm::Constant *> &MethodNames,
const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes);
@@ -141,8 +145,8 @@ public:
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
- bool IsClassMessage,
const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method);
virtual CodeGen::RValue
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
@@ -170,6 +174,7 @@ public:
virtual llvm::Function *ModuleInitFunction();
virtual llvm::Function *GetPropertyGetFunction();
virtual llvm::Function *GetPropertySetFunction();
+ virtual llvm::Function *GetCopyStructFunction();
virtual llvm::Constant *EnumerationMutationFunction();
virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
@@ -221,10 +226,6 @@ void CGObjCGNU::EmitClassRef(const std::string &className) {
llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef);
}
-static std::string SymbolNameForClass(const std::string &ClassName) {
- return "_OBJC_CLASS_" + ClassName;
-}
-
static std::string SymbolNameForMethod(const std::string &ClassName, const
std::string &CategoryName, const std::string &MethodName, bool isClassMethod)
{
@@ -238,6 +239,9 @@ static std::string SymbolNameForMethod(const std::string &ClassName, const
CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
: CGM(cgm), TheModule(CGM.getModule()), ClassPtrAlias(0),
MetaClassPtrAlias(0), VMContext(cgm.getLLVMContext()) {
+
+ msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend");
+
IntTy = cast<llvm::IntegerType>(
CGM.getTypes().ConvertType(CGM.getContext().IntTy));
LongTy = cast<llvm::IntegerType>(
@@ -452,12 +456,15 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
return RValue::get(0);
}
}
- llvm::Value *cmd = GetSelector(CGF.Builder, Sel);
+
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *cmd = GetSelector(Builder, Sel);
+
CallArgList ActualArgs;
ActualArgs.push_back(
- std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)),
+ std::make_pair(RValue::get(Builder.CreateBitCast(Receiver, IdTy)),
ASTIdTy));
ActualArgs.push_back(std::make_pair(RValue::get(cmd),
CGF.getContext().getObjCSelType()));
@@ -481,7 +488,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
IdTy, Params, true), "objc_get_class");
}
- ReceiverClass = CGF.Builder.CreateCall(classLookupFunction,
+ ReceiverClass = Builder.CreateCall(classLookupFunction,
MakeConstantString(Class->getNameAsString()));
} else {
// Set up global aliases for the metaclass or class pointer if they do not
@@ -506,36 +513,64 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
}
}
// Cast the pointer to a simplified version of the class structure
- ReceiverClass = CGF.Builder.CreateBitCast(ReceiverClass,
+ ReceiverClass = Builder.CreateBitCast(ReceiverClass,
llvm::PointerType::getUnqual(
llvm::StructType::get(VMContext, IdTy, IdTy, NULL)));
// Get the superclass pointer
- ReceiverClass = CGF.Builder.CreateStructGEP(ReceiverClass, 1);
+ ReceiverClass = Builder.CreateStructGEP(ReceiverClass, 1);
// Load the superclass pointer
- ReceiverClass = CGF.Builder.CreateLoad(ReceiverClass);
+ ReceiverClass = Builder.CreateLoad(ReceiverClass);
// Construct the structure used to look up the IMP
llvm::StructType *ObjCSuperTy = llvm::StructType::get(VMContext,
Receiver->getType(), IdTy, NULL);
- llvm::Value *ObjCSuper = CGF.Builder.CreateAlloca(ObjCSuperTy);
+ llvm::Value *ObjCSuper = Builder.CreateAlloca(ObjCSuperTy);
- CGF.Builder.CreateStore(Receiver, CGF.Builder.CreateStructGEP(ObjCSuper, 0));
- CGF.Builder.CreateStore(ReceiverClass,
- CGF.Builder.CreateStructGEP(ObjCSuper, 1));
+ Builder.CreateStore(Receiver, Builder.CreateStructGEP(ObjCSuper, 0));
+ Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1));
// Get the IMP
std::vector<const llvm::Type*> Params;
Params.push_back(llvm::PointerType::getUnqual(ObjCSuperTy));
Params.push_back(SelectorTy);
+
+ llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
+ llvm::Value *imp;
+
+ if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
+ // The lookup function returns a slot, which can be safely cached.
+ llvm::Type *SlotTy = llvm::StructType::get(VMContext, PtrTy, PtrTy, PtrTy,
+ IntTy, llvm::PointerType::getUnqual(impType), NULL);
+
+ llvm::Constant *lookupFunction =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(
+ llvm::PointerType::getUnqual(SlotTy), Params, true),
+ "objc_slot_lookup_super");
+
+ llvm::CallInst *slot = Builder.CreateCall(lookupFunction, lookupArgs,
+ lookupArgs+2);
+ slot->setOnlyReadsMemory();
+
+ imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4));
+ } else {
llvm::Constant *lookupFunction =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(
llvm::PointerType::getUnqual(impType), Params, true),
"objc_msg_lookup_super");
+ imp = Builder.CreateCall(lookupFunction, lookupArgs, lookupArgs+2);
+ }
- llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
- llvm::Value *imp = CGF.Builder.CreateCall(lookupFunction, lookupArgs,
- lookupArgs+2);
-
- return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs);
+ llvm::Value *impMD[] = {
+ llvm::MDString::get(VMContext, Sel.getAsString()),
+ llvm::MDString::get(VMContext, Class->getSuperClass()->getNameAsString()),
+ llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsClassMessage)
+ };
+ llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3);
+
+ llvm::Instruction *call;
+ RValue msgRet = CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs,
+ 0, &call);
+ call->setMetadata(msgSendMDKind, node);
+ return msgRet;
}
/// Generate code for a message send expression.
@@ -544,9 +579,10 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
- bool IsClassMessage,
const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
+ // Strip out message sends to retain / release in GC mode
if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
if (Sel == RetainSel || Sel == AutoreleaseSel) {
return RValue::get(Receiver);
@@ -555,7 +591,39 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
return RValue::get(0);
}
}
+
CGBuilderTy &Builder = CGF.Builder;
+
+ // If the return type is something that goes in an integer register, the
+ // runtime will handle 0 returns. For other cases, we fill in the 0 value
+ // ourselves.
+ //
+ // The language spec says the result of this kind of message send is
+ // undefined, but lots of people seem to have forgotten to read that
+ // paragraph and insist on sending messages to nil that have structure
+ // returns. With GCC, this generates a random return value (whatever happens
+ // to be on the stack / in those registers at the time) on most platforms,
+ // and generates a SegV on SPARC. With LLVM it corrupts the stack.
+ bool isPointerSizedReturn = false;
+ if (ResultType->isAnyPointerType() || ResultType->isIntegralType() ||
+ ResultType->isVoidType())
+ isPointerSizedReturn = true;
+
+ llvm::BasicBlock *startBB = 0;
+ llvm::BasicBlock *messageBB = 0;
+ llvm::BasicBlock *contiueBB = 0;
+
+ if (!isPointerSizedReturn) {
+ startBB = Builder.GetInsertBlock();
+ messageBB = CGF.createBasicBlock("msgSend");
+ contiueBB = CGF.createBasicBlock("continue");
+
+ llvm::Value *isNil = Builder.CreateICmpEQ(Receiver,
+ llvm::Constant::getNullValue(Receiver->getType()));
+ Builder.CreateCondBr(isNil, contiueBB, messageBB);
+ CGF.EmitBlock(messageBB);
+ }
+
IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
llvm::Value *cmd;
if (Method)
@@ -577,6 +645,14 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
const llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
+ llvm::Value *impMD[] = {
+ llvm::MDString::get(VMContext, Sel.getAsString()),
+ llvm::MDString::get(VMContext, Class ? Class->getNameAsString() :""),
+ llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), Class!=0)
+ };
+ llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3);
+
+
llvm::Value *imp;
// For sender-aware dispatch, we pass the sender as the third argument to a
// lookup function. When sending messages from C code, the sender is nil.
@@ -611,9 +687,13 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
LookupFn->setDoesNotCapture(1);
}
- llvm::Value *slot =
+ llvm::CallInst *slot =
Builder.CreateCall3(lookupFunction, ReceiverPtr, cmd, self);
+ slot->setOnlyReadsMemory();
+ slot->setMetadata(msgSendMDKind, node);
+
imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4));
+
// The lookup function may have changed the receiver, so make sure we use
// the new one.
ActualArgs[0] =
@@ -628,9 +708,46 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
"objc_msg_lookup");
imp = Builder.CreateCall2(lookupFunction, Receiver, cmd);
+ cast<llvm::CallInst>(imp)->setMetadata(msgSendMDKind, node);
}
-
- return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs);
+ llvm::Instruction *call;
+ RValue msgRet = CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs,
+ 0, &call);
+ call->setMetadata(msgSendMDKind, node);
+
+ if (!isPointerSizedReturn) {
+ CGF.EmitBlock(contiueBB);
+ if (msgRet.isScalar()) {
+ llvm::Value *v = msgRet.getScalarVal();
+ llvm::PHINode *phi = Builder.CreatePHI(v->getType());
+ phi->addIncoming(v, messageBB);
+ phi->addIncoming(llvm::Constant::getNullValue(v->getType()), startBB);
+ msgRet = RValue::get(phi);
+ } else if (msgRet.isAggregate()) {
+ llvm::Value *v = msgRet.getAggregateAddr();
+ llvm::PHINode *phi = Builder.CreatePHI(v->getType());
+ const llvm::PointerType *RetTy = cast<llvm::PointerType>(v->getType());
+ llvm::AllocaInst *NullVal =
+ CGF.CreateTempAlloca(RetTy->getElementType(), "null");
+ CGF.InitTempAlloca(NullVal,
+ llvm::Constant::getNullValue(RetTy->getElementType()));
+ phi->addIncoming(v, messageBB);
+ phi->addIncoming(NullVal, startBB);
+ msgRet = RValue::getAggregate(phi);
+ } else /* isComplex() */ {
+ std::pair<llvm::Value*,llvm::Value*> v = msgRet.getComplexVal();
+ llvm::PHINode *phi = Builder.CreatePHI(v.first->getType());
+ phi->addIncoming(v.first, messageBB);
+ phi->addIncoming(llvm::Constant::getNullValue(v.first->getType()),
+ startBB);
+ llvm::PHINode *phi2 = Builder.CreatePHI(v.second->getType());
+ phi2->addIncoming(v.second, messageBB);
+ phi2->addIncoming(llvm::Constant::getNullValue(v.second->getType()),
+ startBB);
+ msgRet = RValue::getComplex(phi, phi2);
+ }
+ }
+ return msgRet;
}
/// Generates a MethodList. Used in construction of a objc_class and
@@ -749,7 +866,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
llvm::Constant *Methods,
llvm::Constant *Protocols,
llvm::Constant *IvarOffsets,
- llvm::Constant *Properties) {
+ llvm::Constant *Properties,
+ bool isMeta) {
// Set up the class structure
// Note: Several of these are char*s when they should be ids. This is
// because the runtime performs this translation on load.
@@ -799,8 +917,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
// Create an instance of the structure
// 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);
+ return MakeGlobal(ClassTy, Elements, (isMeta ? "_OBJC_METACLASS_":
+ "_OBJC_CLASS_") + std::string(Name), llvm::GlobalValue::ExternalLinkage);
}
llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
@@ -1289,16 +1407,21 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
instanceSize = 0 - (instanceSize - superInstanceSize);
}
- for (ObjCInterfaceDecl::ivar_iterator iter = ClassDecl->ivar_begin(),
- endIter = ClassDecl->ivar_end() ; iter != endIter ; iter++) {
+
+ // Collect declared and synthesized ivars.
+ llvm::SmallVector<ObjCIvarDecl*, 16> OIvars;
+ CGM.getContext().ShallowCollectObjCIvars(ClassDecl, OIvars);
+
+ for (unsigned i = 0, e = OIvars.size(); i != e; ++i) {
+ ObjCIvarDecl *IVD = OIvars[i];
// Store the name
- IvarNames.push_back(MakeConstantString((*iter)->getNameAsString()));
+ IvarNames.push_back(MakeConstantString(IVD->getNameAsString()));
// Get the type encoding for this ivar
std::string TypeStr;
- Context.getObjCEncodingForType((*iter)->getType(), TypeStr);
+ Context.getObjCEncodingForType(IVD->getType(), TypeStr);
IvarTypes.push_back(MakeConstantString(TypeStr));
// Get the offset
- uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter);
+ uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD);
uint64_t Offset = BaseOffset;
if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
Offset = BaseOffset - superInstanceSize;
@@ -1309,7 +1432,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
false, llvm::GlobalValue::ExternalLinkage,
llvm::ConstantInt::get(IntTy, BaseOffset),
"__objc_ivar_offset_value_" + ClassName +"." +
- (*iter)->getNameAsString()));
+ IVD->getNameAsString()));
}
llvm::Constant *IvarOffsetArrayInit =
llvm::ConstantArray::get(llvm::ArrayType::get(PtrToIntTy,
@@ -1411,7 +1534,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
//Generate metaclass for class methods
llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr,
NULLPtr, 0x12L, ClassName.c_str(), 0, Zeros[0], GenerateIvarList(
- empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr);
+ empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr, true);
// Generate the class structure
llvm::Constant *ClassStruct =
@@ -1658,10 +1781,9 @@ llvm::Function *CGObjCGNU::GetPropertyGetFunction() {
CGM.getTypes().ConvertType(CGM.getContext().BoolTy);
Params.push_back(IdTy);
Params.push_back(SelectorTy);
- // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64
- Params.push_back(LongTy);
+ Params.push_back(IntTy);
Params.push_back(BoolTy);
- // void objc_getProperty (id, SEL, ptrdiff_t, bool)
+ // void objc_getProperty (id, SEL, int, bool)
const llvm::FunctionType *FTy =
llvm::FunctionType::get(IdTy, Params, false);
return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy,
@@ -1674,18 +1796,22 @@ llvm::Function *CGObjCGNU::GetPropertySetFunction() {
CGM.getTypes().ConvertType(CGM.getContext().BoolTy);
Params.push_back(IdTy);
Params.push_back(SelectorTy);
- // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64
- Params.push_back(LongTy);
+ Params.push_back(IntTy);
Params.push_back(IdTy);
Params.push_back(BoolTy);
Params.push_back(BoolTy);
- // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool)
+ // void objc_setProperty (id, SEL, int, id, bool, bool)
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false);
return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy,
"objc_setProperty"));
}
+// FIXME. Implement this.
+llvm::Function *CGObjCGNU::GetCopyStructFunction() {
+ return 0;
+}
+
llvm::Constant *CGObjCGNU::EnumerationMutationFunction() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
@@ -1764,7 +1890,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::Value *RethrowPtr = CGF.CreateTempAlloca(Exc->getType(), "_rethrow");
llvm::SmallVector<llvm::Value*, 8> ESelArgs;
- llvm::SmallVector<std::pair<const ParmVarDecl*, const Stmt*>, 8> Handlers;
+ llvm::SmallVector<std::pair<const VarDecl*, const Stmt*>, 8> Handlers;
ESelArgs.push_back(Exc);
ESelArgs.push_back(Personality);
@@ -1772,12 +1898,13 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
bool HasCatchAll = false;
// Only @try blocks are allowed @catch blocks, but both can have @finally
if (isTry) {
- if (const ObjCAtCatchStmt* CatchStmt =
- cast<ObjCAtTryStmt>(S).getCatchStmts()) {
+ if (cast<ObjCAtTryStmt>(S).getNumCatchStmts()) {
+ const ObjCAtTryStmt &AtTry = cast<ObjCAtTryStmt>(S);
CGF.setInvokeDest(CatchInCatch);
- for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
- const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
+ for (unsigned I = 0, N = AtTry.getNumCatchStmts(); I != N; ++I) {
+ const ObjCAtCatchStmt *CatchStmt = AtTry.getCatchStmt(I);
+ const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
Handlers.push_back(std::make_pair(CatchDecl,
CatchStmt->getCatchBody()));
@@ -1816,7 +1943,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
ESelArgs.begin(), ESelArgs.end(), "selector");
for (unsigned i = 0, e = Handlers.size(); i != e; ++i) {
- const ParmVarDecl *CatchParam = Handlers[i].first;
+ const VarDecl *CatchParam = Handlers[i].first;
const Stmt *CatchBody = Handlers[i].second;
llvm::BasicBlock *Next = 0;
@@ -2046,7 +2173,14 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
// when linked against code which isn't (most of the time).
llvm::GlobalVariable *IvarOffsetPointer = TheModule.getNamedGlobal(Name);
if (!IvarOffsetPointer) {
- uint64_t Offset = ComputeIvarBaseOffset(CGM, ID, Ivar);
+ uint64_t Offset;
+ if (ObjCImplementationDecl *OID =
+ CGM.getContext().getObjCImplementation(
+ const_cast<ObjCInterfaceDecl *>(ID)))
+ Offset = ComputeIvarBaseOffset(CGM, OID, Ivar);
+ else
+ Offset = ComputeIvarBaseOffset(CGM, ID, Ivar);
+
llvm::ConstantInt *OffsetGuess =
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
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index ac8fa05..77eabbf 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -124,9 +124,19 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
// layout object. However, this is blocked on other cleanups to the
// Objective-C code, so for now we just live with allocating a bunch of these
// objects.
- unsigned FieldNo = 0; // This value is unused.
+
+ // We always construct a single, possibly unaligned, access for this case.
+ CGBitFieldInfo::AccessInfo AI;
+ AI.FieldIndex = 0;
+ AI.FieldByteOffset = 0;
+ AI.FieldBitStart = BitOffset;
+ AI.AccessWidth = CGF.CGM.getContext().getTypeSize(IvarTy);
+ AI.AccessAlignment = 0;
+ AI.TargetBitOffset = 0;
+ AI.TargetBitWidth = BitFieldSize;
+
CGBitFieldInfo *Info =
- new (CGF.CGM.getContext()) CGBitFieldInfo(FieldNo, BitOffset, BitFieldSize,
+ new (CGF.CGM.getContext()) CGBitFieldInfo(BitFieldSize, 1, &AI,
IvarTy->isSignedIntegerType());
// FIXME: We need to set a very conservative alignment on this, or make sure
@@ -329,6 +339,24 @@ public:
return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
}
+
+ llvm::Constant *getCopyStructFn() {
+ CodeGen::CodeGenTypes &Types = CGM.getTypes();
+ ASTContext &Ctx = CGM.getContext();
+ // void objc_copyStruct (void *, const void *, size_t, bool, bool)
+ llvm::SmallVector<CanQualType,5> Params;
+ Params.push_back(Ctx.VoidPtrTy);
+ Params.push_back(Ctx.VoidPtrTy);
+ Params.push_back(Ctx.LongTy);
+ Params.push_back(Ctx.BoolTy);
+ Params.push_back(Ctx.BoolTy);
+ const llvm::FunctionType *FTy =
+ Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
+ FunctionType::ExtInfo()),
+ false);
+ return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct");
+ }
+
llvm::Constant *getEnumerationMutationFn() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
@@ -954,6 +982,10 @@ protected:
const ObjCMethodDecl *OMD,
const ObjCCommonTypesHelper &ObjCTypes);
+ /// EmitImageInfo - Emit the image info marker used to encode some module
+ /// level information.
+ void EmitImageInfo();
+
public:
CGObjCCommonMac(CodeGen::CodeGenModule &cgm) :
CGM(cgm), VMContext(cgm.getLLVMContext()) { }
@@ -980,9 +1012,6 @@ public:
class CGObjCMac : public CGObjCCommonMac {
private:
ObjCTypesHelper ObjCTypes;
- /// EmitImageInfo - Emit the image info marker used to encode some module
- /// level information.
- void EmitImageInfo();
/// EmitModuleInfo - Another marker encoding module level
/// information.
@@ -1100,8 +1129,8 @@ public:
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
- bool IsClassMessage,
const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method);
virtual CodeGen::RValue
@@ -1134,6 +1163,7 @@ public:
virtual llvm::Constant *GetPropertyGetFunction();
virtual llvm::Constant *GetPropertySetFunction();
+ virtual llvm::Constant *GetCopyStructFunction();
virtual llvm::Constant *EnumerationMutationFunction();
virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
@@ -1327,8 +1357,8 @@ public:
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
- bool IsClassMessage,
const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method);
virtual CodeGen::RValue
@@ -1366,6 +1396,11 @@ public:
virtual llvm::Constant *GetPropertySetFunction() {
return ObjCTypes.getSetPropertyFn();
}
+
+ virtual llvm::Constant *GetCopyStructFunction() {
+ return ObjCTypes.getCopyStructFn();
+ }
+
virtual llvm::Constant *EnumerationMutationFunction() {
return ObjCTypes.getEnumerationMutationFn();
}
@@ -1459,9 +1494,20 @@ llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
};
*/
+/// or Generate a constant NSString object.
+/*
+ struct __builtin_NSString {
+ const int *isa; // point to __NSConstantStringClassReference
+ const char *str;
+ unsigned int length;
+ };
+*/
+
llvm::Constant *CGObjCCommonMac::GenerateConstantString(
const StringLiteral *SL) {
- return CGM.GetAddrOfConstantCFString(SL);
+ return (CGM.getLangOptions().NoConstantCFStrings == 0 ?
+ CGM.GetAddrOfConstantCFString(SL) :
+ CGM.GetAddrOfConstantNSString(SL));
}
/// Generates a message send where the super is the receiver. This is
@@ -1531,8 +1577,8 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
- bool IsClassMessage,
const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
return EmitLegacyMessageSend(CGF, ResultType,
EmitSelector(CGF.Builder, Sel),
@@ -1696,7 +1742,6 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
Init,
"\01L_OBJC_PROTOCOL_" + PD->getName());
Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
- Entry->setAlignment(4);
// FIXME: Is this necessary? Why only for protocol?
Entry->setAlignment(4);
}
@@ -1718,7 +1763,6 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) {
0,
"\01L_OBJC_PROTOCOL_" + PD->getName());
Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
- Entry->setAlignment(4);
// FIXME: Is this necessary? Why only for protocol?
Entry->setAlignment(4);
}
@@ -2039,6 +2083,8 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
Interface->protocol_begin(),
Interface->protocol_end());
unsigned Flags = eClassFlags_Factory;
+ if (ID->getNumIvarInitializers())
+ Flags |= eClassFlags_HasCXXStructors;
unsigned Size =
CGM.getContext().getASTObjCImplementationLayout(ID).getSize() / 8;
@@ -2430,6 +2476,10 @@ llvm::Constant *CGObjCMac::GetPropertySetFunction() {
return ObjCTypes.getSetPropertyFn();
}
+llvm::Constant *CGObjCMac::GetCopyStructFunction() {
+ return ObjCTypes.getCopyStructFn();
+}
+
llvm::Constant *CGObjCMac::EnumerationMutationFunction() {
return ObjCTypes.getEnumerationMutationFn();
}
@@ -2597,8 +2647,9 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext),
CallTryExitPtr);
CGF.EmitBranchThroughCleanup(FinallyRethrow);
- } else if (const ObjCAtCatchStmt* CatchStmt =
- cast<ObjCAtTryStmt>(S).getCatchStmts()) {
+ } else if (cast<ObjCAtTryStmt>(S).getNumCatchStmts()) {
+ const ObjCAtTryStmt* AtTryStmt = cast<ObjCAtTryStmt>(&S);
+
// Enter a new exception try block (in case a @catch block throws
// an exception).
CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData);
@@ -2617,10 +2668,11 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// matched and avoid generating code for falling off the end if
// so.
bool AllMatched = false;
- for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
+ for (unsigned I = 0, N = AtTryStmt->getNumCatchStmts(); I != N; ++I) {
+ const ObjCAtCatchStmt *CatchStmt = AtTryStmt->getCatchStmt(I);
llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch");
- const ParmVarDecl *CatchParam = CatchStmt->getCatchParamDecl();
+ const VarDecl *CatchParam = CatchStmt->getCatchParamDecl();
const ObjCObjectPointerType *OPT = 0;
// catch(...) always matches.
@@ -2911,18 +2963,17 @@ llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
/// unsigned flags;
/// };
enum ImageInfoFlags {
- eImageInfo_FixAndContinue = (1 << 0), // FIXME: Not sure what
- // this implies.
+ eImageInfo_FixAndContinue = (1 << 0),
eImageInfo_GarbageCollected = (1 << 1),
eImageInfo_GCOnly = (1 << 2),
eImageInfo_OptimizedByDyld = (1 << 3), // FIXME: When is this set.
- // A flag indicating that the module has no instances of an
- // @synthesize of a superclass variable. <rdar://problem/6803242>
+ // A flag indicating that the module has no instances of a @synthesize of a
+ // superclass variable. <rdar://problem/6803242>
eImageInfo_CorrectedSynthesize = (1 << 4)
};
-void CGObjCMac::EmitImageInfo() {
+void CGObjCCommonMac::EmitImageInfo() {
unsigned version = 0; // Version is unused?
unsigned flags = 0;
@@ -3132,19 +3183,10 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
FieldDecl *Field = RecFields[i];
uint64_t FieldOffset;
if (RD) {
- const CGRecordLayout &RL =
- CGM.getTypes().getCGRecordLayout(Field->getParent());
- if (Field->isBitField()) {
- const CGBitFieldInfo &Info = RL.getBitFieldInfo(Field);
-
- const llvm::Type *Ty =
- CGM.getTypes().ConvertTypeForMemRecursive(Field->getType());
- uint64_t TypeSize =
- CGM.getTypes().getTargetData().getTypeAllocSize(Ty);
- FieldOffset = Info.FieldNo * TypeSize;
- } else
- FieldOffset =
- Layout->getElementOffset(RL.getLLVMFieldNo(Field));
+ // Note that 'i' here is actually the field index inside RD of Field,
+ // although this dependency is hidden.
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+ FieldOffset = RL.getFieldOffset(i) / 8;
} else
FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field));
@@ -3536,7 +3578,7 @@ void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D,
<< '[' << CD->getName();
if (const ObjCCategoryImplDecl *CID =
dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext()))
- OS << '(' << CID->getNameAsString() << ')';
+ OS << '(' << CID << ')';
OS << ' ' << D->getSelector().getAsString() << ']';
}
@@ -3574,14 +3616,14 @@ void CGObjCMac::FinishModule() {
Asm += '\n';
llvm::raw_svector_ostream OS(Asm);
- for (llvm::SetVector<IdentifierInfo*>::iterator I = LazySymbols.begin(),
- e = LazySymbols.end(); I != e; ++I)
- OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n";
for (llvm::SetVector<IdentifierInfo*>::iterator I = DefinedSymbols.begin(),
e = DefinedSymbols.end(); I != e; ++I)
OS << "\t.objc_class_name_" << (*I)->getName() << "=0\n"
<< "\t.globl .objc_class_name_" << (*I)->getName() << "\n";
-
+ for (llvm::SetVector<IdentifierInfo*>::iterator I = LazySymbols.begin(),
+ e = LazySymbols.end(); I != e; ++I)
+ OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n";
+
CGM.getModule().setModuleInlineAsm(OS.str());
}
}
@@ -3627,7 +3669,8 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// id self;
// Class cls;
// }
- RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0,
+ RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct,
+ Ctx.getTranslationUnitDecl(),
SourceLocation(),
&Ctx.Idents.get("_objc_super"));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
@@ -4088,7 +4131,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// };
// First the clang type for struct _message_ref_t
- RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0,
+ RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct,
+ Ctx.getTranslationUnitDecl(),
SourceLocation(),
&Ctx.Idents.get("_message_ref_t"));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
@@ -4162,7 +4206,7 @@ void CGObjCNonFragileABIMac::AddModuleClassList(const
llvm::GlobalValue::InternalLinkage,
Init,
SymbolName);
- GV->setAlignment(8);
+ GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType()));
GV->setSection(SectionName);
CGM.AddUsedGlobal(GV);
}
@@ -4203,28 +4247,7 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
"\01L_OBJC_LABEL_NONLAZY_CATEGORY_$",
"__DATA, __objc_nlcatlist, regular, no_dead_strip");
- // static int L_OBJC_IMAGE_INFO[2] = { 0, flags };
- // FIXME. flags can be 0 | 1 | 2 | 6. For now just use 0
- std::vector<llvm::Constant*> Values(2);
- Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, 0);
- unsigned int flags = 0;
- // FIXME: Fix and continue?
- if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC)
- flags |= eImageInfo_GarbageCollected;
- if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly)
- flags |= eImageInfo_GCOnly;
- Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags);
- llvm::Constant* Init = llvm::ConstantArray::get(
- llvm::ArrayType::get(ObjCTypes.IntTy, 2),
- Values);
- llvm::GlobalVariable *IMGV =
- new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
- llvm::GlobalValue::InternalLinkage,
- Init,
- "\01L_OBJC_IMAGE_INFO");
- IMGV->setSection("__DATA, __objc_imageinfo, regular, no_dead_strip");
- IMGV->setConstant(true);
- CGM.AddUsedGlobal(IMGV);
+ EmitImageInfo();
}
/// LegacyDispatchedSelector - Returns true if SEL is not in the list of
@@ -4233,9 +4256,19 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
/// message dispatch call for all the rest.
///
bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) {
- if (CGM.getCodeGenOpts().ObjCLegacyDispatch)
+ switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) {
+ default:
+ assert(0 && "Invalid dispatch method!");
+ case CodeGenOptions::Legacy:
return true;
+ case CodeGenOptions::NonLegacy:
+ return false;
+ case CodeGenOptions::Mixed:
+ break;
+ }
+ // If so, see whether this selector is in the white-list of things which must
+ // use the new dispatch convention. We lazily build a dense set for this.
if (NonLegacyDispatchMethods.empty()) {
NonLegacyDispatchMethods.insert(GetNullarySelector("alloc"));
NonLegacyDispatchMethods.insert(GetNullarySelector("class"));
@@ -4265,6 +4298,7 @@ bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) {
NonLegacyDispatchMethods.insert(
CGM.getContext().Selectors.getSelector(3, KeyIdents));
}
+
return (NonLegacyDispatchMethods.count(Sel) == 0);
}
@@ -4369,7 +4403,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName :
std::string("\01l_OBJC_CLASS_RO_$_")+ClassName);
CLASS_RO_GV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ClassRonfABITy));
+ CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassRonfABITy));
CLASS_RO_GV->setSection("__DATA, __objc_const");
return CLASS_RO_GV;
@@ -4405,7 +4439,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData(
GV->setInitializer(Init);
GV->setSection("__DATA, __objc_data");
GV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ClassnfABITy));
+ CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassnfABITy));
if (HiddenVisibility)
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
return GV;
@@ -4467,6 +4501,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden;
if (classIsHidden)
flags |= OBJC2_CLS_HIDDEN;
+ if (ID->getNumIvarInitializers())
+ flags |= eClassFlags_ABI2_HasCXXStructors;
if (!ID->getClassInterface()->getSuperClass()) {
// class is root
flags |= CLS_ROOT;
@@ -4501,6 +4537,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
flags = CLS;
if (classIsHidden)
flags |= OBJC2_CLS_HIDDEN;
+ if (ID->getNumIvarInitializers())
+ flags |= eClassFlags_ABI2_HasCXXStructors;
if (hasObjCExceptionAttribute(CGM.getContext(), ID->getClassInterface()))
flags |= CLS_EXCEPTION;
@@ -4655,7 +4693,7 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
Init,
ExtCatName);
GCATV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.CategorynfABITy));
+ CGM.getTargetData().getABITypeAlignment(ObjCTypes.CategorynfABITy));
GCATV->setSection("__DATA, __objc_const");
CGM.AddUsedGlobal(GCATV);
DefinedCategories.push_back(GCATV);
@@ -4715,7 +4753,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(llvm::Twine Name,
Init,
Name);
GV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(Init->getType()));
+ CGM.getTargetData().getABITypeAlignment(Init->getType()));
GV->setSection(Section);
CGM.AddUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV,
@@ -4750,7 +4788,7 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy,
Offset));
IvarOffsetGV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.LongTy));
+ CGM.getTargetData().getABITypeAlignment(ObjCTypes.LongTy));
// FIXME: This matches gcc, but shouldn't the visibility be set on the use as
// well (i.e., in ObjCIvarOffsetVariable).
@@ -4837,7 +4875,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
Init,
Prefix + OID->getName());
GV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(Init->getType()));
+ CGM.getTargetData().getABITypeAlignment(Init->getType()));
GV->setSection("__DATA, __objc_const");
CGM.AddUsedGlobal(GV);
@@ -4956,7 +4994,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
false, llvm::GlobalValue::WeakAnyLinkage, Init,
"\01l_OBJC_PROTOCOL_$_" + PD->getName());
Entry->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABITy));
+ CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABITy));
Entry->setSection("__DATA,__datacoal_nt,coalesced");
}
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
@@ -4969,7 +5007,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
false, llvm::GlobalValue::WeakAnyLinkage, Entry,
"\01l_OBJC_LABEL_PROTOCOL_$_" + PD->getName());
PTGV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
+ CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.AddUsedGlobal(PTGV);
@@ -5025,7 +5063,7 @@ CGObjCNonFragileABIMac::EmitProtocolList(llvm::Twine Name,
Name);
GV->setSection("__DATA, __objc_const");
GV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(Init->getType()));
+ CGM.getTargetData().getABITypeAlignment(Init->getType()));
CGM.AddUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV,
ObjCTypes.ProtocolListnfABIPtrTy);
@@ -5184,8 +5222,8 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
- bool IsClassMessage,
const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
return LegacyDispatchedSelector(Sel)
? EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel),
@@ -5222,7 +5260,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
ClassGV,
"\01L_OBJC_CLASSLIST_REFERENCES_$_");
Entry->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(
+ CGM.getTargetData().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
@@ -5245,7 +5283,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
ClassGV,
"\01L_OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(
+ CGM.getTargetData().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
@@ -5271,7 +5309,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
MetaClassGV,
"\01L_OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(
+ CGM.getTargetData().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
@@ -5532,45 +5570,44 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
SelectorArgs.push_back(ObjCTypes.getEHPersonalityPtr());
// Construct the lists of (type, catch body) to handle.
- llvm::SmallVector<std::pair<const ParmVarDecl*, const Stmt*>, 8> Handlers;
+ llvm::SmallVector<std::pair<const VarDecl*, const Stmt*>, 8> Handlers;
bool HasCatchAll = false;
if (isTry) {
- if (const ObjCAtCatchStmt* CatchStmt =
- cast<ObjCAtTryStmt>(S).getCatchStmts()) {
- for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
- const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
- Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody()));
-
- // catch(...) always matches.
- if (!CatchDecl) {
- // Use i8* null here to signal this is a catch all, not a cleanup.
- llvm::Value *Null = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
- SelectorArgs.push_back(Null);
- HasCatchAll = true;
- break;
- }
+ const ObjCAtTryStmt &AtTry = cast<ObjCAtTryStmt>(S);
+ for (unsigned I = 0, N = AtTry.getNumCatchStmts(); I != N; ++I) {
+ const ObjCAtCatchStmt *CatchStmt = AtTry.getCatchStmt(I);
+ const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
+ Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody()));
- if (CatchDecl->getType()->isObjCIdType() ||
- CatchDecl->getType()->isObjCQualifiedIdType()) {
- llvm::Value *IDEHType =
- CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
- if (!IDEHType)
- IDEHType =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy,
- false,
- llvm::GlobalValue::ExternalLinkage,
- 0, "OBJC_EHTYPE_id");
- SelectorArgs.push_back(IDEHType);
- } else {
- // All other types should be Objective-C interface pointer types.
- const ObjCObjectPointerType *PT =
- CatchDecl->getType()->getAs<ObjCObjectPointerType>();
- assert(PT && "Invalid @catch type.");
- const ObjCInterfaceType *IT = PT->getInterfaceType();
- assert(IT && "Invalid @catch type.");
- llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false);
- SelectorArgs.push_back(EHType);
- }
+ // catch(...) always matches.
+ if (!CatchDecl) {
+ // Use i8* null here to signal this is a catch all, not a cleanup.
+ llvm::Value *Null = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
+ SelectorArgs.push_back(Null);
+ HasCatchAll = true;
+ break;
+ }
+
+ if (CatchDecl->getType()->isObjCIdType() ||
+ CatchDecl->getType()->isObjCQualifiedIdType()) {
+ llvm::Value *IDEHType =
+ CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
+ if (!IDEHType)
+ IDEHType =
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy,
+ false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0, "OBJC_EHTYPE_id");
+ SelectorArgs.push_back(IDEHType);
+ } else {
+ // All other types should be Objective-C interface pointer types.
+ const ObjCObjectPointerType *PT =
+ CatchDecl->getType()->getAs<ObjCObjectPointerType>();
+ assert(PT && "Invalid @catch type.");
+ const ObjCInterfaceType *IT = PT->getInterfaceType();
+ assert(IT && "Invalid @catch type.");
+ llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false);
+ SelectorArgs.push_back(EHType);
}
}
}
@@ -5589,7 +5626,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
SelectorArgs.begin(), SelectorArgs.end(),
"selector");
for (unsigned i = 0, e = Handlers.size(); i != e; ++i) {
- const ParmVarDecl *CatchParam = Handlers[i].first;
+ const VarDecl *CatchParam = Handlers[i].first;
const Stmt *CatchBody = Handlers[i].second;
llvm::BasicBlock *Next = 0;
@@ -5612,14 +5649,9 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
if (CatchBody) {
llvm::BasicBlock *MatchEnd = CGF.createBasicBlock("match.end");
- llvm::BasicBlock *MatchHandler = CGF.createBasicBlock("match.handler");
// Cleanups must call objc_end_catch.
- //
- // FIXME: It seems incorrect for objc_begin_catch to be inside this
- // context, but this matches gcc.
CGF.PushCleanupBlock(MatchEnd);
- CGF.setInvokeDest(MatchHandler);
llvm::Value *ExcObject =
CGF.Builder.CreateCall(ObjCTypes.getObjCBeginCatchFn(), Exc);
@@ -5636,25 +5668,37 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.Builder.CreateStore(ExcObject, CGF.GetAddrOfLocalVar(CatchParam));
}
+ // Exceptions inside the catch block must be rethrown. We set a special
+ // purpose invoke destination for this which just collects the thrown
+ // exception and overwrites the object in RethrowPtr, branches through the
+ // match.end to make sure we call objc_end_catch, before branching to the
+ // rethrow handler.
+ llvm::BasicBlock *MatchHandler = CGF.createBasicBlock("match.handler");
+ CGF.setInvokeDest(MatchHandler);
CGF.ObjCEHValueStack.push_back(ExcObject);
CGF.EmitStmt(CatchBody);
CGF.ObjCEHValueStack.pop_back();
+ CGF.setInvokeDest(0);
CGF.EmitBranchThroughCleanup(FinallyEnd);
- CGF.EmitBlock(MatchHandler);
-
- llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
- // We are required to emit this call to satisfy LLVM, even
- // though we don't use the result.
- llvm::SmallVector<llvm::Value*, 8> Args;
- Args.push_back(Exc);
- Args.push_back(ObjCTypes.getEHPersonalityPtr());
- Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- 0));
- CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
- CGF.Builder.CreateStore(Exc, RethrowPtr);
- CGF.EmitBranchThroughCleanup(FinallyRethrow);
+ // Don't emit the extra match handler if there we no unprotected calls in
+ // the catch block.
+ if (MatchHandler->use_empty()) {
+ delete MatchHandler;
+ } else {
+ CGF.EmitBlock(MatchHandler);
+ llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
+ // We are required to emit this call to satisfy LLVM, even
+ // though we don't use the result.
+ CGF.Builder.CreateCall3(llvm_eh_selector,
+ Exc, ObjCTypes.getEHPersonalityPtr(),
+ llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), 0),
+ "unused_eh_selector");
+ CGF.Builder.CreateStore(Exc, RethrowPtr);
+ CGF.EmitBranchThroughCleanup(FinallyRethrow);
+ }
CodeGenFunction::CleanupBlockInfo Info = CGF.PopCleanupBlock();
@@ -5666,8 +5710,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.createBasicBlock("match.end.handler");
llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
CGF.Builder.CreateInvoke(ObjCTypes.getObjCEndCatchFn(),
- Cont, MatchEndHandler,
- Args.begin(), Args.begin());
+ Cont, MatchEndHandler);
CGF.EmitBlock(Cont);
if (Info.SwitchBlock)
@@ -5676,15 +5719,14 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.EmitBlock(Info.EndBlock);
CGF.EmitBlock(MatchEndHandler);
- Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
+ llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
// We are required to emit this call to satisfy LLVM, even
// though we don't use the result.
- Args.clear();
- Args.push_back(Exc);
- Args.push_back(ObjCTypes.getEHPersonalityPtr());
- Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- 0));
- CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
+ CGF.Builder.CreateCall3(llvm_eh_selector,
+ Exc, ObjCTypes.getEHPersonalityPtr(),
+ llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), 0),
+ "unused_eh_selector");
CGF.Builder.CreateStore(Exc, RethrowPtr);
CGF.EmitBranchThroughCleanup(FinallyRethrow);
@@ -5723,9 +5765,19 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Branch around the rethrow code.
CGF.EmitBranch(FinallyEnd);
+ // Generate the rethrow code, taking care to use an invoke if we are in a
+ // nested exception scope.
CGF.EmitBlock(FinallyRethrow);
- CGF.Builder.CreateCall(ObjCTypes.getUnwindResumeOrRethrowFn(),
- CGF.Builder.CreateLoad(RethrowPtr));
+ if (PrevLandingPad) {
+ llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
+ CGF.Builder.CreateInvoke(ObjCTypes.getUnwindResumeOrRethrowFn(),
+ Cont, PrevLandingPad,
+ CGF.Builder.CreateLoad(RethrowPtr));
+ CGF.EmitBlock(Cont);
+ } else {
+ CGF.Builder.CreateCall(ObjCTypes.getUnwindResumeOrRethrowFn(),
+ CGF.Builder.CreateLoad(RethrowPtr));
+ }
CGF.Builder.CreateUnreachable();
CGF.EmitBlock(FinallyEnd);
@@ -5816,7 +5868,8 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
if (CGM.getLangOptions().getVisibilityMode() == LangOptions::Hidden)
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
- Entry->setAlignment(8);
+ Entry->setAlignment(CGM.getTargetData().getABITypeAlignment(
+ ObjCTypes.EHTypeTy));
if (ForDefinition) {
Entry->setSection("__DATA,__objc_const");
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index e478394..654ad0a 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -122,8 +122,8 @@ public:
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
- bool IsClassMessage,
const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class = 0,
const ObjCMethodDecl *Method = 0) = 0;
/// Generate an Objective-C message send operation to the super
@@ -167,6 +167,9 @@ public:
/// Return the runtime function for setting properties.
virtual llvm::Constant *GetPropertySetFunction() = 0;
+ // API for atomic copying of qualified aggregates in setter/getter.
+ virtual llvm::Constant *GetCopyStructFunction() = 0;
+
/// GetClass - Return a reference to the class for the given
/// interface decl.
virtual llvm::Value *GetClass(CGBuilderTy &Builder,
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 1caec97..aec1c45 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -31,8 +31,8 @@ class RTTIBuilder {
/// descriptor of the given type.
llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty);
- /// BuildVtablePointer - Build the vtable pointer for the given type.
- void BuildVtablePointer(const Type *Ty);
+ /// BuildVTablePointer - Build the vtable pointer for the given type.
+ void BuildVTablePointer(const Type *Ty);
/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
/// inheritance, according to the Itanium C++ ABI, 2.9.5p6b.
@@ -148,6 +148,9 @@ public:
};
/// BuildTypeInfo - Build the RTTI type info struct for the given type.
+ ///
+ /// \param Force - true to force the creation of this RTTI value
+ /// \param ForEH - true if this is for exception handling
llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false);
};
}
@@ -242,9 +245,10 @@ static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) {
}
/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
-/// the given type exists somewhere else, and that we should not emit the typ
+/// the given type exists somewhere else, and that we should not emit the type
/// information in this translation unit.
-bool ShouldUseExternalRTTIDescriptor(QualType Ty) {
+static bool ShouldUseExternalRTTIDescriptor(ASTContext &Context,
+ QualType Ty) {
// Type info for builtin types is defined in the standard library.
if (const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Ty))
return TypeInfoIsInStandardLibrary(BuiltinTy);
@@ -254,6 +258,9 @@ bool ShouldUseExternalRTTIDescriptor(QualType Ty) {
if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
return TypeInfoIsInStandardLibrary(PointerTy);
+ // If RTTI is disabled, don't consider key functions.
+ if (!Context.getLangOptions().RTTI) return false;
+
if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
if (!RD->hasDefinition())
@@ -337,7 +344,7 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(QualType Ty) {
if (const RecordType *Record = dyn_cast<RecordType>(Ty)) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
if (RD->isDynamicClass())
- return CodeGenModule::getVtableLinkage(RD);
+ return CodeGenModule::getVTableLinkage(RD);
}
return llvm::GlobalValue::WeakODRLinkage;
@@ -375,8 +382,8 @@ static bool CanUseSingleInheritance(const CXXRecordDecl *RD) {
return true;
}
-void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
- const char *VtableName;
+void RTTIBuilder::BuildVTablePointer(const Type *Ty) {
+ const char *VTableName;
switch (Ty->getTypeClass()) {
default: assert(0 && "Unhandled type!");
@@ -386,24 +393,24 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
case Type::Vector:
case Type::ExtVector:
// abi::__fundamental_type_info.
- VtableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE";
break;
case Type::ConstantArray:
case Type::IncompleteArray:
// abi::__array_type_info.
- VtableName = "_ZTVN10__cxxabiv117__array_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv117__array_type_infoE";
break;
case Type::FunctionNoProto:
case Type::FunctionProto:
// abi::__function_type_info.
- VtableName = "_ZTVN10__cxxabiv120__function_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv120__function_type_infoE";
break;
case Type::Enum:
// abi::__enum_type_info.
- VtableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
break;
case Type::Record: {
@@ -412,13 +419,13 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
if (!RD->hasDefinition() || !RD->getNumBases()) {
// abi::__class_type_info.
- VtableName = "_ZTVN10__cxxabiv117__class_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv117__class_type_infoE";
} else if (CanUseSingleInheritance(RD)) {
// abi::__si_class_type_info.
- VtableName = "_ZTVN10__cxxabiv120__si_class_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv120__si_class_type_infoE";
} else {
// abi::__vmi_class_type_info.
- VtableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
}
break;
@@ -426,30 +433,31 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
case Type::Pointer:
// abi::__pointer_type_info.
- VtableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
break;
case Type::MemberPointer:
// abi::__pointer_to_member_type_info.
- VtableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
break;
}
- llvm::Constant *Vtable =
- CGM.getModule().getOrInsertGlobal(VtableName, Int8PtrTy);
+ llvm::Constant *VTable =
+ CGM.getModule().getOrInsertGlobal(VTableName, Int8PtrTy);
const llvm::Type *PtrDiffTy =
CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
// The vtable address point is 2.
llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2);
- Vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, &Two, 1);
- Vtable = llvm::ConstantExpr::getBitCast(Vtable, Int8PtrTy);
+ VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, &Two, 1);
+ VTable = llvm::ConstantExpr::getBitCast(VTable, Int8PtrTy);
- Fields.push_back(Vtable);
+ Fields.push_back(VTable);
}
-llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
+llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty,
+ bool Force) {
// We want to operate on the canonical type.
Ty = CGM.getContext().getCanonicalType(Ty);
@@ -463,13 +471,13 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy);
// Check if there is already an external RTTI descriptor for this type.
- if (!Force && ShouldUseExternalRTTIDescriptor(Ty))
+ if (!Force && ShouldUseExternalRTTIDescriptor(CGM.getContext(), Ty))
return GetAddrOfExternalRTTIDescriptor(Ty);
llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(Ty);
// Add the vtable pointer.
- BuildVtablePointer(cast<Type>(Ty));
+ BuildVTablePointer(cast<Type>(Ty));
// And the name.
Fields.push_back(BuildName(Ty, DecideHidden(Ty), Linkage));
@@ -782,42 +790,17 @@ void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {
Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(QualType(ClassType, 0)));
}
-llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty) {
- if (!getContext().getLangOptions().RTTI) {
+llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
+ bool ForEH) {
+ // Return a bogus pointer if RTTI is disabled, unless it's for EH.
+ // FIXME: should we even be calling this method if RTTI is disabled
+ // and it's not for EH?
+ if (!ForEH && !getContext().getLangOptions().RTTI) {
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
return llvm::Constant::getNullValue(Int8PtrTy);
}
-
- return RTTIBuilder(*this).BuildTypeInfo(Ty);
-}
-// Try to find the magic class __cxxabiv1::__fundamental_type_info. If
-// exists and has a destructor, we will emit the typeinfo for the fundamental
-// types. This is the same behaviour as GCC.
-static CXXRecordDecl *FindMagicClass(ASTContext &AC) {
- const IdentifierInfo &NamespaceII = AC.Idents.get("__cxxabiv1");
- DeclarationName NamespaceDN = AC.DeclarationNames.getIdentifier(&NamespaceII);
- TranslationUnitDecl *TUD = AC.getTranslationUnitDecl();
- DeclContext::lookup_result NamespaceLookup = TUD->lookup(NamespaceDN);
- if (NamespaceLookup.first == NamespaceLookup.second)
- return NULL;
- const NamespaceDecl *Namespace =
- dyn_cast<NamespaceDecl>(*NamespaceLookup.first);
- if (!Namespace)
- return NULL;
-
- const IdentifierInfo &ClassII = AC.Idents.get("__fundamental_type_info");
- DeclarationName ClassDN = AC.DeclarationNames.getIdentifier(&ClassII);
- DeclContext::lookup_const_result ClassLookup = Namespace->lookup(ClassDN);
- if (ClassLookup.first == ClassLookup.second)
- return NULL;
- CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(*ClassLookup.first);
-
- if (Class->hasDefinition() && Class->isDynamicClass() &&
- Class->getDestructor(AC))
- return Class;
-
- return NULL;
+ return RTTIBuilder(*this).BuildTypeInfo(Ty);
}
void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) {
@@ -829,12 +812,6 @@ void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) {
}
void CodeGenModule::EmitFundamentalRTTIDescriptors() {
- CXXRecordDecl *RD = FindMagicClass(getContext());
- if (!RD)
- return;
-
- getVTables().GenerateClassData(getVtableLinkage(RD), RD);
-
QualType FundamentalTypes[] = { Context.VoidTy, Context.Char32Ty,
Context.Char16Ty, Context.UnsignedLongLongTy,
Context.LongLongTy, Context.WCharTy,
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h
index fd1775e..9f966fb 100644
--- a/lib/CodeGen/CGRecordLayout.h
+++ b/lib/CodeGen/CGRecordLayout.h
@@ -13,22 +13,137 @@
#include "llvm/ADT/DenseMap.h"
#include "clang/AST/Decl.h"
namespace llvm {
+ class raw_ostream;
class Type;
}
namespace clang {
namespace CodeGen {
+/// \brief Helper object for describing how to generate the code for access to a
+/// bit-field.
+///
+/// This structure is intended to describe the "policy" of how the bit-field
+/// should be accessed, which may be target, language, or ABI dependent.
class CGBitFieldInfo {
public:
- CGBitFieldInfo(unsigned FieldNo, unsigned Start, unsigned Size,
- bool IsSigned)
- : FieldNo(FieldNo), Start(Start), Size(Size), IsSigned(IsSigned) {}
+ /// Descriptor for a single component of a bit-field access. The entire
+ /// bit-field is constituted of a bitwise OR of all of the individual
+ /// components.
+ ///
+ /// Each component describes an accessed value, which is how the component
+ /// should be transferred to/from memory, and a target placement, which is how
+ /// that component fits into the constituted bit-field. The pseudo-IR for a
+ /// load is:
+ ///
+ /// %0 = gep %base, 0, FieldIndex
+ /// %1 = gep (i8*) %0, FieldByteOffset
+ /// %2 = (i(AccessWidth) *) %1
+ /// %3 = load %2, align AccessAlignment
+ /// %4 = shr %3, FieldBitStart
+ ///
+ /// and the composed bit-field is formed as the boolean OR of all accesses,
+ /// masked to TargetBitWidth bits and shifted to TargetBitOffset.
+ struct AccessInfo {
+ /// Offset of the field to load in the LLVM structure, if any.
+ unsigned FieldIndex;
+
+ /// Byte offset from the field address, if any. This should generally be
+ /// unused as the cleanest IR comes from having a well-constructed LLVM type
+ /// with proper GEP instructions, but sometimes its use is required, for
+ /// example if an access is intended to straddle an LLVM field boundary.
+ unsigned FieldByteOffset;
+
+ /// Bit offset in the accessed value to use. The width is implied by \see
+ /// TargetBitWidth.
+ unsigned FieldBitStart;
+
+ /// Bit width of the memory access to perform.
+ unsigned AccessWidth;
+
+ /// The alignment of the memory access, or 0 if the default alignment should
+ /// be used.
+ //
+ // FIXME: Remove use of 0 to encode default, instead have IRgen do the right
+ // thing when it generates the code, if avoiding align directives is
+ // desired.
+ unsigned AccessAlignment;
+
+ /// Offset for the target value.
+ unsigned TargetBitOffset;
+
+ /// Number of bits in the access that are destined for the bit-field.
+ unsigned TargetBitWidth;
+ };
- unsigned FieldNo;
- unsigned Start;
+private:
+ /// The components to use to access the bit-field. We may need up to three
+ /// separate components to support up to i64 bit-field access (4 + 2 + 1 byte
+ /// accesses).
+ //
+ // FIXME: De-hardcode this, just allocate following the struct.
+ AccessInfo Components[3];
+
+ /// The total size of the bit-field, in bits.
unsigned Size;
+
+ /// The number of access components to use.
+ unsigned NumComponents;
+
+ /// Whether the bit-field is signed.
bool IsSigned : 1;
+
+public:
+ CGBitFieldInfo(unsigned Size, unsigned NumComponents, AccessInfo *_Components,
+ bool IsSigned) : Size(Size), NumComponents(NumComponents),
+ IsSigned(IsSigned) {
+ assert(NumComponents <= 3 && "invalid number of components!");
+ for (unsigned i = 0; i != NumComponents; ++i)
+ Components[i] = _Components[i];
+
+ // Check some invariants.
+ unsigned AccessedSize = 0;
+ for (unsigned i = 0, e = getNumComponents(); i != e; ++i) {
+ const AccessInfo &AI = getComponent(i);
+ AccessedSize += AI.TargetBitWidth;
+
+ // We shouldn't try to load 0 bits.
+ assert(AI.TargetBitWidth > 0);
+
+ // We can't load more bits than we accessed.
+ assert(AI.FieldBitStart + AI.TargetBitWidth <= AI.AccessWidth);
+
+ // We shouldn't put any bits outside the result size.
+ assert(AI.TargetBitWidth + AI.TargetBitOffset <= Size);
+ }
+
+ // Check that the total number of target bits matches the total bit-field
+ // size.
+ assert(AccessedSize == Size && "Total size does not match accessed size!");
+ }
+
+public:
+ /// \brief Check whether this bit-field access is (i.e., should be sign
+ /// extended on loads).
+ bool isSigned() const { return IsSigned; }
+
+ /// \brief Get the size of the bit-field, in bits.
+ unsigned getSize() const { return Size; }
+
+ /// @name Component Access
+ /// @{
+
+ unsigned getNumComponents() const { return NumComponents; }
+
+ const AccessInfo &getComponent(unsigned Index) const {
+ assert(Index < getNumComponents() && "Invalid access!");
+ return Components[Index];
+ }
+
+ /// @}
+
+ void print(llvm::raw_ostream &OS) const;
+ void dump() const;
};
/// CGRecordLayout - This class handles struct and union layout info while
@@ -71,15 +186,15 @@ public:
return ContainsPointerToDataMember;
}
- /// \brief Return the BitFieldInfo that corresponds to the field FD.
+ /// \brief Return llvm::StructType element number that corresponds to the
+ /// field FD.
unsigned getLLVMFieldNo(const FieldDecl *FD) const {
assert(!FD->isBitField() && "Invalid call for bit-field decl!");
assert(FieldInfo.count(FD) && "Invalid field for record!");
return FieldInfo.lookup(FD);
}
- /// \brief Return llvm::StructType element number that corresponds to the
- /// field FD.
+ /// \brief Return the BitFieldInfo that corresponds to the field FD.
const CGBitFieldInfo &getBitFieldInfo(const FieldDecl *FD) const {
assert(FD->isBitField() && "Invalid call for non bit-field decl!");
llvm::DenseMap<const FieldDecl *, CGBitFieldInfo>::const_iterator
@@ -87,6 +202,9 @@ public:
assert(it != BitFields.end() && "Unable to find bitfield info");
return it->second;
}
+
+ void print(llvm::raw_ostream &OS) const;
+ void dump() const;
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 4b9ec66..6302cf8 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -18,8 +18,10 @@
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "CodeGenTypes.h"
-#include "llvm/Type.h"
#include "llvm/DerivedTypes.h"
+#include "llvm/Type.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetData.h"
using namespace clang;
using namespace CodeGen;
@@ -67,6 +69,11 @@ private:
/// NextFieldOffsetInBytes - Holds the next field offset in bytes.
uint64_t NextFieldOffsetInBytes;
+ /// LayoutUnionField - Will layout a field in an union and return the type
+ /// that the field will have.
+ const llvm::Type *LayoutUnionField(const FieldDecl *Field,
+ const ASTRecordLayout &Layout);
+
/// LayoutUnion - Will layout a union RecordDecl.
void LayoutUnion(const RecordDecl *D);
@@ -87,10 +94,6 @@ private:
/// AppendField - Appends a field with the given offset and type.
void AppendField(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy);
- /// AppendPadding - Appends enough padding bytes so that the total struct
- /// size matches the alignment of the passed in type.
- void AppendPadding(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy);
-
/// AppendPadding - Appends enough padding bytes so that the total
/// struct size is a multiple of the field alignment.
void AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment);
@@ -103,7 +106,6 @@ private:
void AppendTailPadding(uint64_t RecordSize);
unsigned getTypeAlignment(const llvm::Type *Ty) const;
- uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const;
/// CheckForPointerToDataMember - Check if the given type contains a pointer
/// to data member.
@@ -145,6 +147,104 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
LayoutFields(D);
}
+static CGBitFieldInfo ComputeBitFieldInfo(CodeGenTypes &Types,
+ const FieldDecl *FD,
+ uint64_t FieldOffset,
+ uint64_t FieldSize) {
+ const RecordDecl *RD = FD->getParent();
+ const ASTRecordLayout &RL = Types.getContext().getASTRecordLayout(RD);
+ uint64_t ContainingTypeSizeInBits = RL.getSize();
+ unsigned ContainingTypeAlign = RL.getAlignment();
+
+ const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(FD->getType());
+ uint64_t TypeSizeInBytes = Types.getTargetData().getTypeAllocSize(Ty);
+ uint64_t TypeSizeInBits = TypeSizeInBytes * 8;
+
+ bool IsSigned = FD->getType()->isSignedIntegerType();
+
+ if (FieldSize > TypeSizeInBits) {
+ // We have a wide bit-field. The extra bits are only used for padding, so
+ // if we have a bitfield of type T, with size N:
+ //
+ // T t : N;
+ //
+ // We can just assume that it's:
+ //
+ // T t : sizeof(T);
+ //
+ FieldSize = TypeSizeInBits;
+ }
+
+ // Compute the access components. The policy we use is to start by attempting
+ // to access using the width of the bit-field type itself and to always access
+ // at aligned indices of that type. If such an access would fail because it
+ // extends past the bound of the type, then we reduce size to the next smaller
+ // power of two and retry. The current algorithm assumes pow2 sized types,
+ // although this is easy to fix.
+ //
+ // FIXME: This algorithm is wrong on big-endian systems, I think.
+ assert(llvm::isPowerOf2_32(TypeSizeInBits) && "Unexpected type size!");
+ CGBitFieldInfo::AccessInfo Components[3];
+ unsigned NumComponents = 0;
+ unsigned AccessedTargetBits = 0; // The tumber of target bits accessed.
+ unsigned AccessWidth = TypeSizeInBits; // The current access width to attempt.
+
+ // Round down from the field offset to find the first access position that is
+ // at an aligned offset of the initial access type.
+ uint64_t AccessStart = FieldOffset - (FieldOffset % AccessWidth);
+
+ // Adjust initial access size to fit within record.
+ while (AccessWidth > 8 &&
+ AccessStart + AccessWidth > ContainingTypeSizeInBits) {
+ AccessWidth >>= 1;
+ AccessStart = FieldOffset - (FieldOffset % AccessWidth);
+ }
+
+ while (AccessedTargetBits < FieldSize) {
+ // Check that we can access using a type of this size, without reading off
+ // the end of the structure. This can occur with packed structures and
+ // -fno-bitfield-type-align, for example.
+ if (AccessStart + AccessWidth > ContainingTypeSizeInBits) {
+ // If so, reduce access size to the next smaller power-of-two and retry.
+ AccessWidth >>= 1;
+ assert(AccessWidth >= 8 && "Cannot access under byte size!");
+ continue;
+ }
+
+ // Otherwise, add an access component.
+
+ // First, compute the bits inside this access which are part of the
+ // target. We are reading bits [AccessStart, AccessStart + AccessWidth); the
+ // intersection with [FieldOffset, FieldOffset + FieldSize) gives the bits
+ // in the target that we are reading.
+ assert(FieldOffset < AccessStart + AccessWidth && "Invalid access start!");
+ assert(AccessStart < FieldOffset + FieldSize && "Invalid access start!");
+ uint64_t AccessBitsInFieldStart = std::max(AccessStart, FieldOffset);
+ uint64_t AccessBitsInFieldSize =
+ std::min(AccessWidth + AccessStart,
+ FieldOffset + FieldSize) - AccessBitsInFieldStart;
+
+ assert(NumComponents < 3 && "Unexpected number of components!");
+ CGBitFieldInfo::AccessInfo &AI = Components[NumComponents++];
+ AI.FieldIndex = 0;
+ // FIXME: We still follow the old access pattern of only using the field
+ // byte offset. We should switch this once we fix the struct layout to be
+ // pretty.
+ AI.FieldByteOffset = AccessStart / 8;
+ AI.FieldBitStart = AccessBitsInFieldStart - AccessStart;
+ AI.AccessWidth = AccessWidth;
+ AI.AccessAlignment = llvm::MinAlign(ContainingTypeAlign, AccessStart) / 8;
+ AI.TargetBitOffset = AccessedTargetBits;
+ AI.TargetBitWidth = AccessBitsInFieldSize;
+
+ AccessStart += AccessWidth;
+ AccessedTargetBits += AI.TargetBitWidth;
+ }
+
+ assert(AccessedTargetBits == FieldSize && "Invalid bit-field access!");
+ return CGBitFieldInfo(FieldSize, NumComponents, Components, IsSigned);
+}
+
void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D,
uint64_t FieldOffset) {
uint64_t FieldSize =
@@ -175,14 +275,9 @@ void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D,
assert(NumBytesToAppend && "No bytes to append!");
}
- const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType());
- uint64_t TypeSizeInBits = getTypeSizeInBytes(Ty) * 8;
-
- bool IsSigned = D->getType()->isSignedIntegerType();
- LLVMBitFields.push_back(LLVMBitFieldInfo(
- D, CGBitFieldInfo(FieldOffset / TypeSizeInBits,
- FieldOffset % TypeSizeInBits,
- FieldSize, IsSigned)));
+ // Add the bit field info.
+ LLVMBitFields.push_back(
+ LLVMBitFieldInfo(D, ComputeBitFieldInfo(Types, D, FieldOffset, FieldSize)));
AppendBytes(NumBytesToAppend);
@@ -254,6 +349,35 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
return true;
}
+const llvm::Type *
+CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
+ const ASTRecordLayout &Layout) {
+ if (Field->isBitField()) {
+ uint64_t FieldSize =
+ Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue();
+
+ // Ignore zero sized bit fields.
+ if (FieldSize == 0)
+ return 0;
+
+ const llvm::Type *FieldTy = llvm::Type::getInt8Ty(Types.getLLVMContext());
+ unsigned NumBytesToAppend =
+ llvm::RoundUpToAlignment(FieldSize, 8) / 8;
+
+ if (NumBytesToAppend > 1)
+ FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend);
+
+ // Add the bit field info.
+ LLVMBitFields.push_back(
+ LLVMBitFieldInfo(Field, ComputeBitFieldInfo(Types, Field, 0, FieldSize)));
+ return FieldTy;
+ }
+
+ // This is a regular union field.
+ LLVMFields.push_back(LLVMFieldInfo(Field, 0));
+ return Types.ConvertTypeForMemRecursive(Field->getType());
+}
+
void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
assert(D->isUnion() && "Can't call LayoutUnion on a non-union record!");
@@ -270,28 +394,13 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
assert(Layout.getFieldOffset(FieldNo) == 0 &&
"Union field offset did not start at the beginning of record!");
+ const llvm::Type *FieldTy = LayoutUnionField(*Field, Layout);
- if (Field->isBitField()) {
- uint64_t FieldSize =
- Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue();
-
- // Ignore zero sized bit fields.
- if (FieldSize == 0)
- continue;
-
- // Add the bit field info.
- bool IsSigned = Field->getType()->isSignedIntegerType();
- LLVMBitFields.push_back(LLVMBitFieldInfo(
- *Field, CGBitFieldInfo(0, 0, FieldSize,
- IsSigned)));
- } else {
- LLVMFields.push_back(LLVMFieldInfo(*Field, 0));
- }
+ if (!FieldTy)
+ continue;
HasOnlyZeroSizedBitFields = false;
- const llvm::Type *FieldTy =
- Types.ConvertTypeForMemRecursive(Field->getType());
unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy);
uint64_t FieldSize = Types.getTargetData().getTypeAllocSize(FieldTy);
@@ -334,7 +443,7 @@ void CGRecordLayoutBuilder::LayoutBases(const CXXRecordDecl *RD,
llvm::Type::getInt8PtrTy(Types.getLLVMContext());
assert(NextFieldOffsetInBytes == 0 &&
- "Vtable pointer must come first!");
+ "VTable pointer must come first!");
AppendField(NextFieldOffsetInBytes, Int8PtrTy->getPointerTo());
}
}
@@ -388,7 +497,7 @@ void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes,
AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct,
getTypeAlignment(FieldTy));
- uint64_t FieldSizeInBytes = getTypeSizeInBytes(FieldTy);
+ uint64_t FieldSizeInBytes = Types.getTargetData().getTypeAllocSize(FieldTy);
FieldTypes.push_back(FieldTy);
@@ -396,12 +505,6 @@ void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes,
BitsAvailableInLastField = 0;
}
-void
-CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes,
- const llvm::Type *FieldTy) {
- AppendPadding(FieldOffsetInBytes, getTypeAlignment(FieldTy));
-}
-
void CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes,
unsigned FieldAlignment) {
assert(NextFieldOffsetInBytes <= FieldOffsetInBytes &&
@@ -439,10 +542,6 @@ unsigned CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const {
return Types.getTargetData().getABITypeAlignment(Ty);
}
-uint64_t CGRecordLayoutBuilder::getTypeSizeInBytes(const llvm::Type *Ty) const {
- return Types.getTargetData().getTypeAllocSize(Ty);
-}
-
void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) {
// This record already contains a member pointer.
if (ContainsPointerToDataMember)
@@ -481,9 +580,6 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
const llvm::Type *Ty = llvm::StructType::get(getLLVMContext(),
Builder.FieldTypes,
Builder.Packed);
- assert(getContext().getASTRecordLayout(D).getSize() / 8 ==
- getTargetData().getTypeAllocSize(Ty) &&
- "Type size mismatch!");
CGRecordLayout *RL =
new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember);
@@ -496,5 +592,121 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i)
RL->BitFields.insert(Builder.LLVMBitFields[i]);
+ // Dump the layout, if requested.
+ if (getContext().getLangOptions().DumpRecordLayouts) {
+ llvm::errs() << "\n*** Dumping IRgen Record Layout\n";
+ llvm::errs() << "Record: ";
+ D->dump();
+ llvm::errs() << "\nLayout: ";
+ RL->dump();
+ }
+
+#ifndef NDEBUG
+ // Verify that the computed LLVM struct size matches the AST layout size.
+ uint64_t TypeSizeInBits = getContext().getASTRecordLayout(D).getSize();
+ assert(TypeSizeInBits == getTargetData().getTypeAllocSizeInBits(Ty) &&
+ "Type size mismatch!");
+
+ // Verify that the LLVM and AST field offsets agree.
+ const llvm::StructType *ST =
+ dyn_cast<llvm::StructType>(RL->getLLVMType());
+ const llvm::StructLayout *SL = getTargetData().getStructLayout(ST);
+
+ const ASTRecordLayout &AST_RL = getContext().getASTRecordLayout(D);
+ RecordDecl::field_iterator it = D->field_begin();
+ for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) {
+ const FieldDecl *FD = *it;
+
+ // For non-bit-fields, just check that the LLVM struct offset matches the
+ // AST offset.
+ if (!FD->isBitField()) {
+ unsigned FieldNo = RL->getLLVMFieldNo(FD);
+ assert(AST_RL.getFieldOffset(i) == SL->getElementOffsetInBits(FieldNo) &&
+ "Invalid field offset!");
+ continue;
+ }
+
+ // Ignore unnamed bit-fields.
+ if (!FD->getDeclName())
+ continue;
+
+ const CGBitFieldInfo &Info = RL->getBitFieldInfo(FD);
+ for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) {
+ const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i);
+
+ // Verify that every component access is within the structure.
+ uint64_t FieldOffset = SL->getElementOffsetInBits(AI.FieldIndex);
+ uint64_t AccessBitOffset = FieldOffset + AI.FieldByteOffset * 8;
+ assert(AccessBitOffset + AI.AccessWidth <= TypeSizeInBits &&
+ "Invalid bit-field access (out of range)!");
+ }
+ }
+#endif
+
return RL;
}
+
+void CGRecordLayout::print(llvm::raw_ostream &OS) const {
+ OS << "<CGRecordLayout\n";
+ OS << " LLVMType:" << *LLVMType << "\n";
+ OS << " ContainsPointerToDataMember:" << ContainsPointerToDataMember << "\n";
+ OS << " BitFields:[\n";
+
+ // Print bit-field infos in declaration order.
+ std::vector<std::pair<unsigned, const CGBitFieldInfo*> > BFIs;
+ for (llvm::DenseMap<const FieldDecl*, CGBitFieldInfo>::const_iterator
+ it = BitFields.begin(), ie = BitFields.end();
+ it != ie; ++it) {
+ const RecordDecl *RD = it->first->getParent();
+ unsigned Index = 0;
+ for (RecordDecl::field_iterator
+ it2 = RD->field_begin(); *it2 != it->first; ++it2)
+ ++Index;
+ BFIs.push_back(std::make_pair(Index, &it->second));
+ }
+ llvm::array_pod_sort(BFIs.begin(), BFIs.end());
+ for (unsigned i = 0, e = BFIs.size(); i != e; ++i) {
+ OS.indent(4);
+ BFIs[i].second->print(OS);
+ OS << "\n";
+ }
+
+ OS << "]>\n";
+}
+
+void CGRecordLayout::dump() const {
+ print(llvm::errs());
+}
+
+void CGBitFieldInfo::print(llvm::raw_ostream &OS) const {
+ OS << "<CGBitFieldInfo";
+ OS << " Size:" << Size;
+ OS << " IsSigned:" << IsSigned << "\n";
+
+ OS.indent(4 + strlen("<CGBitFieldInfo"));
+ OS << " NumComponents:" << getNumComponents();
+ OS << " Components: [";
+ if (getNumComponents()) {
+ OS << "\n";
+ for (unsigned i = 0, e = getNumComponents(); i != e; ++i) {
+ const AccessInfo &AI = getComponent(i);
+ OS.indent(8);
+ OS << "<AccessInfo"
+ << " FieldIndex:" << AI.FieldIndex
+ << " FieldByteOffset:" << AI.FieldByteOffset
+ << " FieldBitStart:" << AI.FieldBitStart
+ << " AccessWidth:" << AI.AccessWidth << "\n";
+ OS.indent(8 + strlen("<AccessInfo"));
+ OS << " AccessAlignment:" << AI.AccessAlignment
+ << " TargetBitOffset:" << AI.TargetBitOffset
+ << " TargetBitWidth:" << AI.TargetBitWidth
+ << ">\n";
+ }
+ OS.indent(4);
+ }
+ OS << "]>";
+}
+
+void CGBitFieldInfo::dump() const {
+ print(llvm::errs());
+}
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index ae2f791..a914c80d 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -160,7 +160,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
EmitStmt(*I);
if (DI) {
- DI->setLocation(S.getLBracLoc());
+ DI->setLocation(S.getRBracLoc());
DI->EmitRegionEnd(CurFn, Builder);
}
@@ -205,6 +205,8 @@ void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) {
}
void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) {
+ llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
+
// Fall out of the current block (if necessary).
EmitBranch(BB);
@@ -225,7 +227,12 @@ void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) {
}
}
- CurFn->getBasicBlockList().push_back(BB);
+ // Place the block after the current block, if possible, or else at
+ // the end of the function.
+ if (CurBB && CurBB->getParent())
+ CurFn->getBasicBlockList().insertAfter(CurBB, BB);
+ else
+ CurFn->getBasicBlockList().push_back(BB);
Builder.SetInsertPoint(BB);
}
@@ -974,19 +981,18 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
unsigned InputNo;
for (InputNo = 0; InputNo != S.getNumInputs(); ++InputNo) {
TargetInfo::ConstraintInfo &Input = InputConstraintInfos[InputNo];
- if (Input.hasTiedOperand() &&
- Input.getTiedOperand() == i)
+ if (Input.hasTiedOperand() && Input.getTiedOperand() == i)
break;
}
assert(InputNo != S.getNumInputs() && "Didn't find matching input!");
QualType InputTy = S.getInputExpr(InputNo)->getType();
- QualType OutputTy = OutExpr->getType();
+ QualType OutputType = OutExpr->getType();
uint64_t InputSize = getContext().getTypeSize(InputTy);
- if (getContext().getTypeSize(OutputTy) < InputSize) {
- // Form the asm to return the value as a larger integer type.
- ResultRegTypes.back() = llvm::IntegerType::get(VMContext, (unsigned)InputSize);
+ if (getContext().getTypeSize(OutputType) < InputSize) {
+ // Form the asm to return the value as a larger integer or fp type.
+ ResultRegTypes.back() = ConvertType(InputTy);
}
}
} else {
@@ -1036,17 +1042,20 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// that is usually cheaper, but LLVM IR should really get an anyext someday.
if (Info.hasTiedOperand()) {
unsigned Output = Info.getTiedOperand();
- QualType OutputTy = S.getOutputExpr(Output)->getType();
+ QualType OutputType = S.getOutputExpr(Output)->getType();
QualType InputTy = InputExpr->getType();
- if (getContext().getTypeSize(OutputTy) >
+ if (getContext().getTypeSize(OutputType) >
getContext().getTypeSize(InputTy)) {
// Use ptrtoint as appropriate so that we can do our extension.
if (isa<llvm::PointerType>(Arg->getType()))
Arg = Builder.CreatePtrToInt(Arg,
- llvm::IntegerType::get(VMContext, LLVMPointerWidth));
- unsigned OutputSize = (unsigned)getContext().getTypeSize(OutputTy);
- Arg = Builder.CreateZExt(Arg, llvm::IntegerType::get(VMContext, OutputSize));
+ llvm::IntegerType::get(VMContext, LLVMPointerWidth));
+ const llvm::Type *OutputTy = ConvertType(OutputType);
+ if (isa<llvm::IntegerType>(OutputTy))
+ Arg = Builder.CreateZExt(Arg, OutputTy);
+ else
+ Arg = Builder.CreateFPExt(Arg, OutputTy);
}
}
@@ -1102,6 +1111,12 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
llvm::CallInst *Result = Builder.CreateCall(IA, Args.begin(), Args.end());
Result->addAttribute(~0, llvm::Attribute::NoUnwind);
+ // Slap the source location of the inline asm into a !srcloc metadata on the
+ // call.
+ unsigned LocID = S.getAsmString()->getLocStart().getRawEncoding();
+ llvm::Value *LocIDC =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), LocID);
+ Result->setMetadata("srcloc", llvm::MDNode::get(VMContext, &LocIDC, 1));
// Extract all of the register value results from the asm.
std::vector<llvm::Value*> RegResults;
@@ -1121,14 +1136,23 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// the expression, do the conversion.
if (ResultRegTypes[i] != ResultTruncRegTypes[i]) {
const llvm::Type *TruncTy = ResultTruncRegTypes[i];
- // Truncate the integer result to the right size, note that
- // ResultTruncRegTypes can be a pointer.
- uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy);
- Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(VMContext, (unsigned)ResSize));
-
- if (Tmp->getType() != TruncTy) {
- assert(isa<llvm::PointerType>(TruncTy));
+
+ // Truncate the integer result to the right size, note that TruncTy can be
+ // a pointer.
+ if (TruncTy->isFloatingPointTy())
+ Tmp = Builder.CreateFPTrunc(Tmp, TruncTy);
+ else if (TruncTy->isPointerTy() && Tmp->getType()->isIntegerTy()) {
+ uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy);
+ Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(VMContext,
+ (unsigned)ResSize));
Tmp = Builder.CreateIntToPtr(Tmp, TruncTy);
+ } else if (Tmp->getType()->isPointerTy() && TruncTy->isIntegerTy()) {
+ uint64_t TmpSize =CGM.getTargetData().getTypeSizeInBits(Tmp->getType());
+ Tmp = Builder.CreatePtrToInt(Tmp, llvm::IntegerType::get(VMContext,
+ (unsigned)TmpSize));
+ Tmp = Builder.CreateTrunc(Tmp, TruncTy);
+ } else if (TruncTy->isIntegerTy()) {
+ Tmp = Builder.CreateTrunc(Tmp, TruncTy);
}
}
diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp
index 6d38ab9..a8f0467 100644
--- a/lib/CodeGen/CGTemporaries.cpp
+++ b/lib/CodeGen/CGTemporaries.cpp
@@ -23,7 +23,7 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
"Pushed the same temporary twice; AST is likely wrong");
llvm::BasicBlock *DtorBlock = createBasicBlock("temp.dtor");
- llvm::Value *CondPtr = 0;
+ llvm::AllocaInst *CondPtr = 0;
// Check if temporaries need to be conditional. If so, we'll create a
// condition boolean, initialize it to 0 and
@@ -32,10 +32,7 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
// Initialize it to false. This initialization takes place right after
// the alloca insert point.
- llvm::StoreInst *SI =
- new llvm::StoreInst(llvm::ConstantInt::getFalse(VMContext), CondPtr);
- llvm::BasicBlock *Block = AllocaInsertPt->getParent();
- Block->getInstList().insertAfter((llvm::Instruction *)AllocaInsertPt, SI);
+ InitTempAlloca(CondPtr, llvm::ConstantInt::getFalse(VMContext));
// Now set it to true.
Builder.CreateStore(llvm::ConstantInt::getTrue(VMContext), CondPtr);
@@ -64,7 +61,8 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
}
EmitCXXDestructorCall(Info.Temporary->getDestructor(),
- Dtor_Complete, Info.ThisPtr);
+ Dtor_Complete, /*ForVirtualBase=*/false,
+ Info.ThisPtr);
if (CondEnd) {
// Reset the condition. to false.
@@ -107,7 +105,7 @@ void CodeGenFunction::PopCXXTemporary() {
}
EmitCXXDestructorCall(Info.Temporary->getDestructor(),
- Dtor_Complete, Info.ThisPtr);
+ Dtor_Complete, /*ForVirtualBase=*/false, Info.ThisPtr);
if (CondEnd) {
// Reset the condition. to false.
diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp
index 91d9f76..15e5648 100644
--- a/lib/CodeGen/CGVTT.cpp
+++ b/lib/CodeGen/CGVTT.cpp
@@ -43,7 +43,7 @@ class VTTBuilder {
/// SubVTTIndicies - The sub-VTT indices for the bases of the most derived
/// class.
- llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies;
+ llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndicies;
/// SecondaryVirtualPointerIndices - The secondary virtual pointer indices of
/// all subobjects of the most derived class.
@@ -116,8 +116,7 @@ public:
}
/// getSubVTTIndicies - Returns a reference to the sub-VTT indices.
- const llvm::DenseMap<const CXXRecordDecl *, uint64_t> &
- getSubVTTIndicies() const {
+ const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndicies() const {
return SubVTTIndicies;
}
@@ -179,13 +178,14 @@ void VTTBuilder::AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable,
// The vtable is a construction vtable, look in the construction vtable
// address points.
AddressPoint = AddressPoints.lookup(Base);
+ assert(AddressPoint != 0 && "Did not find ctor vtable address point!");
} else {
// Just get the address point for the regular vtable.
AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass);
+ assert(AddressPoint != 0 && "Did not find vtable address point!");
}
if (!AddressPoint) AddressPoint = 0;
- assert(AddressPoint != 0 && "Did not find an address point!");
llvm::Value *Idxs[] = {
llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0),
@@ -340,7 +340,7 @@ void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) {
if (!IsPrimaryVTT) {
// Remember the sub-VTT index.
- SubVTTIndicies[RD] = VTTComponents.size();
+ SubVTTIndicies[Base] = VTTComponents.size();
}
AddressPointsMapTy AddressPoints;
@@ -434,25 +434,25 @@ bool CodeGenVTables::needsVTTParameter(GlobalDecl GD) {
}
uint64_t CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD,
- const CXXRecordDecl *Base) {
- ClassPairTy ClassPair(RD, Base);
+ BaseSubobject Base) {
+ BaseSubobjectPairTy ClassSubobjectPair(RD, Base);
- SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassPair);
+ SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassSubobjectPair);
if (I != SubVTTIndicies.end())
return I->second;
VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false);
- for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::const_iterator I =
+ for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I =
Builder.getSubVTTIndicies().begin(),
E = Builder.getSubVTTIndicies().end(); I != E; ++I) {
// Insert all indices.
- ClassPairTy ClassPair(RD, I->first);
+ BaseSubobjectPairTy ClassSubobjectPair(RD, I->first);
- SubVTTIndicies.insert(std::make_pair(ClassPair, I->second));
+ SubVTTIndicies.insert(std::make_pair(ClassSubobjectPair, I->second));
}
- I = SubVTTIndicies.find(ClassPair);
+ I = SubVTTIndicies.find(ClassSubobjectPair);
assert(I != SubVTTIndicies.end() && "Did not find index!");
return I->second;
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVTables.cpp
index fc6d1a8..159753a 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -1,4 +1,4 @@
-//===--- CGVtable.cpp - Emit LLVM Code for C++ vtables --------------------===//
+//===--- CGVTables.cpp - Emit LLVM Code for C++ vtables -------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -573,8 +573,8 @@ void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) {
}
}
-/// VtableComponent - Represents a single component in a vtable.
-class VtableComponent {
+/// VTableComponent - Represents a single component in a vtable.
+class VTableComponent {
public:
enum Kind {
CK_VCallOffset,
@@ -595,49 +595,49 @@ public:
CK_UnusedFunctionPointer
};
- static VtableComponent MakeVCallOffset(int64_t Offset) {
- return VtableComponent(CK_VCallOffset, Offset);
+ static VTableComponent MakeVCallOffset(int64_t Offset) {
+ return VTableComponent(CK_VCallOffset, Offset);
}
- static VtableComponent MakeVBaseOffset(int64_t Offset) {
- return VtableComponent(CK_VBaseOffset, Offset);
+ static VTableComponent MakeVBaseOffset(int64_t Offset) {
+ return VTableComponent(CK_VBaseOffset, Offset);
}
- static VtableComponent MakeOffsetToTop(int64_t Offset) {
- return VtableComponent(CK_OffsetToTop, Offset);
+ static VTableComponent MakeOffsetToTop(int64_t Offset) {
+ return VTableComponent(CK_OffsetToTop, Offset);
}
- static VtableComponent MakeRTTI(const CXXRecordDecl *RD) {
- return VtableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD));
+ static VTableComponent MakeRTTI(const CXXRecordDecl *RD) {
+ return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD));
}
- static VtableComponent MakeFunction(const CXXMethodDecl *MD) {
+ static VTableComponent MakeFunction(const CXXMethodDecl *MD) {
assert(!isa<CXXDestructorDecl>(MD) &&
"Don't use MakeFunction with destructors!");
- return VtableComponent(CK_FunctionPointer,
+ return VTableComponent(CK_FunctionPointer,
reinterpret_cast<uintptr_t>(MD));
}
- static VtableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) {
- return VtableComponent(CK_CompleteDtorPointer,
+ static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) {
+ return VTableComponent(CK_CompleteDtorPointer,
reinterpret_cast<uintptr_t>(DD));
}
- static VtableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) {
- return VtableComponent(CK_DeletingDtorPointer,
+ static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) {
+ return VTableComponent(CK_DeletingDtorPointer,
reinterpret_cast<uintptr_t>(DD));
}
- static VtableComponent MakeUnusedFunction(const CXXMethodDecl *MD) {
+ static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) {
assert(!isa<CXXDestructorDecl>(MD) &&
"Don't use MakeUnusedFunction with destructors!");
- return VtableComponent(CK_UnusedFunctionPointer,
+ return VTableComponent(CK_UnusedFunctionPointer,
reinterpret_cast<uintptr_t>(MD));
}
- static VtableComponent getFromOpaqueInteger(uint64_t I) {
- return VtableComponent(I);
+ static VTableComponent getFromOpaqueInteger(uint64_t I) {
+ return VTableComponent(I);
}
/// getKind - Get the kind of this vtable component.
@@ -689,7 +689,7 @@ public:
}
private:
- VtableComponent(Kind ComponentKind, int64_t Offset) {
+ VTableComponent(Kind ComponentKind, int64_t Offset) {
assert((ComponentKind == CK_VCallOffset ||
ComponentKind == CK_VBaseOffset ||
ComponentKind == CK_OffsetToTop) && "Invalid component kind!");
@@ -698,7 +698,7 @@ private:
Value = ((Offset << 3) | ComponentKind);
}
- VtableComponent(Kind ComponentKind, uintptr_t Ptr) {
+ VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
assert((ComponentKind == CK_RTTI ||
ComponentKind == CK_FunctionPointer ||
ComponentKind == CK_CompleteDtorPointer ||
@@ -729,7 +729,7 @@ private:
return static_cast<uintptr_t>(Value & ~7ULL);
}
- explicit VtableComponent(uint64_t Value)
+ explicit VTableComponent(uint64_t Value)
: Value(Value) { }
/// The kind is stored in the lower 3 bits of the value. For offsets, we
@@ -855,8 +855,8 @@ private:
ASTContext &Context;
/// Components - vcall and vbase offset components
- typedef llvm::SmallVector<VtableComponent, 64> VtableComponentVectorTy;
- VtableComponentVectorTy Components;
+ typedef llvm::SmallVector<VTableComponent, 64> VTableComponentVectorTy;
+ VTableComponentVectorTy Components;
/// VisitedVirtualBases - Visited virtual bases.
llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
@@ -902,7 +902,7 @@ public:
}
/// Methods for iterating over the components.
- typedef VtableComponentVectorTy::const_reverse_iterator const_iterator;
+ typedef VTableComponentVectorTy::const_reverse_iterator const_iterator;
const_iterator components_begin() const { return Components.rbegin(); }
const_iterator components_end() const { return Components.rend(); }
@@ -982,30 +982,17 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
// Handle the primary base first.
- if (PrimaryBase) {
- uint64_t PrimaryBaseOffset;
-
+ // We only want to add vcall offsets if the base is non-virtual; a virtual
+ // primary base will have its vcall and vbase offsets emitted already.
+ if (PrimaryBase && !Layout.getPrimaryBaseWasVirtual()) {
// Get the base offset of the primary base.
- if (Layout.getPrimaryBaseWasVirtual()) {
- assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 &&
- "Primary vbase should have a zero offset!");
-
- const ASTRecordLayout &MostDerivedClassLayout =
- Context.getASTRecordLayout(MostDerivedClass);
-
- PrimaryBaseOffset =
- MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase);
- } else {
- assert(Layout.getBaseClassOffset(PrimaryBase) == 0 &&
- "Primary base should have a zero offset!");
+ assert(Layout.getBaseClassOffset(PrimaryBase) == 0 &&
+ "Primary base should have a zero offset!");
- PrimaryBaseOffset = Base.getBaseOffset();
- }
-
- AddVCallOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset),
+ AddVCallOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()),
VBaseOffset);
}
-
+
// Add the vcall offsets.
for (CXXRecordDecl::method_iterator I = RD->method_begin(),
E = RD->method_end(); I != E; ++I) {
@@ -1034,7 +1021,7 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
Offset = (int64_t)(Overrider.Offset - VBaseOffset) / 8;
}
- Components.push_back(VtableComponent::MakeVCallOffset(Offset));
+ Components.push_back(VTableComponent::MakeVCallOffset(Offset));
}
// And iterate over all non-virtual bases (ignoring the primary base).
@@ -1082,7 +1069,7 @@ void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
int64_t VBaseOffsetOffset = getCurrentOffsetOffset();
VBaseOffsetOffsets.insert(std::make_pair(BaseDecl, VBaseOffsetOffset));
- Components.push_back(VtableComponent::MakeVBaseOffset(Offset));
+ Components.push_back(VTableComponent::MakeVBaseOffset(Offset));
}
// Check the base class looking for more vbase offsets.
@@ -1090,8 +1077,8 @@ void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
}
}
-/// VtableBuilder - Class for building vtable layout information.
-class VtableBuilder {
+/// VTableBuilder - Class for building vtable layout information.
+class VTableBuilder {
public:
/// PrimaryBasesSetVectorTy - A set vector of direct and indirect
/// primary bases.
@@ -1140,7 +1127,7 @@ private:
VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
/// Components - The components of the vtable being built.
- llvm::SmallVector<VtableComponent, 64> Components;
+ llvm::SmallVector<VTableComponent, 64> Components;
/// AddressPoints - Address points for the vtable being built.
AddressPointsMapTy AddressPoints;
@@ -1155,17 +1142,17 @@ private:
/// method.
const uint64_t BaseOffsetInLayoutClass;
- /// VtableIndex - The index in the vtable that this method has.
+ /// VTableIndex - The index in the vtable that this method has.
/// (For destructors, this is the index of the complete destructor).
- const uint64_t VtableIndex;
+ const uint64_t VTableIndex;
MethodInfo(uint64_t BaseOffset, uint64_t BaseOffsetInLayoutClass,
- uint64_t VtableIndex)
+ uint64_t VTableIndex)
: BaseOffset(BaseOffset),
BaseOffsetInLayoutClass(BaseOffsetInLayoutClass),
- VtableIndex(VtableIndex) { }
+ VTableIndex(VTableIndex) { }
- MethodInfo() : BaseOffset(0), BaseOffsetInLayoutClass(0), VtableIndex(0) { }
+ MethodInfo() : BaseOffset(0), BaseOffsetInLayoutClass(0), VTableIndex(0) { }
};
typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
@@ -1174,11 +1161,11 @@ private:
/// currently building.
MethodInfoMapTy MethodInfoMap;
- typedef llvm::DenseMap<uint64_t, ThunkInfo> VtableThunksMapTy;
+ typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
/// VTableThunks - The thunks by vtable index in the vtable currently being
/// built.
- VtableThunksMapTy VTableThunks;
+ VTableThunksMapTy VTableThunks;
typedef llvm::SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
@@ -1253,22 +1240,29 @@ private:
uint64_t FirstBaseOffsetInLayoutClass,
PrimaryBasesSetVectorTy &PrimaryBases);
- // LayoutVtable - Layout the vtable for the given base class, including its
+ // LayoutVTable - Layout the vtable for the given base class, including its
// secondary vtables and any vtables for virtual bases.
- void LayoutVtable();
+ void LayoutVTable();
- /// LayoutPrimaryAndSecondaryVtables - Layout the primary vtable for the
+ /// LayoutPrimaryAndSecondaryVTables - Layout the primary vtable for the
/// given base subobject, as well as all its secondary vtables.
- void LayoutPrimaryAndSecondaryVtables(BaseSubobject Base,
- bool BaseIsVirtual,
+ ///
+ /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
+ /// or a direct or indirect base of a virtual base.
+ ///
+ /// \param BaseIsVirtualInLayoutClass - Whether the base subobject is virtual
+ /// in the layout class.
+ void LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ bool BaseIsVirtualInLayoutClass,
uint64_t OffsetInLayoutClass);
- /// LayoutSecondaryVtables - Layout the secondary vtables for the given base
+ /// LayoutSecondaryVTables - Layout the secondary vtables for the given base
/// subobject.
///
/// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
/// or a direct or indirect base of a virtual base.
- void LayoutSecondaryVtables(BaseSubobject Base, bool BaseIsMorallyVirtual,
+ void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual,
uint64_t OffsetInLayoutClass);
/// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this
@@ -1277,19 +1271,19 @@ private:
uint64_t OffsetInLayoutClass,
VisitedVirtualBasesSetTy &VBases);
- /// LayoutVtablesForVirtualBases - Layout vtables for all virtual bases of the
+ /// LayoutVTablesForVirtualBases - Layout vtables for all virtual bases of the
/// given base (excluding any primary bases).
- void LayoutVtablesForVirtualBases(const CXXRecordDecl *RD,
+ void LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
VisitedVirtualBasesSetTy &VBases);
- /// isBuildingConstructionVtable - Return whether this vtable builder is
+ /// isBuildingConstructionVTable - Return whether this vtable builder is
/// building a construction vtable.
- bool isBuildingConstructorVtable() const {
+ bool isBuildingConstructorVTable() const {
return MostDerivedClass != LayoutClass;
}
public:
- VtableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass,
+ VTableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass,
uint64_t MostDerivedClassOffset, bool MostDerivedClassIsVirtual,
const CXXRecordDecl *LayoutClass)
: VTables(VTables), MostDerivedClass(MostDerivedClass),
@@ -1298,7 +1292,7 @@ public:
LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
- LayoutVtable();
+ LayoutVTable();
}
ThunksMapTy::const_iterator thunks_begin() const {
@@ -1335,11 +1329,11 @@ public:
return AddressPoints.end();
}
- VtableThunksMapTy::const_iterator vtable_thunks_begin() const {
+ VTableThunksMapTy::const_iterator vtable_thunks_begin() const {
return VTableThunks.begin();
}
- VtableThunksMapTy::const_iterator vtable_thunks_end() const {
+ VTableThunksMapTy::const_iterator vtable_thunks_end() const {
return VTableThunks.end();
}
@@ -1347,8 +1341,8 @@ public:
void dumpLayout(llvm::raw_ostream&);
};
-void VtableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
- assert(!isBuildingConstructorVtable() &&
+void VTableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
+ assert(!isBuildingConstructorVTable() &&
"Can't add thunks for construction vtable");
llvm::SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD];
@@ -1361,27 +1355,26 @@ void VtableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
ThunksVector.push_back(Thunk);
}
-/// OverridesMethodInBases - Checks whether whether this virtual member
-/// function overrides a member function in any of the given bases.
-/// Returns the overridden member function, or null if none was found.
-static const CXXMethodDecl *
-OverridesMethodInBases(const CXXMethodDecl *MD,
- VtableBuilder::PrimaryBasesSetVectorTy &Bases) {
+typedef llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverriddenMethodsSetTy;
+
+/// ComputeAllOverriddenMethods - Given a method decl, will return a set of all
+/// the overridden methods that the function decl overrides.
+static void
+ComputeAllOverriddenMethods(const CXXMethodDecl *MD,
+ OverriddenMethodsSetTy& OverriddenMethods) {
+ assert(MD->isVirtual() && "Method is not virtual!");
+
for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
E = MD->end_overridden_methods(); I != E; ++I) {
const CXXMethodDecl *OverriddenMD = *I;
- const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent();
- assert(OverriddenMD->isCanonicalDecl() &&
- "Should have the canonical decl of the overridden RD!");
- if (Bases.count(OverriddenRD))
- return OverriddenMD;
+ OverriddenMethods.insert(OverriddenMD);
+
+ ComputeAllOverriddenMethods(OverriddenMD, OverriddenMethods);
}
-
- return 0;
}
-void VtableBuilder::ComputeThisAdjustments() {
+void VTableBuilder::ComputeThisAdjustments() {
// Now go through the method info map and see if any of the methods need
// 'this' pointer adjustments.
for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
@@ -1390,9 +1383,9 @@ void VtableBuilder::ComputeThisAdjustments() {
const MethodInfo &MethodInfo = I->second;
// Ignore adjustments for unused function pointers.
- uint64_t VtableIndex = MethodInfo.VtableIndex;
- if (Components[VtableIndex].getKind() ==
- VtableComponent::CK_UnusedFunctionPointer)
+ uint64_t VTableIndex = MethodInfo.VTableIndex;
+ if (Components[VTableIndex].getKind() ==
+ VTableComponent::CK_UnusedFunctionPointer)
continue;
// Get the final overrider for this method.
@@ -1407,7 +1400,7 @@ void VtableBuilder::ComputeThisAdjustments() {
// While the thunk itself might be needed by vtables in subclasses or
// in construction vtables, there doesn't seem to be a reason for using
// the thunk in this vtable. Still, we do so to match gcc.
- if (VTableThunks.lookup(VtableIndex).Return.isEmpty())
+ if (VTableThunks.lookup(VTableIndex).Return.isEmpty())
continue;
}
@@ -1418,38 +1411,38 @@ void VtableBuilder::ComputeThisAdjustments() {
continue;
// Add it.
- VTableThunks[VtableIndex].This = ThisAdjustment;
+ VTableThunks[VTableIndex].This = ThisAdjustment;
if (isa<CXXDestructorDecl>(MD)) {
// Add an adjustment for the deleting destructor as well.
- VTableThunks[VtableIndex + 1].This = ThisAdjustment;
+ VTableThunks[VTableIndex + 1].This = ThisAdjustment;
}
}
/// Clear the method info map.
MethodInfoMap.clear();
- if (isBuildingConstructorVtable()) {
+ if (isBuildingConstructorVTable()) {
// We don't need to store thunk information for construction vtables.
return;
}
- for (VtableThunksMapTy::const_iterator I = VTableThunks.begin(),
+ for (VTableThunksMapTy::const_iterator I = VTableThunks.begin(),
E = VTableThunks.end(); I != E; ++I) {
- const VtableComponent &Component = Components[I->first];
+ const VTableComponent &Component = Components[I->first];
const ThunkInfo &Thunk = I->second;
const CXXMethodDecl *MD;
switch (Component.getKind()) {
default:
llvm_unreachable("Unexpected vtable component kind!");
- case VtableComponent::CK_FunctionPointer:
+ case VTableComponent::CK_FunctionPointer:
MD = Component.getFunctionDecl();
break;
- case VtableComponent::CK_CompleteDtorPointer:
+ case VTableComponent::CK_CompleteDtorPointer:
MD = Component.getDestructorDecl();
break;
- case VtableComponent::CK_DeletingDtorPointer:
+ case VTableComponent::CK_DeletingDtorPointer:
// We've already added the thunk when we saw the complete dtor pointer.
continue;
}
@@ -1459,7 +1452,7 @@ void VtableBuilder::ComputeThisAdjustments() {
}
}
-ReturnAdjustment VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
+ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
ReturnAdjustment Adjustment;
if (!Offset.isEmpty()) {
@@ -1474,11 +1467,6 @@ ReturnAdjustment VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass,
Offset.VirtualBase);
}
-
- // FIXME: Once the assert in getVirtualBaseOffsetOffset is back again,
- // we can get rid of this assert.
- assert(Adjustment.VBaseOffsetOffset != 0 &&
- "Invalid vbase offset offset!");
}
Adjustment.NonVirtual = Offset.NonVirtualOffset;
@@ -1488,7 +1476,7 @@ ReturnAdjustment VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
}
BaseOffset
-VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
+VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
BaseSubobject Derived) const {
const CXXRecordDecl *BaseRD = Base.getBase();
const CXXRecordDecl *DerivedRD = Derived.getBase();
@@ -1540,7 +1528,7 @@ VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
}
ThisAdjustment
-VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
+VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
uint64_t BaseOffsetInLayoutClass,
FinalOverriders::OverriderInfo Overrider) {
// Ignore adjustments for pure virtual member functions.
@@ -1587,22 +1575,22 @@ VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
}
void
-VtableBuilder::AddMethod(const CXXMethodDecl *MD,
+VTableBuilder::AddMethod(const CXXMethodDecl *MD,
ReturnAdjustment ReturnAdjustment) {
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
assert(ReturnAdjustment.isEmpty() &&
"Destructor can't have return adjustment!");
// Add both the complete destructor and the deleting destructor.
- Components.push_back(VtableComponent::MakeCompleteDtor(DD));
- Components.push_back(VtableComponent::MakeDeletingDtor(DD));
+ Components.push_back(VTableComponent::MakeCompleteDtor(DD));
+ Components.push_back(VTableComponent::MakeDeletingDtor(DD));
} else {
// Add the return adjustment if necessary.
if (!ReturnAdjustment.isEmpty())
VTableThunks[Components.size()].Return = ReturnAdjustment;
// Add the function.
- Components.push_back(VtableComponent::MakeFunction(MD));
+ Components.push_back(VTableComponent::MakeFunction(MD));
}
}
@@ -1616,19 +1604,16 @@ VtableBuilder::AddMethod(const CXXMethodDecl *MD,
/// struct C : B { virtual void f(); }
///
/// OverridesIndirectMethodInBase will return true if given C::f as the method
-/// and { A } as the set of bases.
+/// and { A } as the set of bases.
static bool
OverridesIndirectMethodInBases(const CXXMethodDecl *MD,
- VtableBuilder::PrimaryBasesSetVectorTy &Bases) {
+ VTableBuilder::PrimaryBasesSetVectorTy &Bases) {
+ if (Bases.count(MD->getParent()))
+ return true;
+
for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
E = MD->end_overridden_methods(); I != E; ++I) {
const CXXMethodDecl *OverriddenMD = *I;
- const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent();
- assert(OverriddenMD->isCanonicalDecl() &&
- "Should have the canonical decl of the overridden RD!");
-
- if (Bases.count(OverriddenRD))
- return true;
// Check "indirect overriders".
if (OverridesIndirectMethodInBases(OverriddenMD, Bases))
@@ -1639,7 +1624,7 @@ OverridesIndirectMethodInBases(const CXXMethodDecl *MD,
}
bool
-VtableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
+VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
uint64_t BaseOffsetInLayoutClass,
const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
uint64_t FirstBaseOffsetInLayoutClass) const {
@@ -1657,7 +1642,7 @@ VtableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
if (Overrider->getParent() == FirstBaseInPrimaryBaseChain)
return true;
- VtableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
+ VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain;
PrimaryBases.insert(RD);
@@ -1705,15 +1690,18 @@ VtableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
/// from the nearest base. Returns null if no method was found.
static const CXXMethodDecl *
FindNearestOverriddenMethod(const CXXMethodDecl *MD,
- VtableBuilder::PrimaryBasesSetVectorTy &Bases) {
+ VTableBuilder::PrimaryBasesSetVectorTy &Bases) {
+ OverriddenMethodsSetTy OverriddenMethods;
+ ComputeAllOverriddenMethods(MD, OverriddenMethods);
+
for (int I = Bases.size(), E = 0; I != E; --I) {
const CXXRecordDecl *PrimaryBase = Bases[I - 1];
// Now check the overriden methods.
- for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
- E = MD->end_overridden_methods(); I != E; ++I) {
+ for (OverriddenMethodsSetTy::const_iterator I = OverriddenMethods.begin(),
+ E = OverriddenMethods.end(); I != E; ++I) {
const CXXMethodDecl *OverriddenMD = *I;
-
+
// We found our overridden method.
if (OverriddenMD->getParent() == PrimaryBase)
return OverriddenMD;
@@ -1724,7 +1712,7 @@ FindNearestOverriddenMethod(const CXXMethodDecl *MD,
}
void
-VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
+VTableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
uint64_t FirstBaseOffsetInLayoutClass,
PrimaryBasesSetVectorTy &PrimaryBases) {
@@ -1792,7 +1780,7 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
MethodInfo MethodInfo(Base.getBaseOffset(),
BaseOffsetInLayoutClass,
- OverriddenMethodInfo.VtableIndex);
+ OverriddenMethodInfo.VTableIndex);
assert(!MethodInfoMap.count(MD) &&
"Should not have method info for this method yet!");
@@ -1804,7 +1792,7 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
// or indirect base class of a virtual base class, we need to emit a
// thunk if we ever have a class hierarchy where the base class is not
// a primary base in the complete object.
- if (!isBuildingConstructorVtable() && OverriddenMD != MD) {
+ if (!isBuildingConstructorVTable() && OverriddenMD != MD) {
// Compute the this adjustment.
ThisAdjustment ThisAdjustment =
ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass,
@@ -1835,7 +1823,7 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass,
FirstBaseInPrimaryBaseChain,
FirstBaseOffsetInLayoutClass)) {
- Components.push_back(VtableComponent::MakeUnusedFunction(OverriderMD));
+ Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD));
continue;
}
@@ -1850,8 +1838,9 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
}
}
-void VtableBuilder::LayoutVtable() {
- LayoutPrimaryAndSecondaryVtables(BaseSubobject(MostDerivedClass, 0),
+void VTableBuilder::LayoutVTable() {
+ LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass, 0),
+ /*BaseIsMorallyVirtual=*/false,
MostDerivedClassIsVirtual,
MostDerivedClassOffset);
@@ -1862,22 +1851,24 @@ void VtableBuilder::LayoutVtable() {
VBases);
VBases.clear();
- LayoutVtablesForVirtualBases(MostDerivedClass, VBases);
+ LayoutVTablesForVirtualBases(MostDerivedClass, VBases);
}
void
-VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base,
- bool BaseIsVirtual,
+VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ bool BaseIsVirtualInLayoutClass,
uint64_t OffsetInLayoutClass) {
assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!");
// Add vcall and vbase offsets for this vtable.
VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, LayoutClass, &Overriders,
- Base, BaseIsVirtual, OffsetInLayoutClass);
+ Base, BaseIsVirtualInLayoutClass,
+ OffsetInLayoutClass);
Components.append(Builder.components_begin(), Builder.components_end());
// Check if we need to add these vcall offsets.
- if (BaseIsVirtual && !Builder.getVCallOffsets().empty()) {
+ if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()) {
VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()];
if (VCallOffsets.empty())
@@ -1893,10 +1884,10 @@ VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base,
// FIXME: We should not use / 8 here.
int64_t OffsetToTop = -(int64_t)(OffsetInLayoutClass -
MostDerivedClassOffset) / 8;
- Components.push_back(VtableComponent::MakeOffsetToTop(OffsetToTop));
+ Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
// Next, add the RTTI.
- Components.push_back(VtableComponent::MakeRTTI(MostDerivedClass));
+ Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
uint64_t AddressPoint = Components.size();
@@ -1936,15 +1927,11 @@ VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base,
RD = PrimaryBase;
}
- bool BaseIsMorallyVirtual = BaseIsVirtual;
- if (isBuildingConstructorVtable() && Base.getBase() == MostDerivedClass)
- BaseIsMorallyVirtual = false;
-
// Layout secondary vtables.
- LayoutSecondaryVtables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass);
+ LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass);
}
-void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base,
+void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
bool BaseIsMorallyVirtual,
uint64_t OffsetInLayoutClass) {
// Itanium C++ ABI 2.5.2:
@@ -1969,7 +1956,7 @@ void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base,
if (!BaseDecl->isDynamicClass())
continue;
- if (isBuildingConstructorVtable()) {
+ if (isBuildingConstructorVTable()) {
// Itanium C++ ABI 2.6.4:
// Some of the base class subobjects may not need construction virtual
// tables, which will therefore not be present in the construction
@@ -1988,20 +1975,21 @@ void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base,
// Don't emit a secondary vtable for a primary base. We might however want
// to emit secondary vtables for other bases of this base.
if (BaseDecl == PrimaryBase) {
- LayoutSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset),
+ LayoutSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset),
BaseIsMorallyVirtual, BaseOffsetInLayoutClass);
continue;
}
// Layout the primary vtable (and any secondary vtables) for this base.
- LayoutPrimaryAndSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset),
- /*BaseIsVirtual=*/false,
+ LayoutPrimaryAndSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset),
+ BaseIsMorallyVirtual,
+ /*BaseIsVirtualInLayoutClass=*/false,
BaseOffsetInLayoutClass);
}
}
void
-VtableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
+VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
uint64_t OffsetInLayoutClass,
VisitedVirtualBasesSetTy &VBases) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
@@ -2013,7 +2001,7 @@ VtableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
if (Layout.getPrimaryBaseWasVirtual()) {
bool IsPrimaryVirtualBase = true;
- if (isBuildingConstructorVtable()) {
+ if (isBuildingConstructorVTable()) {
// Check if the base is actually a primary base in the class we use for
// layout.
const ASTRecordLayout &LayoutClassLayout =
@@ -2059,7 +2047,7 @@ VtableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
}
void
-VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD,
+VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
VisitedVirtualBasesSetTy &VBases) {
// Itanium C++ ABI 2.5.2:
// Then come the virtual base virtual tables, also in inheritance graph
@@ -2084,22 +2072,23 @@ VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD,
uint64_t BaseOffsetInLayoutClass =
LayoutClassLayout.getVBaseClassOffset(BaseDecl);
- LayoutPrimaryAndSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset),
- /*BaseIsVirtual=*/true,
+ LayoutPrimaryAndSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset),
+ /*BaseIsMorallyVirtual=*/true,
+ /*BaseIsVirtualInLayoutClass=*/true,
BaseOffsetInLayoutClass);
}
// We only need to check the base for virtual base vtables if it actually
// has virtual bases.
if (BaseDecl->getNumVBases())
- LayoutVtablesForVirtualBases(BaseDecl, VBases);
+ LayoutVTablesForVirtualBases(BaseDecl, VBases);
}
}
/// dumpLayout - Dump the vtable layout.
-void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
+void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) {
- if (isBuildingConstructorVtable()) {
+ if (isBuildingConstructorVTable()) {
Out << "Construction vtable for ('";
Out << MostDerivedClass->getQualifiedNameAsString() << "', ";
// FIXME: Don't use / 8 .
@@ -2129,28 +2118,28 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
Out << llvm::format("%4d | ", I);
- const VtableComponent &Component = Components[I];
+ const VTableComponent &Component = Components[I];
// Dump the component.
switch (Component.getKind()) {
- case VtableComponent::CK_VCallOffset:
+ case VTableComponent::CK_VCallOffset:
Out << "vcall_offset (" << Component.getVCallOffset() << ")";
break;
- case VtableComponent::CK_VBaseOffset:
+ case VTableComponent::CK_VBaseOffset:
Out << "vbase_offset (" << Component.getVBaseOffset() << ")";
break;
- case VtableComponent::CK_OffsetToTop:
+ case VTableComponent::CK_OffsetToTop:
Out << "offset_to_top (" << Component.getOffsetToTop() << ")";
break;
- case VtableComponent::CK_RTTI:
+ case VTableComponent::CK_RTTI:
Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI";
break;
- case VtableComponent::CK_FunctionPointer: {
+ case VTableComponent::CK_FunctionPointer: {
const CXXMethodDecl *MD = Component.getFunctionDecl();
std::string Str =
@@ -2192,10 +2181,10 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
break;
}
- case VtableComponent::CK_CompleteDtorPointer:
- case VtableComponent::CK_DeletingDtorPointer: {
+ case VTableComponent::CK_CompleteDtorPointer:
+ case VTableComponent::CK_DeletingDtorPointer: {
bool IsComplete =
- Component.getKind() == VtableComponent::CK_CompleteDtorPointer;
+ Component.getKind() == VTableComponent::CK_CompleteDtorPointer;
const CXXDestructorDecl *DD = Component.getDestructorDecl();
@@ -2227,7 +2216,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
break;
}
- case VtableComponent::CK_UnusedFunctionPointer: {
+ case VTableComponent::CK_UnusedFunctionPointer: {
const CXXMethodDecl *MD = Component.getUnusedFunctionDecl();
std::string Str =
@@ -2279,7 +2268,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
Out << '\n';
- if (isBuildingConstructorVtable())
+ if (isBuildingConstructorVTable())
return;
if (MostDerivedClass->getNumVBases()) {
@@ -2373,7 +2362,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
}
-void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
+void CodeGenVTables::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
// Itanium C++ ABI 2.5.2:
// The order of the virtual function pointers in a virtual table is the
@@ -2400,7 +2389,7 @@ void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
// Collect all the primary bases, so we can check whether methods override
// a method from the base.
- VtableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
+ VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
for (ASTRecordLayout::primary_base_info_iterator
I = Layout.primary_base_begin(), E = Layout.primary_base_end();
I != E; ++I)
@@ -2418,7 +2407,7 @@ void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
// Check if this method overrides a method in the primary base.
if (const CXXMethodDecl *OverriddenMD =
- OverridesMethodInBases(MD, PrimaryBases)) {
+ FindNearestOverriddenMethod(MD, PrimaryBases)) {
// Check if converting from the return type of the method to the
// return type of the overridden method requires conversion.
if (ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD,
@@ -2430,12 +2419,12 @@ void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
cast<CXXDestructorDecl>(OverriddenMD);
// Add both the complete and deleting entries.
- MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] =
- getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
- MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] =
- getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] =
+ getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+ getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
} else {
- MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD);
+ MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD);
}
// We don't need to add an entry for this method.
@@ -2452,13 +2441,13 @@ void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
}
// Add the complete dtor.
- MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
// Add the deleting dtor.
- MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
} else {
// Add the entry.
- MethodVtableIndices[MD] = CurrentIndex++;
+ MethodVTableIndices[MD] = CurrentIndex++;
}
}
@@ -2468,11 +2457,11 @@ void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
// its entries come after the declared virtual function pointers.
// Add the complete dtor.
- MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
+ MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
CurrentIndex++;
// Add the deleting dtor.
- MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] =
+ MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] =
CurrentIndex++;
}
@@ -2485,24 +2474,24 @@ uint64_t CodeGenVTables::getNumVirtualFunctionPointers(const CXXRecordDecl *RD)
if (I != NumVirtualFunctionPointers.end())
return I->second;
- ComputeMethodVtableIndices(RD);
+ ComputeMethodVTableIndices(RD);
I = NumVirtualFunctionPointers.find(RD);
assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!");
return I->second;
}
-uint64_t CodeGenVTables::getMethodVtableIndex(GlobalDecl GD) {
- MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD);
- if (I != MethodVtableIndices.end())
+uint64_t CodeGenVTables::getMethodVTableIndex(GlobalDecl GD) {
+ MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD);
+ if (I != MethodVTableIndices.end())
return I->second;
const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
- ComputeMethodVtableIndices(RD);
+ ComputeMethodVTableIndices(RD);
- I = MethodVtableIndices.find(GD);
- assert(I != MethodVtableIndices.end() && "Did not find index!");
+ I = MethodVTableIndices.find(GD);
+ assert(I != MethodVTableIndices.end() && "Did not find index!");
return I->second;
}
@@ -2530,13 +2519,6 @@ int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
}
I = VirtualBaseClassOffsetOffsets.find(ClassPair);
-
- // FIXME: The assertion below assertion currently fails with the old vtable
- /// layout code if there is a non-virtual thunk adjustment in a vtable.
- // Once the new layout is in place, this return should be removed.
- if (I == VirtualBaseClassOffsetOffsets.end())
- return 0;
-
assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!");
return I->second;
@@ -2544,6 +2526,9 @@ int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
uint64_t
CodeGenVTables::getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD) {
+ assert(AddressPoints.count(std::make_pair(RD, Base)) &&
+ "Did not find address point!");
+
uint64_t AddressPoint = AddressPoints.lookup(std::make_pair(RD, Base));
assert(AddressPoint && "Address point must not be zero!");
@@ -2562,7 +2547,7 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
else
getMangleContext().mangleThunk(MD, Thunk, Name);
- const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
+ const llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(MD);
return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl());
}
@@ -2745,7 +2730,7 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk)
// There's already a declaration with the same name, check if it has the same
// type or if we need to replace it.
if (cast<llvm::GlobalValue>(Entry)->getType()->getElementType() !=
- CGM.getTypes().GetFunctionTypeForVtable(MD)) {
+ CGM.getTypes().GetFunctionTypeForVTable(MD)) {
llvm::GlobalValue *OldThunkFn = cast<llvm::GlobalValue>(Entry);
// If the types mismatch then we have to rewrite the definition.
@@ -2804,7 +2789,7 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
if (LayoutData)
return;
- VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
+ VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
// Add the VTable layout.
uint64_t NumVTableComponents = Builder.getNumVTableComponents();
@@ -2833,7 +2818,7 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
std::sort(VTableThunks.begin(), VTableThunks.end());
// Add the address points.
- for (VtableBuilder::AddressPointsMapTy::const_iterator I =
+ for (VTableBuilder::AddressPointsMapTy::const_iterator I =
Builder.address_points_begin(), E = Builder.address_points_end();
I != E; ++I) {
@@ -2858,7 +2843,7 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase)))
return;
- for (VtableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
+ for (VTableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
Builder.getVBaseOffsetOffsets().begin(),
E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) {
// Insert all types.
@@ -2888,43 +2873,43 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
llvm::Constant* PureVirtualFn = 0;
for (unsigned I = 0; I != NumComponents; ++I) {
- VtableComponent Component =
- VtableComponent::getFromOpaqueInteger(Components[I]);
+ VTableComponent Component =
+ VTableComponent::getFromOpaqueInteger(Components[I]);
llvm::Constant *Init = 0;
switch (Component.getKind()) {
- case VtableComponent::CK_VCallOffset:
+ case VTableComponent::CK_VCallOffset:
Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVCallOffset());
Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
break;
- case VtableComponent::CK_VBaseOffset:
+ case VTableComponent::CK_VBaseOffset:
Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVBaseOffset());
Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
break;
- case VtableComponent::CK_OffsetToTop:
+ case VTableComponent::CK_OffsetToTop:
Init = llvm::ConstantInt::get(PtrDiffTy, Component.getOffsetToTop());
Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
break;
- case VtableComponent::CK_RTTI:
+ case VTableComponent::CK_RTTI:
Init = llvm::ConstantExpr::getBitCast(RTTI, Int8PtrTy);
break;
- case VtableComponent::CK_FunctionPointer:
- case VtableComponent::CK_CompleteDtorPointer:
- case VtableComponent::CK_DeletingDtorPointer: {
+ case VTableComponent::CK_FunctionPointer:
+ case VTableComponent::CK_CompleteDtorPointer:
+ case VTableComponent::CK_DeletingDtorPointer: {
GlobalDecl GD;
// Get the right global decl.
switch (Component.getKind()) {
default:
llvm_unreachable("Unexpected vtable component kind");
- case VtableComponent::CK_FunctionPointer:
+ case VTableComponent::CK_FunctionPointer:
GD = Component.getFunctionDecl();
break;
- case VtableComponent::CK_CompleteDtorPointer:
+ case VTableComponent::CK_CompleteDtorPointer:
GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Complete);
break;
- case VtableComponent::CK_DeletingDtorPointer:
+ case VTableComponent::CK_DeletingDtorPointer:
GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Deleting);
break;
}
@@ -2953,7 +2938,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
NextVTableThunkIndex++;
} else {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD);
+ const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(MD);
Init = CGM.GetAddrOfFunction(GD, Ty);
}
@@ -2963,7 +2948,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
break;
}
- case VtableComponent::CK_UnusedFunctionPointer:
+ case VTableComponent::CK_UnusedFunctionPointer:
Init = llvm::ConstantExpr::getNullValue(Int8PtrTy);
break;
};
@@ -3020,7 +3005,7 @@ GetGlobalVariable(llvm::Module &Module, llvm::StringRef Name,
llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) {
llvm::SmallString<256> OutName;
- CGM.getMangleContext().mangleCXXVtable(RD, OutName);
+ CGM.getMangleContext().mangleCXXVTable(RD, OutName);
llvm::StringRef Name = OutName.str();
ComputeVTableRelatedInformation(RD);
@@ -3038,8 +3023,8 @@ CodeGenVTables::EmitVTableDefinition(llvm::GlobalVariable *VTable,
llvm::GlobalVariable::LinkageTypes Linkage,
const CXXRecordDecl *RD) {
// Dump the vtable layout if necessary.
- if (CGM.getLangOptions().DumpVtableLayouts) {
- VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
+ if (CGM.getLangOptions().DumpVTableLayouts) {
+ VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
Builder.dumpLayout(llvm::errs());
}
@@ -3064,11 +3049,11 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
const BaseSubobject &Base,
bool BaseIsVirtual,
VTableAddressPointsMapTy& AddressPoints) {
- VtableBuilder Builder(*this, Base.getBase(), Base.getBaseOffset(),
+ VTableBuilder Builder(*this, Base.getBase(), Base.getBaseOffset(),
/*MostDerivedClassIsVirtual=*/BaseIsVirtual, RD);
// Dump the vtable layout if necessary.
- if (CGM.getLangOptions().DumpVtableLayouts)
+ if (CGM.getLangOptions().DumpVTableLayouts)
Builder.dumpLayout(llvm::errs());
// Add the address points.
@@ -3077,7 +3062,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
// Get the mangled construction vtable name.
llvm::SmallString<256> OutName;
- CGM.getMangleContext().mangleCXXCtorVtable(RD, Base.getBaseOffset() / 8,
+ CGM.getMangleContext().mangleCXXCtorVTable(RD, Base.getBaseOffset() / 8,
Base.getBase(), OutName);
llvm::StringRef Name = OutName.str();
@@ -3111,9 +3096,9 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
void
CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
const CXXRecordDecl *RD) {
- llvm::GlobalVariable *&VTable = Vtables[RD];
+ llvm::GlobalVariable *&VTable = VTables[RD];
if (VTable) {
- assert(VTable->getInitializer() && "Vtable doesn't have a definition!");
+ assert(VTable->getInitializer() && "VTable doesn't have a definition!");
return;
}
@@ -3121,6 +3106,18 @@ CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
EmitVTableDefinition(VTable, Linkage, RD);
GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD);
+
+ // If this is the magic class __cxxabiv1::__fundamental_type_info,
+ // we will emit the typeinfo for the fundamental types. This is the
+ // same behaviour as GCC.
+ const DeclContext *DC = RD->getDeclContext();
+ if (RD->getIdentifier() &&
+ RD->getIdentifier()->isStr("__fundamental_type_info") &&
+ isa<NamespaceDecl>(DC) &&
+ cast<NamespaceDecl>(DC)->getIdentifier() &&
+ cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__cxxabiv1") &&
+ DC->getParent()->isTranslationUnit())
+ CGM.EmitFundamentalRTTIDescriptors();
}
void CodeGenVTables::EmitVTableRelatedData(GlobalDecl GD) {
@@ -3160,11 +3157,11 @@ void CodeGenVTables::EmitVTableRelatedData(GlobalDecl GD) {
return;
}
- if (Vtables.count(RD))
+ if (VTables.count(RD))
return;
if (RDKind == TSK_ImplicitInstantiation)
- CGM.DeferredVtables.push_back(RD);
+ CGM.DeferredVTables.push_back(RD);
else
- GenerateClassData(CGM.getVtableLinkage(RD), RD);
+ GenerateClassData(CGM.getVTableLinkage(RD), RD);
}
diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVTables.h
index 6073555..6c18ca8 100644
--- a/lib/CodeGen/CGVtable.h
+++ b/lib/CodeGen/CGVTables.h
@@ -1,4 +1,4 @@
-//===--- CGVtable.h - Emit LLVM Code for C++ vtables ----------------------===//
+//===--- CGVTables.h - Emit LLVM Code for C++ vtables ---------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -180,10 +180,10 @@ namespace CodeGen {
class CodeGenVTables {
CodeGenModule &CGM;
- /// MethodVtableIndices - Contains the index (relative to the vtable address
+ /// MethodVTableIndices - Contains the index (relative to the vtable address
/// point) where the function pointer for a virtual function is stored.
- typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVtableIndicesTy;
- MethodVtableIndicesTy MethodVtableIndices;
+ typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
+ MethodVTableIndicesTy MethodVTableIndices;
typedef std::pair<const CXXRecordDecl *,
const CXXRecordDecl *> ClassPairTy;
@@ -195,8 +195,8 @@ class CodeGenVTables {
VirtualBaseClassOffsetOffsetsMapTy;
VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets;
- /// Vtables - All the vtables which have been defined.
- llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> Vtables;
+ /// VTables - All the vtables which have been defined.
+ llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> VTables;
/// NumVirtualFunctionPointers - Contains the number of virtual function
/// pointers in the vtable for a given record decl.
@@ -216,8 +216,8 @@ class CodeGenVTables {
/// integers are the vtable components.
VTableLayoutMapTy VTableLayoutMap;
- typedef llvm::DenseMap<std::pair<const CXXRecordDecl *,
- BaseSubobject>, uint64_t> AddressPointsMapTy;
+ typedef std::pair<const CXXRecordDecl *, BaseSubobject> BaseSubobjectPairTy;
+ typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t> AddressPointsMapTy;
/// Address points - Address points for all vtables.
AddressPointsMapTy AddressPoints;
@@ -247,14 +247,12 @@ class CodeGenVTables {
return &Components[1];
}
- typedef llvm::DenseMap<ClassPairTy, uint64_t> SubVTTIndiciesMapTy;
+ typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t> SubVTTIndiciesMapTy;
/// SubVTTIndicies - Contains indices into the various sub-VTTs.
SubVTTIndiciesMapTy SubVTTIndicies;
-
- typedef llvm::DenseMap<std::pair<const CXXRecordDecl *,
- BaseSubobject>, uint64_t>
+ typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t>
SecondaryVirtualPointerIndicesMapTy;
/// SecondaryVirtualPointerIndices - Contains the secondary virtual pointer
@@ -265,7 +263,7 @@ class CodeGenVTables {
/// pointers in the vtable for a given record decl.
uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
- void ComputeMethodVtableIndices(const CXXRecordDecl *RD);
+ void ComputeMethodVTableIndices(const CXXRecordDecl *RD);
llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
bool GenerateDefinition,
@@ -295,6 +293,15 @@ public:
CodeGenVTables(CodeGenModule &CGM)
: CGM(CGM) { }
+ // isKeyFunctionInAnotherTU - True if this record has a key function and it is
+ // in another translation unit.
+ static bool isKeyFunctionInAnotherTU(ASTContext &Context,
+ const CXXRecordDecl *RD) {
+ assert (RD->isDynamicClass() && "Non dynamic classes have no key.");
+ const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
+ return KeyFunction && !KeyFunction->getBody();
+ }
+
/// 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.
@@ -302,17 +309,17 @@ public:
/// 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);
+ uint64_t getSubVTTIndex(const CXXRecordDecl *RD, BaseSubobject Base);
/// getSecondaryVirtualPointerIndex - Return the index in the VTT where the
/// virtual pointer for the given subobject is located.
uint64_t getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD,
BaseSubobject Base);
- /// getMethodVtableIndex - Return the index (relative to the vtable address
+ /// getMethodVTableIndex - Return the index (relative to the vtable address
/// point) where the function pointer for the given virtual function is
/// stored.
- uint64_t getMethodVtableIndex(GlobalDecl GD);
+ uint64_t getMethodVTableIndex(GlobalDecl GD);
/// getVirtualBaseOffsetOffset - Return the offset in bytes (relative to the
/// vtable address point) where the offset of the virtual base that contains
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index 91fb714..92ef9dc 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -34,69 +34,64 @@ namespace CodeGen {
/// simple LLVM SSA value, a pair of SSA values for complex numbers, or the
/// address of an aggregate value in memory.
class RValue {
- llvm::Value *V1, *V2;
- // TODO: Encode this into the low bit of pointer for more efficient
- // return-by-value.
- enum { Scalar, Complex, Aggregate } Flavor;
+ enum Flavor { Scalar, Complex, Aggregate };
- bool Volatile:1;
-public:
+ // Stores first value and flavor.
+ llvm::PointerIntPair<llvm::Value *, 2, Flavor> V1;
+ // Stores second value and volatility.
+ llvm::PointerIntPair<llvm::Value *, 1, bool> V2;
- bool isScalar() const { return Flavor == Scalar; }
- bool isComplex() const { return Flavor == Complex; }
- bool isAggregate() const { return Flavor == Aggregate; }
+public:
+ bool isScalar() const { return V1.getInt() == Scalar; }
+ bool isComplex() const { return V1.getInt() == Complex; }
+ bool isAggregate() const { return V1.getInt() == Aggregate; }
- bool isVolatileQualified() const { return Volatile; }
+ bool isVolatileQualified() const { return V2.getInt(); }
/// getScalarVal() - Return the Value* of this scalar value.
llvm::Value *getScalarVal() const {
assert(isScalar() && "Not a scalar!");
- return V1;
+ return V1.getPointer();
}
/// getComplexVal - Return the real/imag components of this complex value.
///
std::pair<llvm::Value *, llvm::Value *> getComplexVal() const {
- return std::pair<llvm::Value *, llvm::Value *>(V1, V2);
+ return std::make_pair(V1.getPointer(), V2.getPointer());
}
/// getAggregateAddr() - Return the Value* of the address of the aggregate.
llvm::Value *getAggregateAddr() const {
assert(isAggregate() && "Not an aggregate!");
- return V1;
+ return V1.getPointer();
}
static RValue get(llvm::Value *V) {
RValue ER;
- ER.V1 = V;
- ER.Flavor = Scalar;
- ER.Volatile = false;
+ ER.V1.setPointer(V);
+ ER.V1.setInt(Scalar);
+ ER.V2.setInt(false);
return ER;
}
static RValue getComplex(llvm::Value *V1, llvm::Value *V2) {
RValue ER;
- ER.V1 = V1;
- ER.V2 = V2;
- ER.Flavor = Complex;
- ER.Volatile = false;
+ ER.V1.setPointer(V1);
+ ER.V2.setPointer(V2);
+ ER.V1.setInt(Complex);
+ ER.V2.setInt(false);
return ER;
}
static RValue getComplex(const std::pair<llvm::Value *, llvm::Value *> &C) {
- RValue ER;
- ER.V1 = C.first;
- ER.V2 = C.second;
- ER.Flavor = Complex;
- ER.Volatile = false;
- return ER;
+ return getComplex(C.first, C.second);
}
// FIXME: Aggregate rvalues need to retain information about whether they are
// volatile or not. Remove default to find all places that probably get this
// wrong.
- static RValue getAggregate(llvm::Value *V, bool Vol = false) {
+ static RValue getAggregate(llvm::Value *V, bool Volatile = false) {
RValue ER;
- ER.V1 = V;
- ER.Flavor = Aggregate;
- ER.Volatile = Vol;
+ ER.V1.setPointer(V);
+ ER.V1.setInt(Aggregate);
+ ER.V2.setInt(Volatile);
return ER;
}
};
@@ -220,7 +215,7 @@ public:
}
// bitfield lvalue
- llvm::Value *getBitFieldAddr() const {
+ llvm::Value *getBitFieldBaseAddr() const {
assert(isBitField());
return V;
}
@@ -269,11 +264,17 @@ public:
return R;
}
- static LValue MakeBitfield(llvm::Value *V, const CGBitFieldInfo &Info,
+ /// \brief Create a new object to represent a bit-field access.
+ ///
+ /// \param BaseValue - The base address of the structure containing the
+ /// bit-field.
+ /// \param Info - The information describing how to perform the bit-field
+ /// access.
+ static LValue MakeBitfield(llvm::Value *BaseValue, const CGBitFieldInfo &Info,
unsigned CVR) {
LValue R;
R.LVType = BitField;
- R.V = V;
+ R.V = BaseValue;
R.BitFieldInfo = &Info;
R.SetQualifiers(Qualifiers::fromCVRMask(CVR));
return R;
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index e72a1d9..dfd2a39 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -23,7 +23,7 @@ add_clang_library(clangCodeGen
CGRTTI.cpp
CGStmt.cpp
CGTemporaries.cpp
- CGVtable.cpp
+ CGVTables.cpp
CGVTT.cpp
CodeGenFunction.cpp
CodeGenModule.cpp
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index f38d8a1..d3bf164 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -246,15 +246,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args) {
const FunctionDecl *FD = cast<FunctionDecl>(CurGD.getDecl());
-
- Stmt *Body = FD->getBody();
- if (Body)
- EmitStmt(Body);
- else {
- assert(FD->isImplicit() && "non-implicit function def has no body");
- assert(FD->isCopyAssignment() && "implicit function not copy assignment");
- SynthesizeCXXCopyAssignment(Args);
- }
+ assert(FD->getBody());
+ EmitStmt(FD->getBody());
}
void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) {
@@ -480,6 +473,14 @@ void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type,
}
void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) {
+ // Ignore empty classes in C++.
+ if (getContext().getLangOptions().CPlusPlus) {
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ if (cast<CXXRecordDecl>(RT->getDecl())->isEmpty())
+ return;
+ }
+ }
+
const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext);
if (DestPtr->getType() != BP)
DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp");
@@ -749,6 +750,11 @@ void CodeGenFunction::EmitCleanupBlock() {
return;
}
+ // Scrub debug location info.
+ for (llvm::BasicBlock::iterator LBI = Info.CleanupBlock->begin(),
+ LBE = Info.CleanupBlock->end(); LBI != LBE; ++LBI)
+ Builder.SetInstDebugLocation(LBI);
+
llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
if (CurBB && !CurBB->getTerminator() &&
Info.CleanupBlock->getNumUses() == 0) {
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index f21350d..90a3ec4 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -32,6 +32,7 @@
namespace llvm {
class BasicBlock;
class LLVMContext;
+ class MDNode;
class Module;
class SwitchInst;
class Twine;
@@ -148,19 +149,17 @@ public:
/// block.
class EHCleanupBlock {
CodeGenFunction& CGF;
- llvm::BasicBlock *Cont;
+ llvm::BasicBlock *PreviousInsertionBlock;
llvm::BasicBlock *CleanupHandler;
- llvm::BasicBlock *CleanupEntryBB;
llvm::BasicBlock *PreviousInvokeDest;
public:
EHCleanupBlock(CodeGenFunction &cgf)
- : CGF(cgf), Cont(CGF.createBasicBlock("cont")),
- CleanupHandler(CGF.createBasicBlock("ehcleanup")),
- CleanupEntryBB(CGF.createBasicBlock("ehcleanup.rest")),
+ : CGF(cgf),
+ PreviousInsertionBlock(CGF.Builder.GetInsertBlock()),
+ CleanupHandler(CGF.createBasicBlock("ehcleanup", CGF.CurFn)),
PreviousInvokeDest(CGF.getInvokeDest()) {
- CGF.EmitBranch(Cont);
llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler();
- CGF.Builder.SetInsertPoint(CleanupEntryBB);
+ CGF.Builder.SetInsertPoint(CleanupHandler);
CGF.setInvokeDest(TerminateHandler);
}
~EHCleanupBlock();
@@ -186,7 +185,8 @@ public:
public:
DelayedCleanupBlock(CodeGenFunction &cgf, bool ehonly = false)
: CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()),
- CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0),
+ CleanupEntryBB(CGF.createBasicBlock("cleanup")),
+ CleanupExitBB(0),
CurInvokeDest(CGF.getInvokeDest()),
EHOnly(ehonly) {
CGF.Builder.SetInsertPoint(CleanupEntryBB);
@@ -474,11 +474,15 @@ public:
/// GenerateObjCGetter - Synthesize an Objective-C property getter function.
void GenerateObjCGetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID);
+ void GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
+ ObjCMethodDecl *MD, bool ctor);
/// GenerateObjCSetter - Synthesize an Objective-C property setter function
/// for the given property.
void GenerateObjCSetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID);
+ bool IndirectObjCSetterArg(const CGFunctionInfo &FI);
+ bool IvarTypeWithAggrGCObjects(QualType Ty);
//===--------------------------------------------------------------------===//
// Block Bits
@@ -532,14 +536,16 @@ public:
/// InitializeVTablePointer - Initialize the vtable pointer of the given
/// subobject.
///
- /// \param BaseIsMorallyVirtual - Whether the base subobject is a virtual base
- /// or a direct or indirect base of a virtual base.
- void InitializeVTablePointer(BaseSubobject Base, bool BaseIsMorallyVirtual,
+ void InitializeVTablePointer(BaseSubobject Base,
+ const CXXRecordDecl *NearestVBase,
+ uint64_t OffsetFromNearestVBase,
llvm::Constant *VTable,
const CXXRecordDecl *VTableClass);
typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
- void InitializeVTablePointers(BaseSubobject Base, bool BaseIsMorallyVirtual,
+ void InitializeVTablePointers(BaseSubobject Base,
+ const CXXRecordDecl *NearestVBase,
+ uint64_t OffsetFromNearestVBase,
bool BaseIsNonVirtualPrimaryBase,
llvm::Constant *VTable,
const CXXRecordDecl *VTableClass,
@@ -549,7 +555,6 @@ public:
void SynthesizeCXXCopyConstructor(const FunctionArgList &Args);
- void SynthesizeCXXCopyAssignment(const FunctionArgList &Args);
/// EmitDtorEpilogue - Emit all code that comes at the end of class's
/// destructor. This is to call destructors on members and base classes in
@@ -670,6 +675,9 @@ public:
llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty,
const llvm::Twine &Name = "tmp");
+ /// InitTempAlloca - Provide an initial value for the given alloca.
+ void InitTempAlloca(llvm::AllocaInst *Alloca, llvm::Value *Value);
+
/// CreateIRTemp - Create a temporary IR object of the given type, with
/// appropriate alignment. This routine should only be used when an temporary
/// value needs to be stored into an alloca (for example, to avoid explicit
@@ -704,6 +712,12 @@ public:
RValue EmitAnyExprToTemp(const Expr *E, bool IsAggLocVolatile = false,
bool IsInitializer = false);
+ /// EmitsAnyExprToMem - Emits the code necessary to evaluate an
+ /// arbitrary expression into the given memory location.
+ void EmitAnyExprToMem(const Expr *E, llvm::Value *Location,
+ bool IsLocationVolatile = false,
+ bool IsInitializer = false);
+
/// EmitAggregateCopy - Emit an aggrate copy.
///
/// \param isVolatile - True iff either the source or the destination is
@@ -765,22 +779,23 @@ public:
}
/// GetAddressOfBaseOfCompleteClass - Convert the given pointer to a
- /// complete class down to one of its virtual bases.
- llvm::Value *GetAddressOfBaseOfCompleteClass(llvm::Value *Value,
- bool IsVirtual,
- const CXXRecordDecl *Derived,
- const CXXRecordDecl *Base);
-
+ /// complete class to the given direct base.
+ llvm::Value *
+ GetAddressOfDirectBaseInCompleteClass(llvm::Value *Value,
+ const CXXRecordDecl *Derived,
+ const CXXRecordDecl *Base,
+ bool BaseIsVirtual);
+
/// GetAddressOfBaseClass - This function will add the necessary delta to the
/// load of 'this' and returns address of the base class.
- llvm::Value *GetAddressOfBaseClass(llvm::Value *Value,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
+ llvm::Value *GetAddressOfBaseClass(llvm::Value *Value,
+ const CXXRecordDecl *Derived,
+ const CXXBaseSpecifierArray &BasePath,
bool NullCheckValue);
-
+
llvm::Value *GetAddressOfDerivedClass(llvm::Value *Value,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *DerivedClassDecl,
+ const CXXRecordDecl *Derived,
+ const CXXBaseSpecifierArray &BasePath,
bool NullCheckValue);
llvm::Value *GetVirtualBaseClassOffset(llvm::Value *This,
@@ -789,31 +804,17 @@ public:
void EmitClassAggrMemberwiseCopy(llvm::Value *DestValue,
llvm::Value *SrcValue,
- const ArrayType *Array,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty);
-
- void EmitClassAggrCopyAssignment(llvm::Value *DestValue,
- llvm::Value *SrcValue,
- const ArrayType *Array,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty);
+ const ConstantArrayType *Array,
+ const CXXRecordDecl *ClassDecl);
void EmitClassMemberwiseCopy(llvm::Value *DestValue, llvm::Value *SrcValue,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty);
-
- void EmitClassCopyAssignment(llvm::Value *DestValue, llvm::Value *SrcValue,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty);
+ const CXXRecordDecl *ClassDecl);
void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
CXXCtorType CtorType,
const FunctionArgList &Args);
void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
- llvm::Value *This,
+ bool ForVirtualBase, llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
@@ -842,7 +843,7 @@ public:
llvm::Value *This);
void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type,
- llvm::Value *This);
+ bool ForVirtualBase, llvm::Value *This);
void PushCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr);
void PopCXXTemporary();
@@ -1033,6 +1034,7 @@ public:
// Note: only availabe for agg return types
LValue EmitBinaryOperatorLValue(const BinaryOperator *E);
+ LValue EmitCompoundAssignOperatorLValue(const CompoundAssignOperator *E);
// Note: only available for agg return types
LValue EmitCallExprLValue(const CallExpr *E);
// Note: only available for agg return types
@@ -1100,7 +1102,8 @@ public:
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
const CallArgList &Args,
- const Decl *TargetDecl = 0);
+ const Decl *TargetDecl = 0,
+ llvm::Instruction **callOrInvoke = 0);
RValue EmitCall(QualType FnType, llvm::Value *Callee,
ReturnValueSlot ReturnValue,
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index a2ad31e..cc90a28 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -35,6 +35,7 @@
#include "llvm/LLVMContext.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Target/TargetData.h"
+#include "llvm/Support/CallSite.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
using namespace CodeGen;
@@ -47,7 +48,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M),
TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags),
Types(C, M, TD, getTargetCodeGenInfo().getABIInfo()),
- MangleCtx(C), VTables(*this), Runtime(0), CFConstantStringClassRef(0),
+ MangleCtx(C, diags), VTables(*this), Runtime(0),
+ CFConstantStringClassRef(0),
+ NSConstantStringClassRef(0),
VMContext(M.getContext()) {
if (!Features.ObjC1)
@@ -78,7 +81,6 @@ void CodeGenModule::createObjCRuntime() {
}
void CodeGenModule::Release() {
- EmitFundamentalRTTIDescriptors();
EmitDeferred();
EmitCXXGlobalInitFunc();
EmitCXXGlobalDtorFunc();
@@ -313,7 +315,18 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
if (FD->getTemplateSpecializationKind()
== TSK_ExplicitInstantiationDeclaration)
return CodeGenModule::GVA_C99Inline;
-
+
+ // If this is a virtual method and its class has a key method in another
+ // translation unit, we know that this method will be present in that
+ // translation unit. In this translation unit we will use this method
+ // only for inlining and analysis. This is the semantics of c99 inline.
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ const CXXRecordDecl *RD = MD->getParent();
+ if (MD->isVirtual() &&
+ CodeGenVTables::isKeyFunctionInAnotherTU(Context, RD))
+ return CodeGenModule::GVA_C99Inline;
+ }
+
return CodeGenModule::GVA_CXXInline;
}
@@ -491,11 +504,11 @@ void CodeGenModule::EmitDeferred() {
// previously unused static decl may become used during the generation of code
// for a static function, iterate until no changes are made.
- while (!DeferredDeclsToEmit.empty() || !DeferredVtables.empty()) {
- if (!DeferredVtables.empty()) {
- const CXXRecordDecl *RD = DeferredVtables.back();
- DeferredVtables.pop_back();
- getVTables().GenerateClassData(getVtableLinkage(RD), RD);
+ while (!DeferredDeclsToEmit.empty() || !DeferredVTables.empty()) {
+ if (!DeferredVTables.empty()) {
+ const CXXRecordDecl *RD = DeferredVTables.back();
+ DeferredVTables.pop_back();
+ getVTables().GenerateClassData(getVTableLinkage(RD), RD);
continue;
}
@@ -687,30 +700,30 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
// Defer code generation when possible if this is a static definition, inline
// function etc. These we only want to emit if they are used.
- if (MayDeferGeneration(Global)) {
- // If the value has already been used, add it directly to the
- // DeferredDeclsToEmit list.
- MangleBuffer MangledName;
- getMangledName(MangledName, GD);
- if (GetGlobalValue(MangledName))
- DeferredDeclsToEmit.push_back(GD);
- else {
- // Otherwise, remember that we saw a deferred decl with this name. The
- // first use of the mangled name will cause it to move into
- // DeferredDeclsToEmit.
- DeferredDecls[MangledName] = GD;
- }
+ if (!MayDeferGeneration(Global)) {
+ // Emit the definition if it can't be deferred.
+ EmitGlobalDefinition(GD);
return;
}
-
- // Otherwise emit the definition.
- EmitGlobalDefinition(GD);
+
+ // If the value has already been used, add it directly to the
+ // DeferredDeclsToEmit list.
+ MangleBuffer MangledName;
+ getMangledName(MangledName, GD);
+ if (GetGlobalValue(MangledName))
+ DeferredDeclsToEmit.push_back(GD);
+ else {
+ // Otherwise, remember that we saw a deferred decl with this name. The
+ // first use of the mangled name will cause it to move into
+ // DeferredDeclsToEmit.
+ DeferredDecls[MangledName] = GD;
+ }
}
void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
const ValueDecl *D = cast<ValueDecl>(GD.getDecl());
- PrettyStackTraceDecl CrashInfo((ValueDecl *)D, D->getLocation(),
+ PrettyStackTraceDecl CrashInfo(const_cast<ValueDecl *>(D), D->getLocation(),
Context.getSourceManager(),
"Generating code for declaration");
@@ -718,16 +731,18 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
getVTables().EmitVTableRelatedData(GD);
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
- EmitCXXConstructor(CD, GD.getCtorType());
- else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D))
- EmitCXXDestructor(DD, GD.getDtorType());
- else if (isa<FunctionDecl>(D))
- EmitGlobalFunctionDefinition(GD);
- else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
- EmitGlobalVarDefinition(VD);
- else {
- assert(0 && "Invalid argument to EmitGlobalDefinition()");
- }
+ return EmitCXXConstructor(CD, GD.getCtorType());
+
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D))
+ return EmitCXXDestructor(DD, GD.getDtorType());
+
+ if (isa<FunctionDecl>(D))
+ return EmitGlobalFunctionDefinition(GD);
+
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ return EmitGlobalVarDefinition(VD);
+
+ assert(0 && "Invalid argument to EmitGlobalDefinition()");
}
/// GetOrCreateLLVMFunction - If the specified mangled name is not in the
@@ -764,12 +779,16 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
// type is an incomplete struct). Use a fake type instead, and make
// sure not to try to set attributes.
bool IsIncompleteFunction = false;
- if (!isa<llvm::FunctionType>(Ty)) {
- Ty = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- std::vector<const llvm::Type*>(), false);
+
+ const llvm::FunctionType *FTy;
+ if (isa<llvm::FunctionType>(Ty)) {
+ FTy = cast<llvm::FunctionType>(Ty);
+ } else {
+ FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ std::vector<const llvm::Type*>(), false);
IsIncompleteFunction = true;
}
- llvm::Function *F = llvm::Function::Create(cast<llvm::FunctionType>(Ty),
+ llvm::Function *F = llvm::Function::Create(FTy,
llvm::Function::ExternalLinkage,
MangledName, &getModule());
assert(F->getName() == MangledName && "name was uniqued!");
@@ -811,7 +830,14 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
}
}
- return F;
+ // Make sure the result is of the requested type.
+ if (!IsIncompleteFunction) {
+ assert(F->getType()->getElementType() == Ty);
+ return F;
+ }
+
+ const llvm::Type *PTy = llvm::PointerType::getUnqual(Ty);
+ return llvm::ConstantExpr::getBitCast(F, PTy);
}
/// GetAddrOfFunction - Return the address of the given function. If Ty is
@@ -959,7 +985,7 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
}
llvm::GlobalVariable::LinkageTypes
-CodeGenModule::getVtableLinkage(const CXXRecordDecl *RD) {
+CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
return llvm::GlobalVariable::InternalLinkage;
@@ -1204,9 +1230,10 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
for (llvm::Value::use_iterator UI = OldFn->use_begin(), E = OldFn->use_end();
UI != E; ) {
// TODO: Do invokes ever occur in C code? If so, we should handle them too.
- unsigned OpNo = UI.getOperandNo();
- llvm::CallInst *CI = dyn_cast<llvm::CallInst>(*UI++);
- if (!CI || OpNo != 0) continue;
+ llvm::Value::use_iterator I = UI++; // Increment before the CI is erased.
+ llvm::CallInst *CI = dyn_cast<llvm::CallInst>(*I);
+ llvm::CallSite CS(CI);
+ if (!CI || !CS.isCallee(I)) continue;
// If the return types don't match exactly, and if the call isn't dead, then
// we can't transform this call.
@@ -1220,8 +1247,8 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
bool DontTransform = false;
for (llvm::Function::arg_iterator AI = NewFn->arg_begin(),
E = NewFn->arg_end(); AI != E; ++AI, ++ArgNo) {
- if (CI->getNumOperands()-1 == ArgNo ||
- CI->getOperand(ArgNo+1)->getType() != AI->getType()) {
+ if (CS.arg_size() == ArgNo ||
+ CS.getArgument(ArgNo)->getType() != AI->getType()) {
DontTransform = true;
break;
}
@@ -1231,7 +1258,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
// Okay, we can transform this. Create the new call instruction and copy
// over the required information.
- ArgList.append(CI->op_begin()+1, CI->op_begin()+1+ArgNo);
+ ArgList.append(CS.arg_begin(), CS.arg_begin() + ArgNo);
llvm::CallInst *NewCall = llvm::CallInst::Create(NewFn, ArgList.begin(),
ArgList.end(), "", CI);
ArgList.clear();
@@ -1578,6 +1605,90 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
return GV;
}
+llvm::Constant *
+CodeGenModule::GetAddrOfConstantNSString(const StringLiteral *Literal) {
+ unsigned StringLength = 0;
+ bool isUTF16 = false;
+ llvm::StringMapEntry<llvm::Constant*> &Entry =
+ GetConstantCFStringEntry(CFConstantStringMap, Literal,
+ getTargetData().isLittleEndian(),
+ isUTF16, StringLength);
+
+ if (llvm::Constant *C = Entry.getValue())
+ return C;
+
+ llvm::Constant *Zero =
+ llvm::Constant::getNullValue(llvm::Type::getInt32Ty(VMContext));
+ llvm::Constant *Zeros[] = { Zero, Zero };
+
+ // If we don't already have it, get _NSConstantStringClassReference.
+ if (!NSConstantStringClassRef) {
+ const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
+ Ty = llvm::ArrayType::get(Ty, 0);
+ llvm::Constant *GV = CreateRuntimeVariable(Ty,
+ Features.ObjCNonFragileABI ?
+ "OBJC_CLASS_$_NSConstantString" :
+ "_NSConstantStringClassReference");
+ // Decay array -> ptr
+ NSConstantStringClassRef =
+ llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
+ }
+
+ QualType NSTy = getContext().getNSConstantStringType();
+
+ const llvm::StructType *STy =
+ cast<llvm::StructType>(getTypes().ConvertType(NSTy));
+
+ std::vector<llvm::Constant*> Fields(3);
+
+ // Class pointer.
+ Fields[0] = NSConstantStringClassRef;
+
+ // String pointer.
+ llvm::Constant *C = llvm::ConstantArray::get(VMContext, Entry.getKey().str());
+
+ llvm::GlobalValue::LinkageTypes Linkage;
+ bool isConstant;
+ if (isUTF16) {
+ // FIXME: why do utf strings get "_" labels instead of "L" labels?
+ Linkage = llvm::GlobalValue::InternalLinkage;
+ // Note: -fwritable-strings doesn't make unicode NSStrings writable, but
+ // does make plain ascii ones writable.
+ isConstant = true;
+ } else {
+ Linkage = llvm::GlobalValue::PrivateLinkage;
+ isConstant = !Features.WritableStrings;
+ }
+
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C,
+ ".str");
+ if (isUTF16) {
+ CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy);
+ GV->setAlignment(Align.getQuantity());
+ }
+ Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
+
+ // String length.
+ const llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy);
+ Fields[2] = llvm::ConstantInt::get(Ty, StringLength);
+
+ // The struct.
+ C = llvm::ConstantStruct::get(STy, Fields);
+ GV = new llvm::GlobalVariable(getModule(), C->getType(), true,
+ llvm::GlobalVariable::PrivateLinkage, C,
+ "_unnamed_nsstring_");
+ // FIXME. Fix section.
+ if (const char *Sect =
+ Features.ObjCNonFragileABI
+ ? getContext().Target.getNSStringNonFragileABISection()
+ : getContext().Target.getNSStringSection())
+ GV->setSection(Sect);
+ Entry.setValue(GV);
+
+ return GV;
+}
+
/// GetStringForStringLiteral - Return the appropriate bytes for a
/// string literal, properly padded to match the literal type.
std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) {
@@ -1709,6 +1820,39 @@ void CodeGenModule::EmitObjCPropertyImplementations(const
}
}
+/// EmitObjCIvarInitializations - Emit information for ivar initialization
+/// for an implementation.
+void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
+ if (!Features.NeXTRuntime || D->getNumIvarInitializers() == 0)
+ return;
+ DeclContext* DC = const_cast<DeclContext*>(dyn_cast<DeclContext>(D));
+ assert(DC && "EmitObjCIvarInitializations - null DeclContext");
+ IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct");
+ Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
+ ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create(getContext(),
+ D->getLocation(),
+ D->getLocation(), cxxSelector,
+ getContext().VoidTy, 0,
+ DC, true, false, true,
+ ObjCMethodDecl::Required);
+ D->addInstanceMethod(DTORMethod);
+ CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
+
+ II = &getContext().Idents.get(".cxx_construct");
+ cxxSelector = getContext().Selectors.getSelector(0, &II);
+ // The constructor returns 'self'.
+ ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(),
+ D->getLocation(),
+ D->getLocation(), cxxSelector,
+ getContext().getObjCIdType(), 0,
+ DC, true, false, true,
+ ObjCMethodDecl::Required);
+ D->addInstanceMethod(CTORMethod);
+ CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
+
+
+}
+
/// EmitNamespace - Emit all declarations in a namespace.
void CodeGenModule::EmitNamespace(const NamespaceDecl *ND) {
for (RecordDecl::decl_iterator I = ND->decls_begin(), E = ND->decls_end();
@@ -1805,6 +1949,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::ObjCImplementation: {
ObjCImplementationDecl *OMD = cast<ObjCImplementationDecl>(D);
EmitObjCPropertyImplementations(OMD);
+ EmitObjCIvarInitializations(OMD);
Runtime->GenerateClass(OMD);
break;
}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index e9f78bc..93d8ddf 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -21,7 +21,7 @@
#include "CGBlocks.h"
#include "CGCall.h"
#include "CGCXX.h"
-#include "CGVtable.h"
+#include "CGVTables.h"
#include "CodeGenTypes.h"
#include "GlobalDecl.h"
#include "Mangle.h"
@@ -94,7 +94,8 @@ class CodeGenModule : public BlockModule {
/// VTables - Holds information about C++ vtables.
CodeGenVTables VTables;
-
+ friend class CodeGenVTables;
+
CGObjCRuntime* Runtime;
CGDebugInfo* DebugInfo;
@@ -132,6 +133,7 @@ class CodeGenModule : public BlockModule {
llvm::StringMap<llvm::Constant*> CFConstantStringMap;
llvm::StringMap<llvm::Constant*> ConstantStringMap;
+ llvm::DenseMap<const Decl*, llvm::Value*> StaticLocalDeclMap;
/// CXXGlobalInits - Global variables with initializers that need to run
/// before main.
@@ -145,6 +147,10 @@ class CodeGenModule : public BlockModule {
/// strings. This value has type int * but is actually an Obj-C class pointer.
llvm::Constant *CFConstantStringClassRef;
+ /// NSConstantStringClassRef - Cached reference to the class for constant
+ /// strings. This value has type int * but is actually an Obj-C class pointer.
+ llvm::Constant *NSConstantStringClassRef;
+
/// Lazily create the Objective-C runtime
void createObjCRuntime();
@@ -169,6 +175,14 @@ public:
/// been configured.
bool hasObjCRuntime() { return !!Runtime; }
+ llvm::Value *getStaticLocalDeclAddress(const VarDecl *VD) {
+ return StaticLocalDeclMap[VD];
+ }
+ void setStaticLocalDeclAddress(const VarDecl *D,
+ llvm::GlobalVariable *GV) {
+ StaticLocalDeclMap[D] = GV;
+ }
+
CGDebugInfo *getDebugInfo() { return DebugInfo; }
ASTContext &getContext() const { return Context; }
const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
@@ -218,7 +232,7 @@ public:
/// GetAddrOfRTTIDescriptor - Get the address of the RTTI descriptor
/// for the given type.
- llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty);
+ llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false);
/// GetAddrOfThunk - Get the address of the thunk for the given global decl.
llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk);
@@ -227,11 +241,11 @@ public:
llvm::Constant *GetWeakRefReference(const ValueDecl *VD);
/// GetNonVirtualBaseClassOffset - Returns the offset from a derived class to
- /// its base class. Returns null if the offset is 0.
+ /// a class. Returns null if the offset is 0.
llvm::Constant *
GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl);
-
+ const CXXBaseSpecifierArray &BasePath);
+
/// GetStringForStringLiteral - Return the appropriate bytes for a string
/// literal, properly padded to match the literal type. If only the address of
/// a constant is needed consider using GetAddrOfConstantStringLiteral.
@@ -240,6 +254,10 @@ public:
/// GetAddrOfConstantCFString - Return a pointer to a constant CFString object
/// for the given string.
llvm::Constant *GetAddrOfConstantCFString(const StringLiteral *Literal);
+
+ /// GetAddrOfConstantNSString - Return a pointer to a constant NSString object
+ /// for the given string.
+ llvm::Constant *GetAddrOfConstantNSString(const StringLiteral *Literal);
/// GetAddrOfConstantStringFromLiteral - Return a pointer to a constant array
/// for the given string literal.
@@ -416,16 +434,16 @@ public:
llvm::GlobalVariable::LinkageTypes
getFunctionLinkage(const FunctionDecl *FD);
- /// getVtableLinkage - Return the appropriate linkage for the vtable, VTT,
+ /// getVTableLinkage - Return the appropriate linkage for the vtable, VTT,
/// and type information of the given class.
static llvm::GlobalVariable::LinkageTypes
- getVtableLinkage(const CXXRecordDecl *RD);
+ getVTableLinkage(const CXXRecordDecl *RD);
/// GetTargetTypeStoreSize - Return the store size, in character units, of
/// the given LLVM type.
CharUnits GetTargetTypeStoreSize(const llvm::Type *Ty) const;
- std::vector<const CXXRecordDecl*> DeferredVtables;
+ std::vector<const CXXRecordDecl*> DeferredVTables;
private:
llvm::GlobalValue *GetGlobalValue(llvm::StringRef Ref);
@@ -464,6 +482,7 @@ private:
void EmitGlobalVarDefinition(const VarDecl *D);
void EmitAliasDefinition(GlobalDecl GD);
void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
+ void EmitObjCIvarInitializations(ObjCImplementationDecl *D);
// C++ related functions.
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 9b74106d..10e71e2 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -52,7 +52,6 @@ namespace clang {
namespace CodeGen {
class CGRecordLayout;
- class CodeGenTypes;
/// CodeGenTypes - This class organizes the cross-module state that is used
/// while lowering AST types to LLVM types.
@@ -124,10 +123,10 @@ public:
const llvm::FunctionType *GetFunctionType(GlobalDecl GD);
- /// GetFunctionTypeForVtable - Get the LLVM function type for use in a vtable,
+ /// GetFunctionTypeForVTable - Get the LLVM function type for use in a vtable,
/// given a CXXMethodDecl. If the method to has an incomplete return type,
/// and/or incomplete argument types, this will return the opaque type.
- const llvm::Type *GetFunctionTypeForVtable(const CXXMethodDecl *MD);
+ const llvm::Type *GetFunctionTypeForVTable(const CXXMethodDecl *MD);
const CGRecordLayout &getCGRecordLayout(const RecordDecl*) const;
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index 077db7c..8658cfb 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -25,7 +25,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
-#include "CGVtable.h"
+#include "CGVTables.h"
#define MANGLE_CHECKER 0
@@ -111,6 +111,7 @@ public:
private:
bool mangleSubstitution(const NamedDecl *ND);
bool mangleSubstitution(QualType T);
+ bool mangleSubstitution(TemplateName Template);
bool mangleSubstitution(uintptr_t Ptr);
bool mangleStandardSubstitution(const NamedDecl *ND);
@@ -121,6 +122,7 @@ private:
addSubstitution(reinterpret_cast<uintptr_t>(ND));
}
void addSubstitution(QualType T);
+ void addSubstitution(TemplateName Template);
void addSubstitution(uintptr_t Ptr);
void mangleUnresolvedScope(NestedNameSpecifier *Qualifier);
@@ -138,6 +140,7 @@ private:
unsigned KnownArity);
void mangleUnscopedName(const NamedDecl *ND);
void mangleUnscopedTemplateName(const TemplateDecl *ND);
+ void mangleUnscopedTemplateName(TemplateName);
void mangleSourceName(const IdentifierInfo *II);
void mangleLocalName(const NamedDecl *ND);
void mangleNestedName(const NamedDecl *ND, const DeclContext *DC,
@@ -147,6 +150,7 @@ private:
unsigned NumTemplateArgs);
void manglePrefix(const DeclContext *DC, bool NoFunction=false);
void mangleTemplatePrefix(const TemplateDecl *ND);
+ void mangleTemplatePrefix(TemplateName Template);
void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
void mangleQualifiers(Qualifiers Quals);
@@ -172,6 +176,9 @@ private:
void mangleCXXCtorType(CXXCtorType T);
void mangleCXXDtorType(CXXDtorType T);
+ void mangleTemplateArgs(TemplateName Template,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
void mangleTemplateArgs(const TemplateParameterList &PL,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
@@ -306,8 +313,6 @@ static bool isStd(const NamespaceDecl *NS) {
static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
while (isa<LinkageSpecDecl>(DC)) {
- assert(cast<LinkageSpecDecl>(DC)->getLanguage() ==
- LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!");
DC = DC->getParent();
}
@@ -429,6 +434,31 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) {
addSubstitution(ND);
}
+void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) {
+ // <unscoped-template-name> ::= <unscoped-name>
+ // ::= <substitution>
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return mangleUnscopedTemplateName(TD);
+
+ if (mangleSubstitution(Template))
+ return;
+
+ // FIXME: How to cope with operators here?
+ DependentTemplateName *Dependent = Template.getAsDependentTemplateName();
+ assert(Dependent && "Not a dependent template name?");
+ if (!Dependent->isIdentifier()) {
+ // FIXME: We can't possibly know the arity of the operator here!
+ Diagnostic &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
+ "cannot mangle dependent operator name");
+ Diags.Report(FullSourceLoc(), DiagID);
+ return;
+ }
+
+ mangleSourceName(Dependent->getIdentifier());
+ addSubstitution(Template);
+}
+
void CXXNameMangler::mangleNumber(int64_t Number) {
// <number> ::= [n] <non-negative decimal integer>
if (Number < 0) {
@@ -475,11 +505,12 @@ void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) {
if (const TemplateSpecializationType *TST =
dyn_cast<TemplateSpecializationType>(QTy)) {
if (!mangleSubstitution(QualType(TST, 0))) {
- TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
- assert(TD && "FIXME: Support dependent template names");
- mangleTemplatePrefix(TD);
- TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
- mangleTemplateArgs(*TemplateParameters, TST->getArgs(),
+ mangleTemplatePrefix(TST->getTemplateName());
+
+ // FIXME: GCC does not appear to mangle the template arguments when
+ // the template in question is a dependent template name. Should we
+ // emulate that badness?
+ mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(),
TST->getNumArgs());
addSubstitution(QualType(TST, 0));
}
@@ -741,6 +772,29 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
addSubstitution(cast<NamedDecl>(DC));
}
+void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
+ // <template-prefix> ::= <prefix> <template unqualified-name>
+ // ::= <template-param>
+ // ::= <substitution>
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return mangleTemplatePrefix(TD);
+
+ if (QualifiedTemplateName *Qualified = Template.getAsQualifiedTemplateName())
+ mangleUnresolvedScope(Qualified->getQualifier());
+
+ if (OverloadedTemplateStorage *Overloaded
+ = Template.getAsOverloadedTemplate()) {
+ mangleUnqualifiedName(0, (*Overloaded->begin())->getDeclName(),
+ UnknownArity);
+ return;
+ }
+
+ DependentTemplateName *Dependent = Template.getAsDependentTemplateName();
+ assert(Dependent && "Unknown template name kind?");
+ mangleUnresolvedScope(Dependent->getQualifier());
+ mangleUnscopedTemplateName(Template);
+}
+
void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
// <template-prefix> ::= <prefix> <template unqualified-name>
// ::= <template-param>
@@ -896,7 +950,7 @@ void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
assert (CD && "Missing container decl in GetNameForMethod");
OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName();
if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD))
- OS << '(' << CID->getNameAsString() << ')';
+ OS << '(' << CID << ')';
OS << ' ' << MD->getSelector().getAsString() << ']';
Out << OS.str().size() << OS.str();
@@ -1157,18 +1211,50 @@ void CXXNameMangler::mangleType(const BlockPointerType *T) {
mangleType(T->getPointeeType());
}
-void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
- TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl();
- assert(TD && "FIXME: Support dependent template names!");
+void CXXNameMangler::mangleType(const InjectedClassNameType *T) {
+ // Mangle injected class name types as if the user had written the
+ // specialization out fully. It may not actually be possible to see
+ // this mangling, though.
+ mangleType(T->getInjectedSpecializationType());
+}
- mangleName(TD, T->getArgs(), T->getNumArgs());
+void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
+ if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) {
+ mangleName(TD, T->getArgs(), T->getNumArgs());
+ } else {
+ if (mangleSubstitution(QualType(T, 0)))
+ return;
+
+ mangleTemplatePrefix(T->getTemplateName());
+
+ // FIXME: GCC does not appear to mangle the template arguments when
+ // the template in question is a dependent template name. Should we
+ // emulate that badness?
+ mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs());
+ addSubstitution(QualType(T, 0));
+ }
}
void CXXNameMangler::mangleType(const DependentNameType *T) {
// Typename types are always nested
Out << 'N';
- mangleUnresolvedScope(T->getQualifier());
- mangleSourceName(T->getIdentifier());
+ if (T->getIdentifier()) {
+ mangleUnresolvedScope(T->getQualifier());
+ mangleSourceName(T->getIdentifier());
+ } else {
+ const TemplateSpecializationType *TST = T->getTemplateId();
+ if (!mangleSubstitution(QualType(TST, 0))) {
+ mangleTemplatePrefix(TST->getTemplateName());
+
+ // FIXME: GCC does not appear to mangle the template arguments when
+ // the template in question is a dependent template name. Should we
+ // emulate that badness?
+ mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(),
+ TST->getNumArgs());
+ addSubstitution(QualType(TST, 0));
+ }
+ }
+
Out << 'E';
}
@@ -1279,17 +1365,33 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
// ::= L <type <value float> E # floating literal
// ::= L <mangled-name> E # external name
switch (E->getStmtClass()) {
- default:
+ case Expr::NoStmtClass:
+#define EXPR(Type, Base)
+#define STMT(Type, Base) \
+ case Expr::Type##Class:
+#include "clang/AST/StmtNodes.def"
llvm_unreachable("unexpected statement kind");
break;
+ default: {
+ // As bad as this diagnostic is, it's better than crashing.
+ Diagnostic &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
+ "cannot yet mangle expression type %0");
+ Diags.Report(FullSourceLoc(E->getExprLoc(),
+ getASTContext().getSourceManager()),
+ DiagID)
+ << E->getStmtClassName() << E->getSourceRange();
+ break;
+ }
+
case Expr::CallExprClass: {
const CallExpr *CE = cast<CallExpr>(E);
Out << "cl";
mangleCalledExpression(CE->getCallee(), CE->getNumArgs());
for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I)
mangleExpression(CE->getArg(I));
- Out << "E";
+ Out << 'E';
break;
}
@@ -1333,9 +1435,9 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
Out << "cv";
mangleType(CE->getType());
- if (N != 1) Out << "_";
+ if (N != 1) Out << '_';
for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
- if (N != 1) Out << "E";
+ if (N != 1) Out << 'E';
break;
}
@@ -1346,21 +1448,21 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
Out << "cv";
mangleType(CE->getType());
- if (N != 1) Out << "_";
+ if (N != 1) Out << '_';
for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
- if (N != 1) Out << "E";
+ if (N != 1) Out << 'E';
break;
}
case Expr::SizeOfAlignOfExprClass: {
const SizeOfAlignOfExpr *SAE = cast<SizeOfAlignOfExpr>(E);
- if (SAE->isSizeOf()) Out << "s";
- else Out << "a";
+ if (SAE->isSizeOf()) Out << 's';
+ else Out << 'a';
if (SAE->isArgumentType()) {
- Out << "t";
+ Out << 't';
mangleType(SAE->getArgumentType());
} else {
- Out << "z";
+ Out << 'z';
mangleExpression(SAE->getArgumentExpr());
}
break;
@@ -1474,9 +1576,21 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
break;
}
+ case Expr::CXXBindReferenceExprClass:
+ mangleExpression(cast<CXXBindReferenceExpr>(E)->getSubExpr());
+ break;
+
+ case Expr::CXXBindTemporaryExprClass:
+ mangleExpression(cast<CXXBindTemporaryExpr>(E)->getSubExpr());
+ break;
+
+ case Expr::CXXExprWithTemporariesClass:
+ mangleExpression(cast<CXXExprWithTemporaries>(E)->getSubExpr());
+ break;
+
case Expr::FloatingLiteralClass: {
const FloatingLiteral *FL = cast<FloatingLiteral>(E);
- Out << "L";
+ Out << 'L';
mangleType(FL->getType());
// TODO: avoid this copy with careful stream management.
@@ -1484,10 +1598,23 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
FL->getValue().bitcastToAPInt().toString(Buffer, 16, false);
Out.write(Buffer.data(), Buffer.size());
- Out << "E";
+ Out << 'E';
break;
}
+ case Expr::CharacterLiteralClass:
+ Out << 'L';
+ mangleType(E->getType());
+ Out << cast<CharacterLiteral>(E)->getValue();
+ Out << 'E';
+ break;
+
+ case Expr::CXXBoolLiteralExprClass:
+ Out << "Lb";
+ Out << (cast<CXXBoolLiteralExpr>(E)->getValue() ? '1' : '0');
+ Out << 'E';
+ break;
+
case Expr::IntegerLiteralClass:
mangleIntegerLiteral(E->getType(),
llvm::APSInt(cast<IntegerLiteral>(E)->getValue()));
@@ -1535,23 +1662,37 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
}
}
+void CXXNameMangler::mangleTemplateArgs(TemplateName Template,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return mangleTemplateArgs(*TD->getTemplateParameters(), TemplateArgs,
+ NumTemplateArgs);
+
+ // <template-args> ::= I <template-arg>+ E
+ Out << 'I';
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ mangleTemplateArg(0, TemplateArgs[i]);
+ Out << 'E';
+}
+
void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL,
const TemplateArgumentList &AL) {
// <template-args> ::= I <template-arg>+ E
- Out << "I";
+ Out << 'I';
for (unsigned i = 0, e = AL.size(); i != e; ++i)
mangleTemplateArg(PL.getParam(i), AL[i]);
- Out << "E";
+ Out << 'E';
}
void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
// <template-args> ::= I <template-arg>+ E
- Out << "I";
+ Out << 'I';
for (unsigned i = 0; i != NumTemplateArgs; ++i)
mangleTemplateArg(PL.getParam(i), TemplateArgs[i]);
- Out << "E";
+ Out << 'E';
}
void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
@@ -1569,7 +1710,7 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
break;
case TemplateArgument::Template:
assert(A.getAsTemplate().getAsTemplateDecl() &&
- "FIXME: Support dependent template names");
+ "Can't get dependent template names here");
mangleName(A.getAsTemplate().getAsTemplateDecl());
break;
case TemplateArgument::Expression:
@@ -1581,6 +1722,7 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
mangleIntegerLiteral(A.getIntegralType(), *A.getAsIntegral());
break;
case TemplateArgument::Declaration: {
+ assert(P && "Missing template parameter for declaration argument");
// <expr-primary> ::= L <mangled-name> E # external name
// Clang produces AST's where pointer-to-member-function expressions
@@ -1646,9 +1788,17 @@ bool CXXNameMangler::mangleSubstitution(QualType T) {
return mangleSubstitution(TypePtr);
}
+bool CXXNameMangler::mangleSubstitution(TemplateName Template) {
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return mangleSubstitution(TD);
+
+ Template = Context.getASTContext().getCanonicalTemplateName(Template);
+ return mangleSubstitution(
+ reinterpret_cast<uintptr_t>(Template.getAsVoidPointer()));
+}
+
bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
- llvm::DenseMap<uintptr_t, unsigned>::iterator I =
- Substitutions.find(Ptr);
+ llvm::DenseMap<uintptr_t, unsigned>::iterator I = Substitutions.find(Ptr);
if (I == Substitutions.end())
return false;
@@ -1660,9 +1810,8 @@ bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
// <seq-id> is encoded in base-36, using digits and upper case letters.
char Buffer[10];
- char *BufferPtr = Buffer + 9;
+ char *BufferPtr = llvm::array_endof(Buffer);
- *BufferPtr = 0;
if (SeqID == 0) *--BufferPtr = '0';
while (SeqID) {
@@ -1674,7 +1823,9 @@ bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
SeqID /= 36;
}
- Out << 'S' << BufferPtr << '_';
+ Out << 'S'
+ << llvm::StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr)
+ << '_';
}
return true;
@@ -1824,6 +1975,14 @@ void CXXNameMangler::addSubstitution(QualType T) {
addSubstitution(TypePtr);
}
+void CXXNameMangler::addSubstitution(TemplateName Template) {
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return addSubstitution(TD);
+
+ Template = Context.getASTContext().getCanonicalTemplateName(Template);
+ addSubstitution(reinterpret_cast<uintptr_t>(Template.getAsVoidPointer()));
+}
+
void CXXNameMangler::addSubstitution(uintptr_t Ptr) {
unsigned SeqID = Substitutions.size();
@@ -1925,7 +2084,7 @@ void MangleContext::mangleGuardVariable(const VarDecl *D,
Mangler.mangleName(D);
}
-void MangleContext::mangleCXXVtable(const CXXRecordDecl *RD,
+void MangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
llvm::SmallVectorImpl<char> &Res) {
// <special-name> ::= TV <type> # virtual table
CXXNameMangler Mangler(*this, Res);
@@ -1941,7 +2100,7 @@ void MangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
Mangler.mangleName(RD);
}
-void MangleContext::mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
+void MangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
const CXXRecordDecl *Type,
llvm::SmallVectorImpl<char> &Res) {
// <special-name> ::= TC <type> <offset number> _ <base type>
@@ -1949,7 +2108,7 @@ void MangleContext::mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
Mangler.getStream() << "_ZTC";
Mangler.mangleName(RD);
Mangler.getStream() << Offset;
- Mangler.getStream() << "_";
+ Mangler.getStream() << '_';
Mangler.mangleName(Type);
}
diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h
index 91a5e97..da3626f 100644
--- a/lib/CodeGen/Mangle.h
+++ b/lib/CodeGen/Mangle.h
@@ -68,17 +68,21 @@ private:
/// calls to the C++ name mangler.
class MangleContext {
ASTContext &Context;
+ Diagnostic &Diags;
llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
unsigned Discriminator;
llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
public:
- explicit MangleContext(ASTContext &Context)
- : Context(Context) { }
+ explicit MangleContext(ASTContext &Context,
+ Diagnostic &Diags)
+ : Context(Context), Diags(Diags) { }
ASTContext &getASTContext() const { return Context; }
+ Diagnostic &getDiags() const { return Diags; }
+
uint64_t getAnonymousStructId(const TagDecl *TD) {
std::pair<llvm::DenseMap<const TagDecl *,
uint64_t>::iterator, bool> Result =
@@ -99,9 +103,9 @@ public:
const ThisAdjustment &ThisAdjustment,
llvm::SmallVectorImpl<char> &);
void mangleGuardVariable(const VarDecl *D, llvm::SmallVectorImpl<char> &);
- void mangleCXXVtable(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
+ void mangleCXXVTable(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
void mangleCXXVTT(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
- void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
+ void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
const CXXRecordDecl *Type,
llvm::SmallVectorImpl<char> &);
void mangleCXXRTTI(QualType T, llvm::SmallVectorImpl<char> &);
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 59e8e77..e1fdf86 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -43,7 +43,8 @@ void ABIArgInfo::dump() const {
getCoerceToType()->print(OS);
break;
case Indirect:
- OS << "Indirect Align=" << getIndirectAlign();
+ OS << "Indirect Align=" << getIndirectAlign()
+ << " Byal=" << getIndirectByVal();
break;
case Expand:
OS << "Expand";
@@ -270,7 +271,7 @@ ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty,
llvm::LLVMContext &VMContext) const {
if (CodeGenFunction::hasAggregateLLVMType(Ty))
return ABIArgInfo::getIndirect(0);
-
+
// Treat an enum type as its underlying type.
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
Ty = EnumTy->getDecl()->getIntegerType();
@@ -291,8 +292,10 @@ class X86_32ABIInfo : public ABIInfo {
static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context);
- static unsigned getIndirectArgumentAlignment(QualType Ty,
- ASTContext &Context);
+ /// 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,
+ bool ByVal = true) const;
public:
ABIArgInfo classifyReturnType(QualType RetTy,
@@ -490,14 +493,19 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
}
}
-unsigned X86_32ABIInfo::getIndirectArgumentAlignment(QualType Ty,
- ASTContext &Context) {
- unsigned Align = Context.getTypeAlign(Ty);
- if (Align < 128) return 0;
- if (const RecordType* RT = Ty->getAs<RecordType>())
- if (typeContainsSSEVector(RT->getDecl(), Context))
- return 16;
- return 0;
+ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty,
+ ASTContext &Context,
+ bool ByVal) const {
+ if (!ByVal)
+ return ABIArgInfo::getIndirect(0, false);
+
+ // Compute the byval alignment. We trust the back-end to honor the
+ // minimum ABI alignment for byval, to make cleaner IR.
+ const unsigned MinABIAlign = 4;
+ unsigned Align = Context.getTypeAlign(Ty) / 8;
+ if (Align > MinABIAlign)
+ return ABIArgInfo::getIndirect(Align);
+ return ABIArgInfo::getIndirect(0);
}
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
@@ -510,11 +518,10 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
// 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);
-
+ return getIndirectResult(Ty, Context, /*ByVal=*/false);
+
if (RT->getDecl()->hasFlexibleArrayMember())
- return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty,
- Context));
+ return getIndirectResult(Ty, Context);
}
// Ignore empty structs.
@@ -529,7 +536,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
canExpandIndirectArgument(Ty, Context))
return ABIArgInfo::getExpand();
- return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context));
+ return getIndirectResult(Ty, Context);
} else {
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
Ty = EnumTy->getDecl()->getIntegerType();
@@ -685,9 +692,12 @@ class X86_64ABIInfo : public ABIInfo {
ASTContext &Context) const;
/// getIndirectResult - Give a source type \arg Ty, return a suitable result
+ /// such that the argument will be returned in memory.
+ ABIArgInfo getIndirectReturnResult(QualType Ty, 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 getIndirectResult(QualType Ty, ASTContext &Context) const;
ABIArgInfo classifyReturnType(QualType RetTy,
ASTContext &Context,
@@ -1060,6 +1070,22 @@ ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty,
return ABIArgInfo::getCoerce(CoerceTo);
}
+ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(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)) {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+
+ return ABIArgInfo::getIndirect(0);
+}
+
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
@@ -1073,10 +1099,16 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
- bool ByVal = !isRecordWithNonTrivialDestructorOrCopyConstructor(Ty);
+ if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
- // FIXME: Set alignment correctly.
- return ABIArgInfo::getIndirect(0, ByVal);
+ // Compute the byval alignment. We trust the back-end to honor the
+ // minimum ABI alignment for byval, to make cleaner IR.
+ const unsigned MinABIAlign = 8;
+ unsigned Align = Context.getTypeAlign(Ty) / 8;
+ if (Align > MinABIAlign)
+ return ABIArgInfo::getIndirect(Align);
+ return ABIArgInfo::getIndirect(0);
}
ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
@@ -1104,7 +1136,7 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
// AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via
// hidden argument.
case Memory:
- return getIndirectResult(RetTy, Context);
+ return getIndirectReturnResult(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.
@@ -1126,7 +1158,8 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
// %st1.
case ComplexX87:
assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification.");
- ResType = llvm::StructType::get(VMContext, llvm::Type::getX86_FP80Ty(VMContext),
+ ResType = llvm::StructType::get(VMContext,
+ llvm::Type::getX86_FP80Ty(VMContext),
llvm::Type::getX86_FP80Ty(VMContext),
NULL);
break;
@@ -1574,7 +1607,7 @@ ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty,
llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
- const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(CGF.getLLVMContext()));
+ const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
const llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
CGBuilderTy &Builder = CGF.Builder;
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 921147f..7371a93 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -239,12 +239,8 @@ int Driver::ExecuteCompilation(const Compilation &C) const {
// other tools are less common, and they generally have worse diagnostics,
// so always print the diagnostic there.
const Action &Source = FailingCommand->getSource();
- bool IsFriendlyTool = (isa<PreprocessJobAction>(Source) ||
- isa<PrecompileJobAction>(Source) ||
- isa<AnalyzeJobAction>(Source) ||
- isa<CompileJobAction>(Source));
- if (!IsFriendlyTool || Res != 1) {
+ if (!FailingCommand->getCreator().hasGoodDiagnostics() || Res != 1) {
// FIXME: See FIXME above regarding result code interpretation.
if (Res < 0)
Diag(clang::diag::err_drv_command_signalled)
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 105eab0..1cd8ee1 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -217,6 +217,8 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const {
void DarwinGCC::AddLinkSearchPathArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
+ std::string Tmp;
+
// FIXME: Derive these correctly.
if (getArchName() == "x86_64") {
CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
@@ -225,10 +227,24 @@ void DarwinGCC::AddLinkSearchPathArgs(const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
"/x86_64"));
}
+
CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/" + ToolChainDir));
+
+ Tmp = getDriver().Dir + "/../lib/gcc/" + ToolChainDir;
+ if (llvm::sys::Path(Tmp).exists())
+ CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));
+ Tmp = getDriver().Dir + "/../lib/gcc";
+ if (llvm::sys::Path(Tmp).exists())
+ CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));
CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir));
// Intentionally duplicated for (temporary) gcc bug compatibility.
CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir));
+ Tmp = getDriver().Dir + "/../lib/" + ToolChainDir;
+ if (llvm::sys::Path(Tmp).exists())
+ CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));
+ Tmp = getDriver().Dir + "/../lib";
+ if (llvm::sys::Path(Tmp).exists())
+ CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));
CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
"/../../../" + ToolChainDir));
CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
@@ -656,6 +672,11 @@ const char *Darwin::GetForcedPicModel() const {
return 0;
}
+bool Darwin::SupportsObjCGC() const {
+ // Garbage collection is supported everywhere except on iPhone OS.
+ return !isTargetIPhoneOS();
+}
+
/// Generic_GCC - A tool chain using the 'gcc' command to perform
/// all subcommands; this relies on gcc translating the majority of
/// command line options.
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 0d5b2a3..9acc950 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -160,13 +160,20 @@ public:
return !isMacosxVersionLT(10, 6);
}
virtual bool IsObjCNonFragileABIDefault() const {
- // Non-fragile ABI default to on for iPhoneOS and x86-64.
- return isTargetIPhoneOS() || getTriple().getArch() == llvm::Triple::x86_64;
+ // Non-fragile ABI is default for everything but i386.
+ return getTriple().getArch() != llvm::Triple::x86;
}
virtual bool IsObjCLegacyDispatchDefault() const {
// This is only used with the non-fragile ABI.
- return (getTriple().getArch() == llvm::Triple::arm ||
- getTriple().getArch() == llvm::Triple::thumb);
+
+ // Legacy dispatch is used everywhere except on x86_64.
+ return getTriple().getArch() != llvm::Triple::x86_64;
+ }
+ virtual bool UseObjCMixedDispatch() const {
+ // This is only used with the non-fragile ABI and non-legacy dispatch.
+
+ // Mixed dispatch is used everywhere except OS X before 10.6.
+ return !(!isTargetIPhoneOS() && isMacosxVersionLT(10, 6));
}
virtual bool IsUnwindTablesDefault() const;
virtual unsigned GetDefaultStackProtectorLevel() const {
@@ -176,6 +183,8 @@ public:
virtual const char *GetDefaultRelocationModel() const;
virtual const char *GetForcedPicModel() const;
+ virtual bool SupportsObjCGC() const;
+
virtual bool UseDwarfDebugFlags() const;
virtual bool UseSjLjExceptions() const;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 2a37991..176d491 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -566,13 +566,9 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
// If unspecified, choose the default based on the platform.
if (FloatABI.empty()) {
- switch (getToolChain().getTriple().getOS()) {
- default:
- // Assume "soft", but warn the user we are guessing.
- FloatABI = "soft";
- D.Diag(clang::diag::warn_drv_assuming_mfloat_abi_is) << "soft";
- break;
- }
+ // Assume "soft", but warn the user we are guessing.
+ FloatABI = "soft";
+ D.Diag(clang::diag::warn_drv_assuming_mfloat_abi_is) << "soft";
}
if (FloatABI == "soft") {
@@ -623,6 +619,11 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
CPUName = "core2";
else if (getToolChain().getArchName() == "i386")
CPUName = "yonah";
+ } else if (getToolChain().getOS().startswith("haiku")) {
+ if (getToolChain().getArchName() == "x86_64")
+ CPUName = "x86-64";
+ else if (getToolChain().getArchName() == "i386")
+ CPUName = "i586";
} else {
if (getToolChain().getArchName() == "x86_64")
CPUName = "x86-64";
@@ -826,7 +827,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Add default argument set.
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
CmdArgs.push_back("-analyzer-check-dead-stores");
- CmdArgs.push_back("-analyzer-check-security-syntactic");
+ // Do not enable the security-syntatic check since it
+ // it needs to be refined (known issues).
+ // CmdArgs.push_back("-analyzer-check-security-syntactic");
CmdArgs.push_back("-analyzer-check-objc-mem");
CmdArgs.push_back("-analyzer-eagerly-assume");
CmdArgs.push_back("-analyzer-check-objc-methodsigs");
@@ -1073,6 +1076,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
}
+ CmdArgs.push_back("-ferror-limit");
+ if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ))
+ CmdArgs.push_back(A->getValue(Args));
+ else
+ CmdArgs.push_back("19");
+
+ CmdArgs.push_back("-ftemplate-backtrace-limit");
+ if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ))
+ CmdArgs.push_back(A->getValue(Args));
+ else
+ CmdArgs.push_back("10");
+
// Pass -fmessage-length=.
CmdArgs.push_back("-fmessage-length");
if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
@@ -1105,10 +1120,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_lax_vector_conversions))
CmdArgs.push_back("-fno-lax-vector-conversions");
+ // Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only
+ // takes precedence.
+ const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only);
+ if (!GCArg)
+ GCArg = Args.getLastArg(options::OPT_fobjc_gc);
+ if (GCArg) {
+ if (getToolChain().SupportsObjCGC()) {
+ GCArg->render(Args, CmdArgs);
+ } else {
+ // FIXME: We should move this to a hard error.
+ D.Diag(clang::diag::warn_drv_objc_gc_unsupported)
+ << GCArg->getAsString(Args);
+ }
+ }
+
Args.AddLastArg(CmdArgs, options::OPT_fno_caret_diagnostics);
Args.AddLastArg(CmdArgs, options::OPT_fno_show_column);
- Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc_only);
- Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc);
Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
@@ -1150,11 +1178,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fblocks");
}
- // -fno-access-control is default (for now).
- if (Args.hasFlag(options::OPT_faccess_control,
- options::OPT_fno_access_control,
+ // -faccess-control is default.
+ if (Args.hasFlag(options::OPT_fno_access_control,
+ options::OPT_faccess_control,
false))
- CmdArgs.push_back("-faccess-control");
+ CmdArgs.push_back("-fno-access-control");
// -fexceptions=0 is default.
if (needsExceptions(Args, InputType, getToolChain().getTriple()))
@@ -1188,6 +1216,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().getTriple().getOS() == llvm::Triple::Win32))
CmdArgs.push_back("-fms-extensions");
+ // -fgnu-keywords default varies depending on language; only pass if
+ // specified.
+ if (Arg *A = Args.getLastArg(options::OPT_fgnu_keywords,
+ options::OPT_fno_gnu_keywords))
+ A->render(Args, CmdArgs);
+
// -fnext-runtime is default.
if (!Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
getToolChain().getTriple().getOS() == llvm::Triple::Darwin))
@@ -1195,16 +1229,32 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fobjc-nonfragile-abi=0 is default.
if (types::isObjC(InputType)) {
+ unsigned Version = 1;
if (Args.hasArg(options::OPT_fobjc_nonfragile_abi) ||
- getToolChain().IsObjCNonFragileABIDefault()) {
+ getToolChain().IsObjCNonFragileABIDefault())
+ Version = 2;
+ if (Arg *A = Args.getLastArg(options::OPT_fobjc_abi_version_EQ)) {
+ if (llvm::StringRef(A->getValue(Args)) == "1")
+ Version = 1;
+ else if (llvm::StringRef(A->getValue(Args)) == "2")
+ Version = 2;
+ else
+ D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ }
+
+ if (Version == 2) {
CmdArgs.push_back("-fobjc-nonfragile-abi");
-
- // -fobjc-legacy-dispatch is only relevant with the nonfragile-abi, and
- // defaults to off.
- if (Args.hasFlag(options::OPT_fobjc_legacy_dispatch,
- options::OPT_fno_objc_legacy_dispatch,
- getToolChain().IsObjCLegacyDispatchDefault()))
- CmdArgs.push_back("-fobjc-legacy-dispatch");
+
+ // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and
+ // legacy is the default.
+ if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch,
+ options::OPT_fno_objc_legacy_dispatch,
+ getToolChain().IsObjCLegacyDispatchDefault())) {
+ if (getToolChain().UseObjCMixedDispatch())
+ CmdArgs.push_back("-fobjc-dispatch-method=mixed");
+ else
+ CmdArgs.push_back("-fobjc-dispatch-method=non-legacy");
+ }
}
}
@@ -1212,12 +1262,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_assume_sane_operator_new))
CmdArgs.push_back("-fno-assume-sane-operator-new");
+ // -fconstant-cfstrings is default, and may be subject to argument translation
+ // on Darwin.
+ if (!Args.hasFlag(options::OPT_fconstant_cfstrings,
+ options::OPT_fno_constant_cfstrings) ||
+ !Args.hasFlag(options::OPT_mconstant_cfstrings,
+ options::OPT_mno_constant_cfstrings))
+ CmdArgs.push_back("-fno-constant-cfstrings");
+
// -fshort-wchar default varies depending on platform; only
// pass if specified.
- if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar)) {
- if (A->getOption().matches(options::OPT_fshort_wchar))
- CmdArgs.push_back("-fshort-wchar");
- }
+ if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar))
+ A->render(Args, CmdArgs);
// -fno-pascal-strings is default, only pass non-default. If the tool chain
// happened to translate to -mpascal-strings, we want to back translate here.
@@ -1305,8 +1361,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_dM);
Args.AddLastArg(CmdArgs, options::OPT_dD);
+ // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
+ // parser.
Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
- Args.AddAllArgValues(CmdArgs, options::OPT_mllvm);
+ for (arg_iterator it = Args.filtered_begin(options::OPT_mllvm),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ it->claim();
+
+ // We translate this by hand to the -cc1 argument, since nightly test uses
+ // it and developers have been trained to spell it with -mllvm.
+ if (llvm::StringRef(it->getValue(Args, 0)) == "-disable-llvm-optzns")
+ CmdArgs.push_back("-disable-llvm-optzns");
+ else
+ it->render(Args, CmdArgs);
+ }
if (Output.getType() == types::TY_Dependencies) {
// Handled with other dependency code.
@@ -1363,10 +1431,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Claim some arguments which clang supports automatically.
- // -fpch-preprocess is used with gcc to add a special marker in the
- // -output to include the PCH file. Clang's PTH solution is
- // -completely transparent, so we do not need to deal with it at
- // -all.
+ // -fpch-preprocess is used with gcc to add a special marker in the output to
+ // include the PCH file. Clang's PTH solution is completely transparent, so we
+ // do not need to deal with it at all.
Args.ClaimAllArgs(options::OPT_fpch_preprocess);
// Claim some arguments which clang doesn't support, but we don't
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 7a8f1b7..091fec3 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -42,6 +42,7 @@ namespace tools {
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
+ virtual bool hasGoodDiagnostics() const { return true; }
virtual bool hasIntegratedAssembler() const { return true; }
virtual bool hasIntegratedCPP() const { return true; }
@@ -79,6 +80,7 @@ namespace gcc {
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
+ virtual bool hasGoodDiagnostics() const { return true; }
virtual bool hasIntegratedCPP() const { return false; }
virtual void RenderExtraToolArgs(const JobAction &JA,
@@ -91,6 +93,7 @@ namespace gcc {
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return false; }
+ virtual bool hasGoodDiagnostics() const { return true; }
virtual bool hasIntegratedCPP() const { return true; }
virtual void RenderExtraToolArgs(const JobAction &JA,
@@ -103,6 +106,7 @@ namespace gcc {
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
+ virtual bool hasGoodDiagnostics() const { return true; }
virtual bool hasIntegratedCPP() const { return true; }
virtual void RenderExtraToolArgs(const JobAction &JA,
@@ -176,6 +180,7 @@ namespace darwin {
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
+ virtual bool hasGoodDiagnostics() const { return true; }
virtual bool hasIntegratedCPP() const { return true; }
};
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index ebbd720..7b8ebf9 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -24,7 +24,6 @@
#include "clang/AST/PrettyPrinter.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "llvm/Module.h"
-#include "llvm/Support/Format.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
@@ -165,7 +164,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
case Decl::Namespace: {
Out << "[namespace] ";
const NamespaceDecl* ND = cast<NamespaceDecl>(DC);
- Out << ND->getNameAsString();
+ Out << ND;
break;
}
case Decl::Enum: {
@@ -174,7 +173,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "[enum] ";
else
Out << "<enum> ";
- Out << ED->getNameAsString();
+ Out << ED;
break;
}
case Decl::Record: {
@@ -183,7 +182,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "[struct] ";
else
Out << "<struct> ";
- Out << RD->getNameAsString();
+ Out << RD;
break;
}
case Decl::CXXRecord: {
@@ -192,7 +191,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "[class] ";
else
Out << "<class> ";
- Out << RD->getNameAsString() << " " << DC;
+ Out << RD << ' ' << DC;
break;
}
case Decl::ObjCMethod:
@@ -225,7 +224,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "[function] ";
else
Out << "<function> ";
- Out << FD->getNameAsString();
+ Out << FD;
// Print the parameters.
Out << "(";
bool PrintComma = false;
@@ -235,7 +234,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << ", ";
else
PrintComma = true;
- Out << (*I)->getNameAsString();
+ Out << *I;
}
Out << ")";
break;
@@ -248,7 +247,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "(c++ method) ";
else
Out << "<c++ method> ";
- Out << D->getNameAsString();
+ Out << D;
// Print the parameters.
Out << "(";
bool PrintComma = false;
@@ -258,7 +257,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << ", ";
else
PrintComma = true;
- Out << (*I)->getNameAsString();
+ Out << *I;
}
Out << ")";
@@ -278,7 +277,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "(c++ ctor) ";
else
Out << "<c++ ctor> ";
- Out << D->getNameAsString();
+ Out << D;
// Print the parameters.
Out << "(";
bool PrintComma = false;
@@ -288,7 +287,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << ", ";
else
PrintComma = true;
- Out << (*I)->getNameAsString();
+ Out << *I;
}
Out << ")";
@@ -307,7 +306,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "(c++ dtor) ";
else
Out << "<c++ dtor> ";
- Out << D->getNameAsString();
+ Out << D;
// Check the semantic DC.
const DeclContext* SemaDC = D->getDeclContext();
const DeclContext* LexicalDC = D->getLexicalDeclContext();
@@ -323,7 +322,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "(c++ conversion) ";
else
Out << "<c++ conversion> ";
- Out << D->getNameAsString();
+ Out << D;
// Check the semantic DC.
const DeclContext* SemaDC = D->getDeclContext();
const DeclContext* LexicalDC = D->getLexicalDeclContext();
@@ -370,42 +369,42 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
}
case Decl::Field: {
FieldDecl* FD = cast<FieldDecl>(*I);
- Out << "<field> " << FD->getNameAsString() << "\n";
+ Out << "<field> " << FD << '\n';
break;
}
case Decl::Typedef: {
TypedefDecl* TD = cast<TypedefDecl>(*I);
- Out << "<typedef> " << TD->getNameAsString() << "\n";
+ Out << "<typedef> " << TD << '\n';
break;
}
case Decl::EnumConstant: {
EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I);
- Out << "<enum constant> " << ECD->getNameAsString() << "\n";
+ Out << "<enum constant> " << ECD << '\n';
break;
}
case Decl::Var: {
VarDecl* VD = cast<VarDecl>(*I);
- Out << "<var> " << VD->getNameAsString() << "\n";
+ Out << "<var> " << VD << '\n';
break;
}
case Decl::ImplicitParam: {
ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I);
- Out << "<implicit parameter> " << IPD->getNameAsString() << "\n";
+ Out << "<implicit parameter> " << IPD << '\n';
break;
}
case Decl::ParmVar: {
ParmVarDecl* PVD = cast<ParmVarDecl>(*I);
- Out << "<parameter> " << PVD->getNameAsString() << "\n";
+ Out << "<parameter> " << PVD << '\n';
break;
}
case Decl::ObjCProperty: {
ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I);
- Out << "<objc property> " << OPD->getNameAsString() << "\n";
+ Out << "<objc property> " << OPD << '\n';
break;
}
case Decl::FunctionTemplate: {
FunctionTemplateDecl* FTD = cast<FunctionTemplateDecl>(*I);
- Out << "<function template> " << FTD->getNameAsString() << "\n";
+ Out << "<function template> " << FTD << '\n';
break;
}
case Decl::FileScopeAsm: {
@@ -418,16 +417,16 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
}
case Decl::NamespaceAlias: {
NamespaceAliasDecl* NAD = cast<NamespaceAliasDecl>(*I);
- Out << "<namespace alias> " << NAD->getNameAsString() << "\n";
+ Out << "<namespace alias> " << NAD << '\n';
break;
}
case Decl::ClassTemplate: {
ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(*I);
- Out << "<class template> " << CTD->getNameAsString() << '\n';
+ Out << "<class template> " << CTD << '\n';
break;
}
default:
- Out << "DeclKind: " << DK << '"' << I->getDeclKindName() << "\"\n";
+ Out << "DeclKind: " << DK << '"' << *I << "\"\n";
assert(0 && "decl unhandled");
}
}
@@ -437,150 +436,6 @@ ASTConsumer *clang::CreateDeclContextPrinter() {
}
//===----------------------------------------------------------------------===//
-/// RecordLayoutDumper - C++ Record Layout Dumping.
-namespace {
-class RecordLayoutDumper : public ASTConsumer {
- llvm::raw_ostream& Out;
-
- void PrintOffset(uint64_t Offset, unsigned IndentLevel) {
- Out << llvm::format("%4d | ", Offset);
- for (unsigned I = 0; I < IndentLevel * 2; ++I) Out << ' ';
- }
-
- void DumpRecordLayoutOffsets(const CXXRecordDecl *RD, ASTContext &C,
- uint64_t Offset,
- unsigned IndentLevel, const char* Description,
- bool IncludeVirtualBases) {
- const ASTRecordLayout &Info = C.getASTRecordLayout(RD);
-
- PrintOffset(Offset, IndentLevel);
- Out << C.getTypeDeclType((CXXRecordDecl *)RD).getAsString();
- if (Description)
- Out << ' ' << Description;
- if (RD->isEmpty())
- Out << " (empty)";
- Out << '\n';
-
- IndentLevel++;
-
- const CXXRecordDecl *PrimaryBase = Info.getPrimaryBase();
-
- // Vtable pointer.
- if (RD->isDynamicClass() && !PrimaryBase) {
- PrintOffset(Offset, IndentLevel);
- Out << '(' << RD->getNameAsString() << " vtable pointer)\n";
- }
- // Dump (non-virtual) bases
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- assert(!I->getType()->isDependentType() &&
- "Cannot layout class with dependent bases.");
- if (I->isVirtual())
- continue;
-
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- uint64_t BaseOffset = Offset + Info.getBaseClassOffset(Base) / 8;
-
- DumpRecordLayoutOffsets(Base, C, BaseOffset, IndentLevel,
- Base == PrimaryBase ? "(primary base)" : "(base)",
- /*IncludeVirtualBases=*/false);
- }
-
- // Dump fields.
- uint64_t FieldNo = 0;
- for (CXXRecordDecl::field_iterator I = RD->field_begin(),
- E = RD->field_end(); I != E; ++I, ++FieldNo) {
- const FieldDecl *Field = *I;
- uint64_t FieldOffset = Offset + Info.getFieldOffset(FieldNo) / 8;
-
- if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
- if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- DumpRecordLayoutOffsets(D, C, FieldOffset, IndentLevel,
- Field->getNameAsCString(),
- /*IncludeVirtualBases=*/true);
- continue;
- }
- }
-
- PrintOffset(FieldOffset, IndentLevel);
- Out << Field->getType().getAsString() << ' ';
- Out << Field->getNameAsString() << '\n';
- }
-
- if (!IncludeVirtualBases)
- return;
-
- // Dump virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I) {
- assert(I->isVirtual() && "Found non-virtual class!");
- const CXXRecordDecl *VBase =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- uint64_t VBaseOffset = Offset + Info.getVBaseClassOffset(VBase) / 8;
- DumpRecordLayoutOffsets(VBase, C, VBaseOffset, IndentLevel,
- VBase == PrimaryBase ?
- "(primary virtual base)" : "(virtual base)",
- /*IncludeVirtualBases=*/false);
- }
- }
-
- // FIXME: Maybe this could be useful in ASTContext.cpp.
- void DumpRecordLayout(const CXXRecordDecl *RD, ASTContext &C) {
- const ASTRecordLayout &Info = C.getASTRecordLayout(RD);
-
- DumpRecordLayoutOffsets(RD, C, 0, 0, 0,
- /*IncludeVirtualBases=*/true);
- Out << " sizeof=" << Info.getSize() / 8;
- Out << ", dsize=" << Info.getDataSize() / 8;
- Out << ", align=" << Info.getAlignment() / 8 << '\n';
- Out << " nvsize=" << Info.getNonVirtualSize() / 8;
- Out << ", nvalign=" << Info.getNonVirtualAlign() / 8 << '\n';
- Out << '\n';
- }
-
-public:
- RecordLayoutDumper() : Out(llvm::errs()) {}
-
- void HandleTranslationUnit(ASTContext &C) {
- for (ASTContext::type_iterator I = C.types_begin(), E = C.types_end();
- I != E; ++I) {
- const RecordType *RT = dyn_cast<RecordType>(*I);
- if (!RT)
- continue;
-
- const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
- if (!RD)
- continue;
-
- if (RD->isImplicit())
- continue;
-
- if (RD->isDependentType())
- continue;
-
- if (RD->isInvalidDecl())
- continue;
-
- if (!RD->getDefinition())
- continue;
-
- // FIXME: Do we really need to hard code this?
- if (RD->getQualifiedNameAsString() == "__va_list_tag")
- continue;
-
- DumpRecordLayout(RD, C);
- }
- }
-};
-} // end anonymous namespace
-ASTConsumer *clang::CreateRecordLayoutDumper() {
- return new RecordLayoutDumper();
-}
-
-//===----------------------------------------------------------------------===//
/// InheritanceViewer - C++ Inheritance Visualization
namespace {
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 427bd6a..4730bdc 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -265,8 +265,16 @@ public:
TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
void HandleTopLevelDecl(DeclGroupRef D) {
- for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
- Unit.getTopLevelDecls().push_back(*it);
+ for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
+ Decl *D = *it;
+ // FIXME: Currently ObjC method declarations are incorrectly being
+ // reported as top-level declarations, even though their DeclContext
+ // is the containing ObjC @interface/@implementation. This is a
+ // fundamental problem in the parser right now.
+ if (isa<ObjCMethodDecl>(D))
+ continue;
+ Unit.getTopLevelDecls().push_back(D);
+ }
}
};
@@ -431,8 +439,10 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
const driver::ArgStringList &CCArgs = Cmd->getArguments();
llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
- CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(),
- (const char**) CCArgs.data()+CCArgs.size(),
+ CompilerInvocation::CreateFromArgs(*CI,
+ const_cast<const char **>(CCArgs.data()),
+ const_cast<const char **>(CCArgs.data()) +
+ CCArgs.size(),
*Diags);
// Override any files that need remapping
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index d764fd0..87c3fca 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -41,10 +41,6 @@ using namespace clang;
static ExplodedNode::Auditor* CreateUbiViz();
//===----------------------------------------------------------------------===//
-// Basic type definitions.
-//===----------------------------------------------------------------------===//
-
-//===----------------------------------------------------------------------===//
// Special PathDiagnosticClients.
//===----------------------------------------------------------------------===//
@@ -62,20 +58,21 @@ CreatePlistHTMLDiagnosticClient(const std::string& prefix,
namespace {
- class AnalysisConsumer : public ASTConsumer {
- public:
+class AnalysisConsumer : public ASTConsumer {
+public:
typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D);
typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M,
TranslationUnitDecl &TU);
- private:
+private:
typedef std::vector<CodeAction> Actions;
typedef std::vector<TUAction> TUActions;
Actions FunctionActions;
Actions ObjCMethodActions;
Actions ObjCImplementationActions;
- TUActions TranslationUnitActions;
+ Actions CXXMethodActions;
+ TUActions TranslationUnitActions; // Remove this.
public:
ASTContext* Ctx;
@@ -150,7 +147,7 @@ public:
if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
const NamedDecl *ND = cast<NamedDecl>(D);
- llvm::errs() << ' ' << ND->getNameAsString() << '\n';
+ llvm::errs() << ' ' << ND << '\n';
}
else if (isa<BlockDecl>(D)) {
llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:"
@@ -161,103 +158,100 @@ public:
void addCodeAction(CodeAction action) {
FunctionActions.push_back(action);
ObjCMethodActions.push_back(action);
- }
-
- void addObjCImplementationAction(CodeAction action) {
- ObjCImplementationActions.push_back(action);
+ CXXMethodActions.push_back(action);
}
void addTranslationUnitAction(TUAction action) {
TranslationUnitActions.push_back(action);
}
+ void addObjCImplementationAction(CodeAction action) {
+ ObjCImplementationActions.push_back(action);
+ }
+
virtual void Initialize(ASTContext &Context) {
Ctx = &Context;
Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
PP.getLangOptions(), PD,
CreateStoreMgr, CreateConstraintMgr,
+ Opts.MaxNodes,
Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
Opts.PurgeDead, Opts.EagerlyAssume,
Opts.TrimGraph));
}
- virtual void HandleTopLevelDecl(DeclGroupRef D) {
- declDisplayed = false;
- for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
- HandleTopLevelSingleDecl(*I);
- }
-
- void HandleTopLevelSingleDecl(Decl *D);
virtual void HandleTranslationUnit(ASTContext &C);
-
- void HandleCode(Decl* D, Stmt* Body, Actions& actions);
+ void HandleCode(Decl *D, Stmt* Body, Actions& actions);
};
} // end anonymous namespace
-namespace llvm {
- template <> struct FoldingSetTrait<AnalysisConsumer::CodeAction> {
- static inline void Profile(AnalysisConsumer::CodeAction X,
- FoldingSetNodeID& ID) {
- ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
- }
- };
-}
-
//===----------------------------------------------------------------------===//
// AnalysisConsumer implementation.
//===----------------------------------------------------------------------===//
-void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) {
- switch (D->getKind()) {
- case Decl::CXXConstructor:
- case Decl::CXXDestructor:
- case Decl::CXXConversion:
- case Decl::CXXMethod:
- case Decl::Function: {
- FunctionDecl* FD = cast<FunctionDecl>(D);
- if (!Opts.AnalyzeSpecificFunction.empty() &&
- FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
- break;
-
- if (Stmt *Body = FD->getBody())
- HandleCode(FD, Body, FunctionActions);
- break;
- }
-
- case Decl::ObjCMethod: {
- ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
+void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
- if (!Opts.AnalyzeSpecificFunction.empty() &&
- Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString())
- return;
+ TranslationUnitDecl *TU = C.getTranslationUnitDecl();
- if (Stmt* Body = MD->getBody())
- HandleCode(MD, Body, ObjCMethodActions);
- break;
- }
+ for (DeclContext::decl_iterator I = TU->decls_begin(), E = TU->decls_end();
+ I != E; ++I) {
+ Decl *D = *I;
+
+ switch (D->getKind()) {
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::CXXMethod:
+ case Decl::Function: {
+ FunctionDecl* FD = cast<FunctionDecl>(D);
+
+ if (FD->isThisDeclarationADefinition()) {
+ if (!Opts.AnalyzeSpecificFunction.empty() &&
+ FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
+ break;
+ HandleCode(FD, FD->getBody(), FunctionActions);
+ }
+ break;
+ }
- default:
- break;
- }
-}
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
+
+ if (MD->isThisDeclarationADefinition()) {
+ if (!Opts.AnalyzeSpecificFunction.empty() &&
+ Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString())
+ break;
+ HandleCode(MD, MD->getBody(), ObjCMethodActions);
+ }
+ break;
+ }
-void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
+ case Decl::ObjCImplementation: {
+ ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I);
+ HandleCode(ID, 0, ObjCImplementationActions);
+
+ for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(),
+ ME = ID->meth_end(); MI != ME; ++MI) {
+ if ((*MI)->isThisDeclarationADefinition()) {
+ if (!Opts.AnalyzeSpecificFunction.empty() &&
+ Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString())
+ break;
+ HandleCode(*MI, (*MI)->getBody(), ObjCMethodActions);
+ }
+ }
+ break;
+ }
- TranslationUnitDecl *TU = C.getTranslationUnitDecl();
+ default:
+ break;
+ }
+ }
for (TUActions::iterator I = TranslationUnitActions.begin(),
E = TranslationUnitActions.end(); I != E; ++I) {
(*I)(*this, *Mgr, *TU);
}
- if (!ObjCImplementationActions.empty()) {
- for (DeclContext::decl_iterator I = TU->decls_begin(),
- E = TU->decls_end();
- I != E; ++I)
- if (ObjCImplementationDecl* ID = dyn_cast<ObjCImplementationDecl>(*I))
- HandleCode(ID, 0, ObjCImplementationActions);
- }
-
// Explicitly destroy the PathDiagnosticClient. This will flush its output.
// FIXME: This should be replaced with something that doesn't rely on
// side-effects in PathDiagnosticClient's destructor. This is required when
@@ -278,7 +272,8 @@ static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) {
void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) {
// Don't run the actions if an error has occured with parsing the file.
- if (PP.getDiagnostics().hasErrorOccurred())
+ Diagnostic &Diags = PP.getDiagnostics();
+ if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
return;
// Don't run the actions on declarations in header files unless
@@ -310,7 +305,6 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) {
static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
if (LiveVariables *L = mgr.getLiveVariables(D)) {
- C.DisplayFunction(D);
BugReporter BR(mgr);
CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR);
}
@@ -319,7 +313,6 @@ static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr,
static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
if (CFG* c = mgr.getCFG(D)) {
- C.DisplayFunction(D);
CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic());
}
}
@@ -331,15 +324,11 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
llvm::OwningPtr<GRTransferFuncs> TF(tf);
- // Display progress.
- C.DisplayFunction(D);
-
// Construct the analysis engine. We first query for the LiveVariables
// information to see if the CFG is valid.
// FIXME: Inter-procedural analysis will need to handle invalid CFGs.
if (!mgr.getLiveVariables(D))
return;
-
GRExprEngine Eng(mgr, TF.take());
if (C.Opts.EnableExperimentalInternalChecks)
@@ -358,7 +347,7 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
}
// Execute the worklist algorithm.
- Eng.ExecuteWorkList(mgr.getStackFrame(D));
+ Eng.ExecuteWorkList(mgr.getStackFrame(D), mgr.getMaxNodes());
// Release the auditor (if any) so that it doesn't monitor the graph
// created BugReporter.
@@ -406,28 +395,24 @@ static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
static void ActionDisplayLiveVariables(AnalysisConsumer &C,
AnalysisManager& mgr, Decl *D) {
if (LiveVariables* L = mgr.getLiveVariables(D)) {
- C.DisplayFunction(D);
L->dumpBlockLiveness(mgr.getSourceManager());
}
}
static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
if (CFG *cfg = mgr.getCFG(D)) {
- C.DisplayFunction(D);
cfg->dump(mgr.getLangOptions());
}
}
static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
if (CFG *cfg = mgr.getCFG(D)) {
- C.DisplayFunction(D);
cfg->viewCFG(mgr.getLangOptions());
}
}
static void ActionSecuritySyntacticChecks(AnalysisConsumer &C,
AnalysisManager &mgr, Decl *D) {
- C.DisplayFunction(D);
BugReporter BR(mgr);
CheckSecuritySyntaxOnly(D, BR);
}
@@ -443,86 +428,28 @@ static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
return;
-
- C.DisplayFunction(D);
BugReporter BR(mgr);
CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR);
}
static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
- C.DisplayFunction(D);
BugReporter BR(mgr);
CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR);
}
static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
- C.DisplayFunction(D);
BugReporter BR(mgr);
CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR);
}
static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr,
Decl *D) {
- C.DisplayFunction(D);
BugReporter BR(mgr);
CheckSizeofPointer(D, BR);
}
-static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr,
- TranslationUnitDecl &TU) {
-
- // Find the entry function definition (if any).
- FunctionDecl *D = 0;
-
- // Must specify an entry function.
- if (!C.Opts.AnalyzeSpecificFunction.empty()) {
- for (DeclContext::decl_iterator I=TU.decls_begin(), E=TU.decls_end();
- I != E; ++I) {
- if (FunctionDecl *fd = dyn_cast<FunctionDecl>(*I))
- if (fd->isThisDeclarationADefinition() &&
- fd->getNameAsString() == C.Opts.AnalyzeSpecificFunction) {
- D = fd;
- break;
- }
- }
- }
-
- if (!D)
- return;
-
-
- // FIXME: This is largely copy of ActionGRExprEngine. Needs cleanup.
- // Display progress.
- C.DisplayFunction(D);
-
- // FIXME: Make a fake transfer function. The GRTransferFunc interface
- // eventually will be removed.
- GRExprEngine Eng(mgr, new GRTransferFuncs());
-
- if (C.Opts.EnableExperimentalInternalChecks)
- RegisterExperimentalInternalChecks(Eng);
-
- RegisterAppleChecks(Eng, *D);
-
- if (C.Opts.EnableExperimentalChecks)
- RegisterExperimentalChecks(Eng);
-
- // Register call inliner as the last checker.
- RegisterCallInliner(Eng);
-
- // Execute the worklist algorithm.
- Eng.ExecuteWorkList(mgr.getStackFrame(D));
-
- // Visualize the exploded graph.
- if (mgr.shouldVisualizeGraphviz())
- Eng.ViewGraph(mgr.shouldTrimGraph());
-
- // Display warnings.
- Eng.getBugReporter().FlushReports();
-}
-
//===----------------------------------------------------------------------===//
// AnalysisConsumer creation.
//===----------------------------------------------------------------------===//
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index d069e8f..a5fcebe 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -475,7 +475,7 @@ void PTHWriter::GeneratePTH(const std::string &MainFile) {
if (!P.isAbsolute())
continue;
- const llvm::MemoryBuffer *B = C.getBuffer(PP.getDiagnostics());
+ const llvm::MemoryBuffer *B = C.getBuffer(PP.getDiagnostics(), SM);
if (!B) continue;
FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
@@ -550,8 +550,7 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
// Lex through the entire file. This will populate SourceManager with
// all of the header information.
Token Tok;
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
do { PP.Lex(Tok); } while (Tok.isNot(tok::eof));
// Generate the PTH file.
diff --git a/lib/Frontend/CodeGenAction.cpp b/lib/Frontend/CodeGenAction.cpp
index b1795a3..79d7d5f 100644
--- a/lib/Frontend/CodeGenAction.cpp
+++ b/lib/Frontend/CodeGenAction.cpp
@@ -8,16 +8,18 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/CodeGenAction.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/Basic/TargetOptions.h"
#include "clang/CodeGen/CodeGenOptions.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/OwningPtr.h"
@@ -28,6 +30,8 @@
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/StandardPasses.h"
#include "llvm/Support/Timer.h"
#include "llvm/Target/SubtargetFeature.h"
@@ -87,7 +91,7 @@ namespace {
const LangOptions &langopts, const CodeGenOptions &compopts,
const TargetOptions &targetopts, bool TimePasses,
const std::string &infile, llvm::raw_ostream *OS,
- LLVMContext& C) :
+ LLVMContext &C) :
Diags(_Diags),
Action(action),
CodeGenOpts(compopts),
@@ -175,6 +179,15 @@ namespace {
virtual void CompleteTentativeDefinition(VarDecl *D) {
Gen->CompleteTentativeDefinition(D);
}
+
+ static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context,
+ unsigned LocCookie) {
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie);
+ ((BackendConsumer*)Context)->InlineAsmDiagHandler2(SM, Loc);
+ }
+
+ void InlineAsmDiagHandler2(const llvm::SMDiagnostic &,
+ SourceLocation LocCookie);
};
}
@@ -211,127 +224,122 @@ bool BackendConsumer::AddEmitPasses() {
if (Action == Backend_EmitBC) {
getPerModulePasses()->add(createBitcodeWriterPass(FormattedOutStream));
- } else if (Action == Backend_EmitLL) {
+ return true;
+ }
+
+ if (Action == Backend_EmitLL) {
getPerModulePasses()->add(createPrintModulePass(&FormattedOutStream));
+ return true;
+ }
+
+ bool Fast = CodeGenOpts.OptimizationLevel == 0;
+
+ // Create the TargetMachine for generating code.
+ std::string Error;
+ std::string Triple = TheModule->getTargetTriple();
+ const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error);
+ if (!TheTarget) {
+ Diags.Report(diag::err_fe_unable_to_create_target) << Error;
+ return false;
+ }
+
+ // FIXME: Expose these capabilities via actual APIs!!!! Aside from just
+ // being gross, this is also totally broken if we ever care about
+ // concurrency.
+ llvm::NoFramePointerElim = CodeGenOpts.DisableFPElim;
+ if (CodeGenOpts.FloatABI == "soft")
+ llvm::FloatABIType = llvm::FloatABI::Soft;
+ else if (CodeGenOpts.FloatABI == "hard")
+ llvm::FloatABIType = llvm::FloatABI::Hard;
+ else {
+ assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!");
+ llvm::FloatABIType = llvm::FloatABI::Default;
+ }
+ NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
+ llvm::UseSoftFloat = CodeGenOpts.SoftFloat;
+ UnwindTablesMandatory = CodeGenOpts.UnwindTables;
+
+ TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose);
+
+ TargetMachine::setFunctionSections(CodeGenOpts.FunctionSections);
+ TargetMachine::setDataSections (CodeGenOpts.DataSections);
+
+ // FIXME: Parse this earlier.
+ if (CodeGenOpts.RelocationModel == "static") {
+ TargetMachine::setRelocationModel(llvm::Reloc::Static);
+ } else if (CodeGenOpts.RelocationModel == "pic") {
+ TargetMachine::setRelocationModel(llvm::Reloc::PIC_);
} else {
- bool Fast = CodeGenOpts.OptimizationLevel == 0;
-
- // Create the TargetMachine for generating code.
- std::string Error;
- std::string Triple = TheModule->getTargetTriple();
- const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error);
- if (!TheTarget) {
- Diags.Report(diag::err_fe_unable_to_create_target) << Error;
- return false;
- }
+ assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" &&
+ "Invalid PIC model!");
+ TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC);
+ }
+ // FIXME: Parse this earlier.
+ if (CodeGenOpts.CodeModel == "small") {
+ TargetMachine::setCodeModel(llvm::CodeModel::Small);
+ } else if (CodeGenOpts.CodeModel == "kernel") {
+ TargetMachine::setCodeModel(llvm::CodeModel::Kernel);
+ } else if (CodeGenOpts.CodeModel == "medium") {
+ TargetMachine::setCodeModel(llvm::CodeModel::Medium);
+ } else if (CodeGenOpts.CodeModel == "large") {
+ TargetMachine::setCodeModel(llvm::CodeModel::Large);
+ } else {
+ assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!");
+ TargetMachine::setCodeModel(llvm::CodeModel::Default);
+ }
- // FIXME: Expose these capabilities via actual APIs!!!! Aside from just
- // being gross, this is also totally broken if we ever care about
- // concurrency.
- llvm::NoFramePointerElim = CodeGenOpts.DisableFPElim;
- if (CodeGenOpts.FloatABI == "soft")
- llvm::FloatABIType = llvm::FloatABI::Soft;
- else if (CodeGenOpts.FloatABI == "hard")
- llvm::FloatABIType = llvm::FloatABI::Hard;
- else {
- assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!");
- llvm::FloatABIType = llvm::FloatABI::Default;
- }
- NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
- llvm::UseSoftFloat = CodeGenOpts.SoftFloat;
- UnwindTablesMandatory = CodeGenOpts.UnwindTables;
-
- TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose);
-
- // FIXME: Parse this earlier.
- if (CodeGenOpts.RelocationModel == "static") {
- TargetMachine::setRelocationModel(llvm::Reloc::Static);
- } else if (CodeGenOpts.RelocationModel == "pic") {
- TargetMachine::setRelocationModel(llvm::Reloc::PIC_);
- } else {
- assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" &&
- "Invalid PIC model!");
- TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC);
- }
- // FIXME: Parse this earlier.
- if (CodeGenOpts.CodeModel == "small") {
- TargetMachine::setCodeModel(llvm::CodeModel::Small);
- } else if (CodeGenOpts.CodeModel == "kernel") {
- TargetMachine::setCodeModel(llvm::CodeModel::Kernel);
- } else if (CodeGenOpts.CodeModel == "medium") {
- TargetMachine::setCodeModel(llvm::CodeModel::Medium);
- } else if (CodeGenOpts.CodeModel == "large") {
- TargetMachine::setCodeModel(llvm::CodeModel::Large);
- } else {
- assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!");
- TargetMachine::setCodeModel(llvm::CodeModel::Default);
- }
+ std::vector<const char *> BackendArgs;
+ BackendArgs.push_back("clang"); // Fake program name.
+ if (!CodeGenOpts.DebugPass.empty()) {
+ BackendArgs.push_back("-debug-pass");
+ BackendArgs.push_back(CodeGenOpts.DebugPass.c_str());
+ }
+ if (!CodeGenOpts.LimitFloatPrecision.empty()) {
+ BackendArgs.push_back("-limit-float-precision");
+ BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str());
+ }
+ if (llvm::TimePassesIsEnabled)
+ BackendArgs.push_back("-time-passes");
+ BackendArgs.push_back(0);
+ llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
+ const_cast<char **>(&BackendArgs[0]));
+
+ std::string FeaturesStr;
+ if (TargetOpts.CPU.size() || TargetOpts.Features.size()) {
+ SubtargetFeatures Features;
+ Features.setCPU(TargetOpts.CPU);
+ for (std::vector<std::string>::const_iterator
+ it = TargetOpts.Features.begin(),
+ ie = TargetOpts.Features.end(); it != ie; ++it)
+ Features.AddFeature(*it);
+ FeaturesStr = Features.getString();
+ }
+ TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr);
- std::vector<const char *> BackendArgs;
- BackendArgs.push_back("clang"); // Fake program name.
- if (!CodeGenOpts.DebugPass.empty()) {
- BackendArgs.push_back("-debug-pass");
- BackendArgs.push_back(CodeGenOpts.DebugPass.c_str());
- }
- if (!CodeGenOpts.LimitFloatPrecision.empty()) {
- BackendArgs.push_back("-limit-float-precision");
- BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str());
- }
- if (llvm::TimePassesIsEnabled)
- BackendArgs.push_back("-time-passes");
- BackendArgs.push_back(0);
- llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
- (char**) &BackendArgs[0]);
-
- std::string FeaturesStr;
- if (TargetOpts.CPU.size() || TargetOpts.Features.size()) {
- SubtargetFeatures Features;
- Features.setCPU(TargetOpts.CPU);
- for (std::vector<std::string>::const_iterator
- it = TargetOpts.Features.begin(),
- ie = TargetOpts.Features.end(); it != ie; ++it)
- Features.AddFeature(*it);
- FeaturesStr = Features.getString();
- }
- TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr);
-
- // Set register scheduler & allocation policy.
- RegisterScheduler::setDefault(createDefaultScheduler);
- RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator :
- createLinearScanRegisterAllocator);
-
- // From llvm-gcc:
- // If there are passes we have to run on the entire module, we do codegen
- // as a separate "pass" after that happens.
- // FIXME: This is disabled right now until bugs can be worked out. Reenable
- // this for fast -O0 compiles!
- FunctionPassManager *PM = getCodeGenPasses();
- CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
-
- switch (CodeGenOpts.OptimizationLevel) {
- default: break;
- case 0: OptLevel = CodeGenOpt::None; break;
- case 3: OptLevel = CodeGenOpt::Aggressive; break;
- }
+ // Set register scheduler & allocation policy.
+ RegisterScheduler::setDefault(createDefaultScheduler);
+ RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator :
+ createLinearScanRegisterAllocator);
- // Request that addPassesToEmitFile run the Verifier after running
- // passes which modify the IR.
-#ifndef NDEBUG
- bool DisableVerify = false;
-#else
- bool DisableVerify = true;
-#endif
-
- // Normal mode, emit a .s or .o file by running the code generator. Note,
- // this also adds codegenerator level optimization passes.
- TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile;
- if (Action == Backend_EmitObj)
- CGFT = TargetMachine::CGFT_ObjectFile;
- if (TM->addPassesToEmitFile(*PM, FormattedOutStream, CGFT, OptLevel,
- DisableVerify)) {
- Diags.Report(diag::err_fe_unable_to_interface_with_target);
- return false;
- }
+ // Create the code generator passes.
+ FunctionPassManager *PM = getCodeGenPasses();
+ CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
+
+ switch (CodeGenOpts.OptimizationLevel) {
+ default: break;
+ case 0: OptLevel = CodeGenOpt::None; break;
+ case 3: OptLevel = CodeGenOpt::Aggressive; break;
+ }
+
+ // Normal mode, emit a .s or .o file by running the code generator. Note,
+ // this also adds codegenerator level optimization passes.
+ TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile;
+ if (Action == Backend_EmitObj)
+ CGFT = TargetMachine::CGFT_ObjectFile;
+ if (TM->addPassesToEmitFile(*PM, FormattedOutStream, CGFT, OptLevel,
+ /*DisableVerify=*/!CodeGenOpts.VerifyModule)) {
+ Diags.Report(diag::err_fe_unable_to_interface_with_target);
+ return false;
}
return true;
@@ -432,14 +440,81 @@ void BackendConsumer::EmitAssembly() {
if (CodeGenPasses) {
PrettyStackTraceString CrashInfo("Code generation");
+
+ // Install an inline asm handler so that diagnostics get printed through our
+ // diagnostics hooks.
+ LLVMContext &Ctx = TheModule->getContext();
+ void *OldHandler = Ctx.getInlineAsmDiagnosticHandler();
+ void *OldContext = Ctx.getInlineAsmDiagnosticContext();
+ Ctx.setInlineAsmDiagnosticHandler((void*)(intptr_t)InlineAsmDiagHandler,
+ this);
+
CodeGenPasses->doInitialization();
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
if (!I->isDeclaration())
CodeGenPasses->run(*I);
CodeGenPasses->doFinalization();
+
+ Ctx.setInlineAsmDiagnosticHandler(OldHandler, OldContext);
}
}
+/// ConvertBackendLocation - Convert a location in a temporary llvm::SourceMgr
+/// buffer to be a valid FullSourceLoc.
+static FullSourceLoc ConvertBackendLocation(const llvm::SMDiagnostic &D,
+ SourceManager &CSM) {
+ // Get both the clang and llvm source managers. The location is relative to
+ // a memory buffer that the LLVM Source Manager is handling, we need to add
+ // a copy to the Clang source manager.
+ const llvm::SourceMgr &LSM = *D.getSourceMgr();
+
+ // We need to copy the underlying LLVM memory buffer because llvm::SourceMgr
+ // already owns its one and clang::SourceManager wants to own its one.
+ const MemoryBuffer *LBuf =
+ LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
+
+ // Create the copy and transfer ownership to clang::SourceManager.
+ llvm::MemoryBuffer *CBuf =
+ llvm::MemoryBuffer::getMemBufferCopy(LBuf->getBuffer(),
+ LBuf->getBufferIdentifier());
+ FileID FID = CSM.createFileIDForMemBuffer(CBuf);
+
+ // Translate the offset into the file.
+ unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
+ SourceLocation NewLoc =
+ CSM.getLocForStartOfFile(FID).getFileLocWithOffset(Offset);
+ return FullSourceLoc(NewLoc, CSM);
+}
+
+
+/// InlineAsmDiagHandler2 - This function is invoked when the backend hits an
+/// error parsing inline asm. The SMDiagnostic indicates the error relative to
+/// the temporary memory buffer that the inline asm parser has set up.
+void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D,
+ SourceLocation LocCookie) {
+ // There are a couple of different kinds of errors we could get here. First,
+ // we re-format the SMDiagnostic in terms of a clang diagnostic.
+
+ // Strip "error: " off the start of the message string.
+ llvm::StringRef Message = D.getMessage();
+ if (Message.startswith("error: "))
+ Message = Message.substr(7);
+
+ // There are two cases: the SMDiagnostic could have a inline asm source
+ // location or it might not. If it does, translate the location.
+ FullSourceLoc Loc;
+ if (D.getLoc() != SMLoc())
+ Loc = ConvertBackendLocation(D, Context->getSourceManager());
+ Diags.Report(Loc, diag::err_fe_inline_asm).AddString(Message);
+
+ // This could be a problem with no clang-level source location information.
+ // In this case, LocCookie is invalid. If there is source level information,
+ // print an "generated from" note.
+ if (LocCookie.isValid())
+ Diags.Report(FullSourceLoc(LocCookie, Context->getSourceManager()),
+ diag::note_fe_inline_asm_here);
+}
+
//
CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {}
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 1f915e3..5ed9c40 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -513,11 +513,20 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
}
}
- if (getDiagnosticOpts().ShowCarets)
- if (unsigned NumDiagnostics = getDiagnostics().getNumDiagnostics())
- OS << NumDiagnostics << " diagnostic"
- << (NumDiagnostics == 1 ? "" : "s")
- << " generated.\n";
+ if (getDiagnosticOpts().ShowCarets) {
+ unsigned NumWarnings = getDiagnostics().getNumWarnings();
+ unsigned NumErrors = getDiagnostics().getNumErrors() -
+ getDiagnostics().getNumErrorsSuppressed();
+
+ if (NumWarnings)
+ OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s");
+ if (NumWarnings && NumErrors)
+ OS << " and ";
+ if (NumErrors)
+ OS << NumErrors << " error" << (NumErrors == 1 ? "" : "s");
+ if (NumWarnings || NumErrors)
+ OS << " generated.\n";
+ }
if (getFrontendOpts().ShowStats) {
getFileManager().PrintStats();
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index dc2c6bf..8ffdde2 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -145,9 +145,12 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
// TimePasses is only derived.
// UnitAtATime is unused.
// UnrollLoops is only derived.
- // VerifyModule is only derived.
// Inlining is only derived.
+ if (Opts.DataSections)
+ Res.push_back("-fdata-sections");
+ if (Opts.FunctionSections)
+ Res.push_back("-ffunction-sections");
if (Opts.AsmVerbose)
Res.push_back("-masm-verbose");
if (!Opts.CodeModel.empty()) {
@@ -174,8 +177,16 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
}
if (Opts.NoZeroInitializedInBSS)
Res.push_back("-mno-zero-initialized-bss");
- if (Opts.ObjCLegacyDispatch)
- Res.push_back("-fobjc-legacy-dispatch");
+ switch (Opts.getObjCDispatchMethod()) {
+ case CodeGenOptions::Legacy:
+ break;
+ case CodeGenOptions::Mixed:
+ Res.push_back("-fobjc-dispatch-method=mixed");
+ break;
+ case CodeGenOptions::NonLegacy:
+ Res.push_back("-fobjc-dispatch-method=non-legacy");
+ break;
+ }
if (Opts.SoftFloat)
Res.push_back("-msoft-float");
if (Opts.UnwindTables)
@@ -232,6 +243,15 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
Res.push_back("-fdiagnostics-binary");
if (Opts.ShowOptionNames)
Res.push_back("-fdiagnostics-show-option");
+ if (Opts.ErrorLimit) {
+ Res.push_back("-ferror-limit");
+ Res.push_back(llvm::utostr(Opts.ErrorLimit));
+ }
+ if (Opts.TemplateBacktraceLimit != 10) {
+ Res.push_back("-ftemplate-backtrace-limit");
+ Res.push_back(llvm::utostr(Opts.TemplateBacktraceLimit));
+ }
+
if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) {
Res.push_back("-ftabstop");
Res.push_back(llvm::utostr(Opts.TabStop));
@@ -279,7 +299,6 @@ static const char *getActionName(frontend::ActionKind Kind) {
case frontend::ASTPrintXML: return "-ast-print-xml";
case frontend::ASTView: return "-ast-view";
case frontend::DumpRawTokens: return "-dump-raw-tokens";
- case frontend::DumpRecordLayouts: return "-dump-record-layouts";
case frontend::DumpTokens: return "-dump-tokens";
case frontend::EmitAssembly: return "-S";
case frontend::EmitBC: return "-emit-llvm-bc";
@@ -349,12 +368,6 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-cxx-inheritance-view");
Res.push_back(Opts.ViewClassInheritance);
}
- for (unsigned i = 0, e = Opts.FixItLocations.size(); i != e; ++i) {
- Res.push_back("-fixit-at");
- Res.push_back(Opts.FixItLocations[i].FileName + ":" +
- llvm::utostr(Opts.FixItLocations[i].Line) + ":" +
- llvm::utostr(Opts.FixItLocations[i].Column));
- }
if (!Opts.CodeCompletionAt.FileName.empty()) {
Res.push_back("-code-completion-at");
Res.push_back(Opts.CodeCompletionAt.FileName + ":" +
@@ -376,6 +389,10 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-ast-merge");
Res.push_back(Opts.ASTMergeFiles[i]);
}
+ for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i) {
+ Res.push_back("-mllvm");
+ Res.push_back(Opts.LLVMArgs[i]);
+ }
}
static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
@@ -389,7 +406,7 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) {
const HeaderSearchOptions::Entry &E = Opts.UserEntries[i];
if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied))
- llvm::llvm_report_error("Invalid option set!");
+ llvm::report_fatal_error("Invalid option set!");
if (E.IsUserSupplied) {
if (E.Group == frontend::After) {
Res.push_back("-idirafter");
@@ -403,7 +420,7 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
}
} else {
if (E.Group != frontend::Angled && E.Group != frontend::System)
- llvm::llvm_report_error("Invalid option set!");
+ llvm::report_fatal_error("Invalid option set!");
Res.push_back(E.Group == frontend::Angled ? "-iwithprefixbefore" :
"-iwithprefix");
}
@@ -412,23 +429,23 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
if (!Opts.EnvIncPath.empty()) {
// FIXME: Provide an option for this, and move env detection to driver.
- llvm::llvm_report_error("Not yet implemented!");
+ llvm::report_fatal_error("Not yet implemented!");
}
if (!Opts.CEnvIncPath.empty()) {
// FIXME: Provide an option for this, and move env detection to driver.
- llvm::llvm_report_error("Not yet implemented!");
+ llvm::report_fatal_error("Not yet implemented!");
}
if (!Opts.ObjCEnvIncPath.empty()) {
// FIXME: Provide an option for this, and move env detection to driver.
- llvm::llvm_report_error("Not yet implemented!");
+ llvm::report_fatal_error("Not yet implemented!");
}
if (!Opts.CXXEnvIncPath.empty()) {
// FIXME: Provide an option for this, and move env detection to driver.
- llvm::llvm_report_error("Not yet implemented!");
+ llvm::report_fatal_error("Not yet implemented!");
}
if (!Opts.ObjCXXEnvIncPath.empty()) {
// FIXME: Provide an option for this, and move env detection to driver.
- llvm::llvm_report_error("Not yet implemented!");
+ llvm::report_fatal_error("Not yet implemented!");
}
if (!Opts.ResourceDir.empty()) {
Res.push_back("-resource-dir");
@@ -462,6 +479,10 @@ static void LangOptsToArgs(const LangOptions &Opts,
// BCPLComment, C99, CPlusPlus0x, Digraphs, GNUInline, ImplicitInt, GNUMode
if (Opts.DollarIdents)
Res.push_back("-fdollars-in-identifiers");
+ if (Opts.GNUMode && !Opts.GNUKeywords)
+ Res.push_back("-fno-gnu-keywords");
+ if (!Opts.GNUMode && Opts.GNUKeywords)
+ Res.push_back("-fgnu-keywords");
if (Opts.Microsoft)
Res.push_back("-fms-extensions");
if (Opts.ObjCNonFragileABI)
@@ -515,15 +536,24 @@ static void LangOptsToArgs(const LangOptions &Opts,
// OptimizeSize is implicit.
if (Opts.Static)
Res.push_back("-static-define");
+ if (Opts.DumpRecordLayouts)
+ Res.push_back("-fdump-record-layouts");
+ if (Opts.DumpVTableLayouts)
+ Res.push_back("-fdump-vtable-layouts");
+ if (Opts.NoBitFieldTypeAlign)
+ Res.push_back("-fno-bitfield-type-alignment");
+ if (Opts.SjLjExceptions)
+ Res.push_back("-fsjlj-exceptions");
if (Opts.PICLevel) {
Res.push_back("-pic-level");
Res.push_back(llvm::utostr(Opts.PICLevel));
}
if (Opts.ObjCGCBitmapPrint)
Res.push_back("-print-ivar-layout");
- // FIXME: Don't forget to update when the default changes!
- if (Opts.AccessControl)
- Res.push_back("-faccess-control");
+ if (Opts.NoConstantCFStrings)
+ Res.push_back("-fno-constant-cfstrings");
+ if (!Opts.AccessControl)
+ Res.push_back("-fno-access-control");
if (!Opts.CharIsSigned)
Res.push_back("-fno-signed-char");
if (Opts.ShortWChar)
@@ -606,7 +636,7 @@ static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts,
std::vector<std::string> &Res) {
if (!Opts.ShowCPP && !Opts.ShowMacros)
- llvm::llvm_report_error("Invalid option combination!");
+ llvm::report_fatal_error("Invalid option combination!");
if (Opts.ShowCPP && Opts.ShowMacros)
Res.push_back("-dD");
@@ -756,6 +786,7 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Opts.EnableExperimentalInternalChecks =
Args.hasArg(OPT_analyzer_experimental_internal_checks);
Opts.TrimGraph = Args.hasArg(OPT_trim_egraph);
+ Opts.MaxNodes = getLastArgIntValue(Args, OPT_analyzer_max_nodes,150000,Diags);
}
static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
@@ -796,13 +827,28 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.FloatABI = getLastArgValue(Args, OPT_mfloat_abi);
Opts.LimitFloatPrecision = getLastArgValue(Args, OPT_mlimit_float_precision);
Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss);
- Opts.ObjCLegacyDispatch = Args.hasArg(OPT_fobjc_legacy_dispatch);
Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic");
+ Opts.FunctionSections = Args.hasArg(OPT_ffunction_sections);
+ Opts.DataSections = Args.hasArg(OPT_fdata_sections);
+
Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name);
Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
+
+ if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
+ llvm::StringRef Name = A->getValue(Args);
+ unsigned Method = llvm::StringSwitch<unsigned>(Name)
+ .Case("legacy", CodeGenOptions::Legacy)
+ .Case("non-legacy", CodeGenOptions::NonLegacy)
+ .Case("mixed", CodeGenOptions::Mixed)
+ .Default(~0U);
+ if (Method == ~0U)
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
+ else
+ Opts.ObjCDispatchMethod = Method;
+ }
}
static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
@@ -830,6 +876,9 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary);
+ Opts.ErrorLimit = getLastArgIntValue(Args, OPT_ferror_limit, 0, Diags);
+ Opts.TemplateBacktraceLimit
+ = getLastArgIntValue(Args, OPT_ftemplate_backtrace_limit, 0, Diags);
Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
DiagnosticOptions::DefaultTabStop, Diags);
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
@@ -860,8 +909,6 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.ProgramAction = frontend::ASTView; break;
case OPT_dump_raw_tokens:
Opts.ProgramAction = frontend::DumpRawTokens; break;
- case OPT_dump_record_layouts:
- Opts.ProgramAction = frontend::DumpRecordLayouts; break;
case OPT_dump_tokens:
Opts.ProgramAction = frontend::DumpTokens; break;
case OPT_S:
@@ -876,6 +923,9 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.ProgramAction = frontend::EmitLLVMOnly; break;
case OPT_emit_obj:
Opts.ProgramAction = frontend::EmitObj; break;
+ case OPT_fixit_EQ:
+ Opts.FixItSuffix = A->getValue(Args);
+ // fall-through!
case OPT_fixit:
Opts.ProgramAction = frontend::FixIt; break;
case OPT_emit_pch:
@@ -922,20 +972,6 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
!Args.hasArg(OPT_no_code_completion_debug_printer);
Opts.DisableFree = Args.hasArg(OPT_disable_free);
- Opts.FixItLocations.clear();
- for (arg_iterator it = Args.filtered_begin(OPT_fixit_at),
- ie = Args.filtered_end(); it != ie; ++it) {
- const char *Loc = it->getValue(Args);
- ParsedSourceLocation PSL = ParsedSourceLocation::FromString(Loc);
-
- if (PSL.FileName.empty()) {
- Diags.Report(diag::err_drv_invalid_value) << it->getAsString(Args) << Loc;
- continue;
- }
-
- Opts.FixItLocations.push_back(PSL);
- }
-
Opts.OutputFile = getLastArgValue(Args, OPT_o);
Opts.Plugins = getAllArgValues(Args, OPT_load);
Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch);
@@ -946,6 +982,7 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.ShowVersion = Args.hasArg(OPT_version);
Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view);
Opts.ASTMergeFiles = getAllArgValues(Args, OPT_ast_merge);
+ Opts.LLVMArgs = getAllArgValues(Args, OPT_mllvm);
FrontendOptions::InputKind DashX = FrontendOptions::IK_None;
if (const Arg *A = Args.getLastArg(OPT_x)) {
@@ -1129,6 +1166,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
// OpenCL and C++ both have bool, true, false keywords.
Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
+ // We abuse '-f[no-]gnu-keywords' to force overriding all GNU-extension
+ // keywords. This behavior is provided by GCC's poorly named '-fasm' flag,
+ // while a subset (the non-C++ GNU keywords) is provided by GCC's
+ // '-fgnu-keywords'. Clang conflates the two for simplicity under the single
+ // name, as it doesn't seem a useful distinction.
+ Opts.GNUKeywords = Args.hasFlag(OPT_fgnu_keywords, OPT_fno_gnu_keywords,
+ Opts.GNUMode);
+
if (Opts.CPlusPlus)
Opts.CXXOperatorNames = !Args.hasArg(OPT_fno_operator_names);
@@ -1139,6 +1184,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
if (Args.hasArg(OPT_print_ivar_layout))
Opts.ObjCGCBitmapPrint = 1;
+ if (Args.hasArg(OPT_fno_constant_cfstrings))
+ Opts.NoConstantCFStrings = 1;
if (Args.hasArg(OPT_faltivec))
Opts.AltiVec = 1;
@@ -1186,10 +1233,10 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);
- Opts.AccessControl = Args.hasArg(OPT_faccess_control);
+ Opts.AccessControl = !Args.hasArg(OPT_fno_access_control);
Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);
Opts.MathErrno = Args.hasArg(OPT_fmath_errno);
- Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 99,
+ Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 1024,
Diags);
Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime);
Opts.ObjCConstantStringClass = getLastArgValue(Args,
@@ -1203,7 +1250,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags);
Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions);
Opts.Static = Args.hasArg(OPT_static_define);
- Opts.DumpVtableLayouts = Args.hasArg(OPT_fdump_vtable_layouts);
+ Opts.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts);
+ Opts.DumpVTableLayouts = Args.hasArg(OPT_fdump_vtable_layouts);
+ Opts.NoBitFieldTypeAlign = Args.hasArg(OPT_fno_bitfield_type_align);
Opts.OptimizeSize = 0;
// FIXME: Eliminate this dependency.
@@ -1268,6 +1317,10 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.Includes.push_back(it->getValue(Args));
}
+ // Include 'altivec.h' if -faltivec option present
+ if (Args.hasArg(OPT_faltivec))
+ Opts.Includes.push_back("altivec.h");
+
for (arg_iterator it = Args.filtered_begin(OPT_remap_file),
ie = Args.filtered_end(); it != ie; ++it) {
std::pair<llvm::StringRef,llvm::StringRef> Split =
diff --git a/lib/Frontend/FixItRewriter.cpp b/lib/Frontend/FixItRewriter.cpp
index 20d452e..7c9a566 100644
--- a/lib/Frontend/FixItRewriter.cpp
+++ b/lib/Frontend/FixItRewriter.cpp
@@ -14,6 +14,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/FixItRewriter.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/Support/raw_ostream.h"
@@ -24,8 +26,12 @@
using namespace clang;
FixItRewriter::FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr,
- const LangOptions &LangOpts)
- : Diags(Diags), Rewrite(SourceMgr, LangOpts), NumFailures(0) {
+ const LangOptions &LangOpts,
+ FixItPathRewriter *PathRewriter)
+ : Diags(Diags),
+ Rewrite(SourceMgr, LangOpts),
+ PathRewriter(PathRewriter),
+ NumFailures(0) {
Client = Diags.getClient();
Diags.setClient(this);
}
@@ -34,92 +40,53 @@ FixItRewriter::~FixItRewriter() {
Diags.setClient(Client);
}
-bool FixItRewriter::WriteFixedFile(const std::string &InFileName,
- const std::string &OutFileName) {
+bool FixItRewriter::WriteFixedFile(FileID ID, llvm::raw_ostream &OS) {
+ const RewriteBuffer *RewriteBuf = Rewrite.getRewriteBufferFor(ID);
+ if (!RewriteBuf) return true;
+ RewriteBuf->write(OS);
+ OS.flush();
+ return false;
+}
+
+bool FixItRewriter::WriteFixedFiles() {
if (NumFailures > 0) {
Diag(FullSourceLoc(), diag::warn_fixit_no_changes);
return true;
}
- llvm::OwningPtr<llvm::raw_ostream> OwnedStream;
- llvm::raw_ostream *OutFile;
- if (!OutFileName.empty()) {
- std::string Err;
- OutFile = new llvm::raw_fd_ostream(OutFileName.c_str(), Err,
- llvm::raw_fd_ostream::F_Binary);
- OwnedStream.reset(OutFile);
- } else if (InFileName == "-") {
- OutFile = &llvm::outs();
- } else {
- llvm::sys::Path Path(InFileName);
- std::string Suffix = Path.getSuffix();
- Path.eraseSuffix();
- Path.appendSuffix("fixit." + Suffix);
+ for (iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) {
+ const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first);
+ std::string Filename = Entry->getName();
+ if (PathRewriter)
+ Filename = PathRewriter->RewriteFilename(Filename);
std::string Err;
- OutFile = new llvm::raw_fd_ostream(Path.c_str(), Err,
- llvm::raw_fd_ostream::F_Binary);
- OwnedStream.reset(OutFile);
- }
-
- FileID MainFileID = Rewrite.getSourceMgr().getMainFileID();
- if (const RewriteBuffer *RewriteBuf =
- Rewrite.getRewriteBufferFor(MainFileID)) {
- *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
- } else {
- Diag(FullSourceLoc(), diag::note_fixit_main_file_unchanged);
+ llvm::raw_fd_ostream OS(Filename.c_str(), Err,
+ llvm::raw_fd_ostream::F_Binary);
+ if (!Err.empty()) {
+ Diags.Report(clang::diag::err_fe_unable_to_open_output)
+ << Filename << Err;
+ continue;
+ }
+ RewriteBuffer &RewriteBuf = I->second;
+ RewriteBuf.write(OS);
+ OS.flush();
}
- OutFile->flush();
return false;
}
bool FixItRewriter::IncludeInDiagnosticCounts() const {
- return Client? Client->IncludeInDiagnosticCounts() : true;
+ return Client ? Client->IncludeInDiagnosticCounts() : true;
}
void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
const DiagnosticInfo &Info) {
Client->HandleDiagnostic(DiagLevel, Info);
- // Skip over any diagnostics that are ignored.
- if (DiagLevel == Diagnostic::Ignored)
+ // Skip over any diagnostics that are ignored or notes.
+ if (DiagLevel <= Diagnostic::Note)
return;
- if (!FixItLocations.empty()) {
- // The user has specified the locations where we should perform
- // the various fix-it modifications.
-
- // If this diagnostic does not have any code modifications,
- // completely ignore it, even if it's an error: fix-it locations
- // are meant to perform specific fix-ups even in the presence of
- // other errors.
- if (Info.getNumFixItHints() == 0)
- return;
-
- // See if the location of the error is one that matches what the
- // user requested.
- bool AcceptableLocation = false;
- const FileEntry *File
- = Rewrite.getSourceMgr().getFileEntryForID(
- Info.getLocation().getFileID());
- unsigned Line = Info.getLocation().getSpellingLineNumber();
- unsigned Column = Info.getLocation().getSpellingColumnNumber();
- for (llvm::SmallVector<RequestedSourceLocation, 4>::iterator
- Loc = FixItLocations.begin(), LocEnd = FixItLocations.end();
- Loc != LocEnd; ++Loc) {
- if (Loc->File == File && Loc->Line == Line && Loc->Column == Column) {
- AcceptableLocation = true;
- break;
- }
- }
-
- 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
// in this diagnostic.
bool CanRewrite = Info.getNumFixItHints() > 0;
@@ -196,3 +163,5 @@ void FixItRewriter::Diag(FullSourceLoc Loc, unsigned DiagID) {
Diags.Report(Loc, DiagID);
Diags.setClient(this);
}
+
+FixItPathRewriter::~FixItPathRewriter() {}
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 251b8e4..6cd960b 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -19,6 +19,7 @@
#include "clang/Frontend/FixItRewriter.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/Utils.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -74,11 +75,6 @@ ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI,
return CreateDeclContextPrinter();
}
-ASTConsumer *DumpRecordAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
- return CreateRecordLayoutDumper();
-}
-
ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
@@ -118,43 +114,38 @@ ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI,
return new ASTConsumer();
}
-/// AddFixItLocations - Add any individual user specified "fix-it" locations,
-/// and return true on success.
-static bool AddFixItLocations(CompilerInstance &CI,
- FixItRewriter &FixItRewrite) {
- const std::vector<ParsedSourceLocation> &Locs =
- CI.getFrontendOpts().FixItLocations;
- for (unsigned i = 0, e = Locs.size(); i != e; ++i) {
- const FileEntry *File = CI.getFileManager().getFile(Locs[i].FileName);
- if (!File) {
- CI.getDiagnostics().Report(diag::err_fe_unable_to_find_fixit_file)
- << Locs[i].FileName;
- return false;
- }
-
- RequestedSourceLocation Requested;
- Requested.File = File;
- Requested.Line = Locs[i].Line;
- Requested.Column = Locs[i].Column;
- FixItRewrite.addFixItLocation(Requested);
- }
+class FixItActionSuffixInserter : public FixItPathRewriter {
+ std::string NewSuffix;
- return true;
-}
+public:
+ explicit FixItActionSuffixInserter(std::string NewSuffix)
+ : NewSuffix(NewSuffix) {}
+
+ std::string RewriteFilename(const std::string &Filename) {
+ llvm::sys::Path Path(Filename);
+ std::string Suffix = Path.getSuffix();
+ Path.eraseSuffix();
+ Path.appendSuffix(NewSuffix + "." + Suffix);
+ return Path.c_str();
+ }
+};
bool FixItAction::BeginSourceFileAction(CompilerInstance &CI,
llvm::StringRef Filename) {
+ const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
+ if (!FEOpts.FixItSuffix.empty()) {
+ PathRewriter.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix));
+ } else {
+ PathRewriter.reset();
+ }
Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
- CI.getLangOpts()));
- if (!AddFixItLocations(CI, *Rewriter))
- return false;
-
+ CI.getLangOpts(), PathRewriter.get()));
return true;
}
void FixItAction::EndSourceFileAction() {
- const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
- Rewriter->WriteFixedFile(getCurrentFile(), FEOpts.OutputFile);
+ // Otherwise rewrite all files.
+ Rewriter->WriteFixedFiles();
}
ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
@@ -197,8 +188,7 @@ void DumpTokensAction::ExecuteAction() {
Preprocessor &PP = getCompilerInstance().getPreprocessor();
// Start preprocessing the specified input file.
Token Tok;
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
do {
PP.Lex(Tok);
PP.DumpToken(Tok, true);
@@ -212,7 +202,7 @@ void GeneratePTHAction::ExecuteAction() {
CI.getFrontendOpts().OutputFile == "-") {
// FIXME: Don't fail this way.
// FIXME: Verify that we can actually seek in the given file.
- llvm::llvm_report_error("PTH requires a seekable file for output!");
+ llvm::report_fatal_error("PTH requires a seekable file for output!");
}
llvm::raw_fd_ostream *OS =
CI.createDefaultOutputFile(true, getCurrentFile());
@@ -226,8 +216,7 @@ void ParseOnlyAction::ExecuteAction() {
llvm::OwningPtr<Action> PA(new MinimalAction(PP));
Parser P(PP, *PA);
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
P.ParseTranslationUnit();
}
@@ -236,8 +225,7 @@ void PreprocessOnlyAction::ExecuteAction() {
Token Tok;
// Start parsing the specified input file.
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
do {
PP.Lex(Tok);
} while (Tok.isNot(tok::eof));
@@ -252,8 +240,7 @@ void PrintParseAction::ExecuteAction() {
llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS));
Parser P(PP, *PA);
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
P.ParseTranslationUnit();
}
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 9f5bced..12a4d4d 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -355,7 +355,7 @@ static bool getVisualStudioDir(std::string &path) {
else if (vs80comntools)
vscomntools = vs80comntools;
if (vscomntools && *vscomntools) {
- char *p = (char*)strstr(vscomntools, "\\Common7\\Tools");
+ char *p = const_cast<char *>(strstr(vscomntools, "\\Common7\\Tools"));
if (p)
*p = '\0';
path = vscomntools;
@@ -429,6 +429,49 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) {
}
}
break;
+ case llvm::Triple::Haiku:
+ AddPath("/boot/common/include", System, true, false, false);
+ AddPath("/boot/develop/headers/os", System, true, false, false);
+ AddPath("/boot/develop/headers/os/app", System, true, false, false);
+ AddPath("/boot/develop/headers/os/arch", System, true, false, false);
+ AddPath("/boot/develop/headers/os/device", System, true, false, false);
+ AddPath("/boot/develop/headers/os/drivers", System, true, false, false);
+ AddPath("/boot/develop/headers/os/game", System, true, false, false);
+ AddPath("/boot/develop/headers/os/interface", System, true, false, false);
+ AddPath("/boot/develop/headers/os/kernel", System, true, false, false);
+ AddPath("/boot/develop/headers/os/locale", System, true, false, false);
+ AddPath("/boot/develop/headers/os/mail", System, true, false, false);
+ AddPath("/boot/develop/headers/os/media", System, true, false, false);
+ AddPath("/boot/develop/headers/os/midi", System, true, false, false);
+ AddPath("/boot/develop/headers/os/midi2", System, true, false, false);
+ AddPath("/boot/develop/headers/os/net", System, true, false, false);
+ AddPath("/boot/develop/headers/os/storage", System, true, false, false);
+ AddPath("/boot/develop/headers/os/support", System, true, false, false);
+ AddPath("/boot/develop/headers/os/translation",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/add-ons/graphics",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/add-ons/input_server",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/add-ons/screen_saver",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/add-ons/tracker",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/be_apps/Deskbar",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/be_apps/NetPositive",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/be_apps/Tracker",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/cpp", System, true, false, false);
+ AddPath("/boot/develop/headers/cpp/i586-pc-haiku",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/3rdparty", System, true, false, false);
+ AddPath("/boot/develop/headers/bsd", System, true, false, false);
+ AddPath("/boot/develop/headers/glibc", System, true, false, false);
+ AddPath("/boot/develop/headers/posix", System, true, false, false);
+ AddPath("/boot/develop/headers", System, true, false, false);
+ break;
case llvm::Triple::MinGW64:
case llvm::Triple::MinGW32:
AddPath("c:/mingw/include", System, true, false, false);
@@ -521,14 +564,26 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1",
"i586-redhat-linux","", "", triple);
+ // Fedora 11 x86_64
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1",
+ "x86_64-redhat-linux", "32", "", triple);
+
// Fedora 12
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
"i686-redhat-linux","", "", triple);
+ // Fedora 12 x86_64
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ "x86_64-redhat-linux", "32", "", triple);
+
// Fedora 12 (February-2010+)
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
"i686-redhat-linux","", "", triple);
-
+
+ // Fedora 12 (February-2010+) x86_64
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
+ "x86_64-redhat-linux", "32", "", triple);
+
// openSUSE 11.1 32 bit
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
"i586-suse-linux", "", "", triple);
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 8bcd3a8..f1e9819 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/Version.h"
#include "clang/Frontend/Utils.h"
#include "clang/Basic/MacroBuilder.h"
#include "clang/Basic/TargetInfo.h"
@@ -212,7 +213,20 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// Compiler version introspection macros.
Builder.defineMacro("__llvm__"); // LLVM Backend
Builder.defineMacro("__clang__"); // Clang Frontend
-
+#define TOSTR2(X) #X
+#define TOSTR(X) TOSTR2(X)
+ Builder.defineMacro("__clang_major__", TOSTR(CLANG_VERSION_MAJOR));
+ Builder.defineMacro("__clang_minor__", TOSTR(CLANG_VERSION_MINOR));
+#ifdef CLANG_VERSION_PATCHLEVEL
+ Builder.defineMacro("__clang_patchlevel__", TOSTR(CLANG_VERSION_PATCHLEVEL));
+#else
+ Builder.defineMacro("__clang_patchlevel__", "0");
+#endif
+ Builder.defineMacro("__clang_version__",
+ "\"" CLANG_VERSION_STRING " ("
+ + getClangFullRepositoryVersion() + ")\"");
+#undef TOSTR
+#undef TOSTR2
// Currently claim to be compatible with GCC 4.2.1-5621.
Builder.defineMacro("__GNUC_MINOR__", "2");
Builder.defineMacro("__GNUC_PATCHLEVEL__", "1");
@@ -294,8 +308,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// C++ translation unit.
Builder.defineMacro("__cplusplus", "199711L");
Builder.defineMacro("__private_extern__", "extern");
- // Ugly hack to work with GNU libstdc++.
- Builder.defineMacro("_GNU_SOURCE");
}
if (LangOpts.Microsoft) {
@@ -503,7 +515,11 @@ void clang::InitializePreprocessor(Preprocessor &PP,
InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(),
PP.getFileManager(), InitOpts);
- Builder.append("# 1 \"<built-in>\" 3");
+ // Emit line markers for various builtin sections of the file. We don't do
+ // this in asm preprocessor mode, because "# 4" is not a line marker directive
+ // in this mode.
+ if (!PP.getLangOptions().AsmPreprocessor)
+ Builder.append("# 1 \"<built-in>\" 3");
// Install things like __POWERPC__, __GNUC__, etc into the macro table.
if (InitOpts.UsePredefines)
@@ -512,7 +528,8 @@ void clang::InitializePreprocessor(Preprocessor &PP,
// Add on the predefines from the driver. Wrap in a #line directive to report
// that they come from the command line.
- Builder.append("# 1 \"<command line>\" 1");
+ if (!PP.getLangOptions().AsmPreprocessor)
+ 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) {
@@ -538,7 +555,8 @@ void clang::InitializePreprocessor(Preprocessor &PP,
}
// Exit the command line and go back to <built-in> (2 is LC_LEAVE).
- Builder.append("# 1 \"<built-in>\" 2");
+ if (!PP.getLangOptions().AsmPreprocessor)
+ Builder.append("# 1 \"<built-in>\" 2");
// Copy PredefinedBuffer into the Preprocessor.
PP.setPredefines(Predefines.str());
diff --git a/lib/Frontend/LangStandards.cpp b/lib/Frontend/LangStandards.cpp
index ed0ea1f..af1721d 100644
--- a/lib/Frontend/LangStandards.cpp
+++ b/lib/Frontend/LangStandards.cpp
@@ -22,7 +22,7 @@ const LangStandard &LangStandard::getLangStandardForKind(Kind K) {
default:
llvm_unreachable("Invalid language kind!");
case lang_unspecified:
- llvm::llvm_report_error("getLangStandardForKind() on unspecified kind");
+ llvm::report_fatal_error("getLangStandardForKind() on unspecified kind");
#define LANGSTANDARD(id, name, desc, features) \
case lang_##id: return Lang_##id;
#include "clang/Frontend/LangStandards.def"
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index b96c04d0..ae57ce5 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -62,6 +62,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
PARSE_LANGOPT_BENIGN(DollarIdents);
PARSE_LANGOPT_BENIGN(AsmPreprocessor);
PARSE_LANGOPT_IMPORTANT(GNUMode, diag::warn_pch_gnu_extensions);
+ PARSE_LANGOPT_IMPORTANT(GNUKeywords, diag::warn_pch_gnu_keywords);
PARSE_LANGOPT_BENIGN(ImplicitInt);
PARSE_LANGOPT_BENIGN(Digraphs);
PARSE_LANGOPT_BENIGN(HexFloats);
@@ -74,6 +75,8 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
PARSE_LANGOPT_IMPORTANT(ObjC2, diag::warn_pch_objective_c2);
PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi);
PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI2, diag::warn_pch_nonfragile_abi2);
+ PARSE_LANGOPT_IMPORTANT(NoConstantCFStrings,
+ diag::warn_pch_no_constant_cfstrings);
PARSE_LANGOPT_BENIGN(PascalStrings);
PARSE_LANGOPT_BENIGN(WritableStrings);
PARSE_LANGOPT_IMPORTANT(LaxVectorConversions,
@@ -910,8 +913,14 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
return Failure;
}
- if ((off_t)Record[4] != File->getSize() ||
- (time_t)Record[5] != File->getModificationTime()) {
+ if ((off_t)Record[4] != File->getSize()
+#if !defined(LLVM_ON_WIN32)
+ // In our regression testing, the Windows file system seems to
+ // have inconsistent modification times that sometimes
+ // erroneously trigger this error-handling path.
+ || (time_t)Record[5] != File->getModificationTime()
+#endif
+ ) {
Diag(diag::err_fe_pch_file_modified)
<< Filename;
return Failure;
@@ -1757,17 +1766,16 @@ void PCHReader::InitializeContext(ASTContext &Ctx) {
if (unsigned ObjCClassRedef
= SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS_REDEFINITION])
Context->ObjCClassRedefinitionType = GetType(ObjCClassRedef);
-#if 0
- // FIXME. Accommodate for this in several PCH/Index tests
- if (unsigned ObjCSelRedef
- = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SEL_REDEFINITION])
- Context->ObjCSelRedefinitionType = GetType(ObjCSelRedef);
-#endif
if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_DESCRIPTOR])
Context->setBlockDescriptorType(GetType(String));
if (unsigned String
= SpecialTypes[pch::SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR])
Context->setBlockDescriptorExtendedType(GetType(String));
+ if (unsigned ObjCSelRedef
+ = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SEL_REDEFINITION])
+ Context->ObjCSelRedefinitionType = GetType(ObjCSelRedef);
+ if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_NS_CONSTANT_STRING])
+ Context->setNSConstantStringType(GetType(String));
}
/// \brief Retrieve the name of the original source file name
@@ -1879,6 +1887,7 @@ bool PCHReader::ParseLanguageOptions(
PARSE_LANGOPT(DollarIdents);
PARSE_LANGOPT(AsmPreprocessor);
PARSE_LANGOPT(GNUMode);
+ PARSE_LANGOPT(GNUKeywords);
PARSE_LANGOPT(ImplicitInt);
PARSE_LANGOPT(Digraphs);
PARSE_LANGOPT(HexFloats);
@@ -1891,6 +1900,7 @@ bool PCHReader::ParseLanguageOptions(
PARSE_LANGOPT(ObjC2);
PARSE_LANGOPT(ObjCNonFragileABI);
PARSE_LANGOPT(ObjCNonFragileABI2);
+ PARSE_LANGOPT(NoConstantCFStrings);
PARSE_LANGOPT(PascalStrings);
PARSE_LANGOPT(WritableStrings);
PARSE_LANGOPT(LaxVectorConversions);
@@ -2843,6 +2853,14 @@ Selector PCHReader::DecodeSelector(unsigned ID) {
return SelectorsLoaded[Index];
}
+Selector PCHReader::GetSelector(uint32_t ID) {
+ return DecodeSelector(ID);
+}
+
+uint32_t PCHReader::GetNumKnownSelectors() {
+ return TotalNumSelectors + 1;
+}
+
DeclarationName
PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index f847bec..14dd2e9 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -179,6 +179,7 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->setPreviousDeclaration(
cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]);
+ FD->setStorageClassAsWritten((FunctionDecl::StorageClass)Record[Idx++]);
FD->setInlineSpecified(Record[Idx++]);
FD->setVirtualAsWritten(Record[Idx++]);
FD->setPure(Record[Idx++]);
@@ -196,6 +197,11 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
for (unsigned I = 0; I != NumParams; ++I)
Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
FD->setParams(Params.data(), NumParams);
+
+ // FIXME: order this properly w.r.t. friendness
+ // FIXME: this same thing needs to happen for function templates
+ if (FD->isOverloadedOperator() && !FD->getDeclContext()->isRecord())
+ FD->setNonMemberOperator();
}
void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
@@ -212,6 +218,7 @@ void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
MD->setSynthesized(Record[Idx++]);
MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]);
MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
+ MD->setNumSelectorArgs(unsigned(Record[Idx++]));
MD->setResultType(Reader.GetType(Record[Idx++]));
MD->setResultTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
MD->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
@@ -220,7 +227,8 @@ void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
Params.reserve(NumParams);
for (unsigned I = 0; I != NumParams; ++I)
Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
- MD->setMethodParams(*Reader.getContext(), Params.data(), NumParams);
+ MD->setMethodParams(*Reader.getContext(), Params.data(), NumParams,
+ NumParams);
}
void PCHDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
@@ -375,6 +383,7 @@ void PCHDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
VisitObjCImplDecl(D);
D->setSuperClass(
cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+ // FIXME. Add reading of IvarInitializers and NumIvarInitializers.
}
@@ -397,9 +406,11 @@ void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) {
void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
VisitDeclaratorDecl(VD);
VD->setStorageClass((VarDecl::StorageClass)Record[Idx++]);
+ VD->setStorageClassAsWritten((VarDecl::StorageClass)Record[Idx++]);
VD->setThreadSpecified(Record[Idx++]);
VD->setCXXDirectInitializer(Record[Idx++]);
VD->setDeclaredInCondition(Record[Idx++]);
+ VD->setExceptionVariable(Record[Idx++]);
VD->setPreviousDeclaration(
cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
if (Record[Idx++])
@@ -744,7 +755,7 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
break;
case pch::DECL_VAR:
D = VarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
- VarDecl::None);
+ VarDecl::None, VarDecl::None);
break;
case pch::DECL_IMPLICIT_PARAM:
@@ -753,7 +764,7 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
case pch::DECL_PARM_VAR:
D = ParmVarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
- VarDecl::None, 0);
+ VarDecl::None, VarDecl::None, 0);
break;
case pch::DECL_FILE_SCOPE_ASM:
D = FileScopeAsmDecl::Create(*Context, 0, SourceLocation(), 0);
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index 7b94805..ef6b770 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -71,6 +71,7 @@ namespace {
unsigned VisitCharacterLiteral(CharacterLiteral *E);
unsigned VisitParenExpr(ParenExpr *E);
unsigned VisitUnaryOperator(UnaryOperator *E);
+ unsigned VisitOffsetOfExpr(OffsetOfExpr *E);
unsigned VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
unsigned VisitArraySubscriptExpr(ArraySubscriptExpr *E);
unsigned VisitCallExpr(CallExpr *E);
@@ -432,6 +433,49 @@ unsigned PCHStmtReader::VisitUnaryOperator(UnaryOperator *E) {
return 1;
}
+unsigned PCHStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
+ typedef OffsetOfExpr::OffsetOfNode Node;
+ VisitExpr(E);
+ assert(E->getNumComponents() == Record[Idx]);
+ ++Idx;
+ assert(E->getNumExpressions() == Record[Idx]);
+ ++Idx;
+ E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
+ for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
+ Node::Kind Kind = static_cast<Node::Kind>(Record[Idx++]);
+ SourceLocation Start = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation End = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ switch (Kind) {
+ case Node::Array:
+ E->setComponent(I, Node(Start, Record[Idx++], End));
+ break;
+
+ case Node::Field:
+ E->setComponent(I,
+ Node(Start,
+ dyn_cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])),
+ End));
+ break;
+
+ case Node::Identifier:
+ E->setComponent(I, Node(Start, Reader.GetIdentifier(Record[Idx++]), End));
+ break;
+
+ case Node::Base:
+ // FIXME: Implement this!
+ llvm_unreachable("PCH for offsetof(base-specifier) not implemented");
+ break;
+ }
+ }
+
+ for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I)
+ E->setIndexExpr(I, cast_or_null<Expr>(StmtStack[StmtStack.size() - N + I]));
+
+ return E->getNumExpressions();
+}
+
unsigned PCHStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
VisitExpr(E);
E->setSizeof(Record[Idx++]);
@@ -554,9 +598,9 @@ unsigned PCHStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
unsigned PCHStmtReader::VisitInitListExpr(InitListExpr *E) {
VisitExpr(E);
unsigned NumInits = Record[Idx++];
- E->reserveInits(NumInits);
+ E->reserveInits(*Reader.getContext(), NumInits);
for (unsigned I = 0; I != NumInits; ++I)
- E->updateInit(I,
+ E->updateInit(*Reader.getContext(), I,
cast<Expr>(StmtStack[StmtStack.size() - NumInits - 1 + I]));
E->setSyntacticForm(cast_or_null<InitListExpr>(StmtStack.back()));
E->setLBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
@@ -725,7 +769,7 @@ unsigned PCHStmtReader::VisitObjCStringLiteral(ObjCStringLiteral *E) {
unsigned PCHStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
VisitExpr(E);
- E->setEncodedType(Reader.GetType(Record[Idx++]));
+ E->setEncodedTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
return 0;
@@ -782,25 +826,42 @@ unsigned PCHStmtReader::VisitObjCImplicitSetterGetterRefExpr(
unsigned PCHStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
VisitExpr(E);
- E->setNumArgs(Record[Idx++]);
- E->setLeftLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
- E->setRightLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
- E->setSelector(Reader.GetSelector(Record, Idx));
- E->setMethodDecl(cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
-
- E->setReceiver(
+ assert(Record[Idx] == E->getNumArgs());
+ ++Idx;
+ ObjCMessageExpr::ReceiverKind Kind
+ = static_cast<ObjCMessageExpr::ReceiverKind>(Record[Idx++]);
+ switch (Kind) {
+ case ObjCMessageExpr::Instance:
+ E->setInstanceReceiver(
cast_or_null<Expr>(StmtStack[StmtStack.size() - E->getNumArgs() - 1]));
- if (!E->getReceiver()) {
- ObjCMessageExpr::ClassInfo CI;
- CI.Decl = cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]));
- CI.Name = Reader.GetIdentifierInfo(Record, Idx);
- CI.Loc = SourceLocation::getFromRawEncoding(Record[Idx++]);
- E->setClassInfo(CI);
+ break;
+
+ case ObjCMessageExpr::Class:
+ E->setClassReceiver(Reader.GetTypeSourceInfo(Record, Idx));
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ case ObjCMessageExpr::SuperInstance: {
+ QualType T = Reader.GetType(Record[Idx++]);
+ SourceLocation SuperLoc = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ E->setSuper(SuperLoc, T, Kind == ObjCMessageExpr::SuperInstance);
+ break;
}
+ }
+
+ assert(Kind == E->getReceiverKind());
+
+ if (Record[Idx++])
+ E->setMethodDecl(cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
+ else
+ E->setSelector(Reader.GetSelector(Record, Idx));
+
+ E->setLeftLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRightLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I]));
- return E->getNumArgs() + 1;
+ return E->getNumArgs() + (Kind == ObjCMessageExpr::Instance);
}
unsigned PCHStmtReader::VisitObjCSuperExpr(ObjCSuperExpr *E) {
@@ -821,12 +882,11 @@ unsigned PCHStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
unsigned PCHStmtReader::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
VisitStmt(S);
- S->setCatchBody(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 2]));
- S->setNextCatchStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1]));
- S->setCatchParamDecl(cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setCatchBody(cast_or_null<Stmt>(StmtStack.back()));
+ S->setCatchParamDecl(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
S->setAtCatchLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
- return 2;
+ return 1;
}
unsigned PCHStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
@@ -838,11 +898,21 @@ unsigned PCHStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
unsigned PCHStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
VisitStmt(S);
- S->setTryBody(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 3]));
- S->setCatchStmts(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 2]));
- S->setFinallyStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1]));
+ assert(Record[Idx] == S->getNumCatchStmts());
+ ++Idx;
+ bool HasFinally = Record[Idx++];
+ for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) {
+ unsigned Offset = StmtStack.size() - N - HasFinally + I;
+ S->setCatchStmt(I, cast_or_null<ObjCAtCatchStmt>(StmtStack[Offset]));
+ }
+
+ unsigned TryOffset
+ = StmtStack.size() - S->getNumCatchStmts() - HasFinally - 1;
+ S->setTryBody(cast_or_null<Stmt>(StmtStack[TryOffset]));
+ if (HasFinally)
+ S->setFinallyStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1]));
S->setAtTryLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
- return 3;
+ return 1 + S->getNumCatchStmts() + HasFinally;
}
unsigned PCHStmtReader::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
@@ -1079,6 +1149,12 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
S = new (Context) UnaryOperator(Empty);
break;
+ case pch::EXPR_OFFSETOF:
+ S = OffsetOfExpr::CreateEmpty(*Context,
+ Record[PCHStmtReader::NumExprFields],
+ Record[PCHStmtReader::NumExprFields + 1]);
+ break;
+
case pch::EXPR_SIZEOF_ALIGN_OF:
S = new (Context) SizeOfAlignOfExpr(Empty);
break;
@@ -1124,7 +1200,7 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
break;
case pch::EXPR_INIT_LIST:
- S = new (Context) InitListExpr(Empty);
+ S = new (Context) InitListExpr(*getContext(), Empty);
break;
case pch::EXPR_DESIGNATED_INIT:
@@ -1195,7 +1271,8 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
S = new (Context) ObjCImplicitSetterGetterRefExpr(Empty);
break;
case pch::EXPR_OBJC_MESSAGE_EXPR:
- S = new (Context) ObjCMessageExpr(Empty);
+ S = ObjCMessageExpr::CreateEmpty(*Context,
+ Record[PCHStmtReader::NumExprFields]);
break;
case pch::EXPR_OBJC_SUPER_EXPR:
S = new (Context) ObjCSuperExpr(Empty);
@@ -1213,7 +1290,9 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
S = new (Context) ObjCAtFinallyStmt(Empty);
break;
case pch::STMT_OBJC_AT_TRY:
- S = new (Context) ObjCAtTryStmt(Empty);
+ S = ObjCAtTryStmt::CreateEmpty(*Context,
+ Record[PCHStmtReader::NumStmtFields],
+ Record[PCHStmtReader::NumStmtFields + 1]);
break;
case pch::STMT_OBJC_AT_SYNCHRONIZED:
S = new (Context) ObjCAtSynchronizedStmt(Empty);
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 4dd8dc3..e56dd31 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -1,4 +1,4 @@
-//===--- PCHWriter.h - Precompiled Headers Writer ---------------*- C++ -*-===//
+//===--- PCHWriter.cpp - Precompiled Headers Writer -----------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -63,6 +63,7 @@ namespace {
#define ABSTRACT_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base)
#include "clang/AST/TypeNodes.def"
+ void VisitInjectedClassNameType(const InjectedClassNameType *T);
};
}
@@ -240,7 +241,7 @@ void PCHTypeWriter::VisitQualifiedNameType(const QualifiedNameType *T) {
void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
Writer.AddDeclRef(T->getDecl(), Record);
- Writer.AddTypeRef(T->getUnderlyingType(), Record);
+ Writer.AddTypeRef(T->getInjectedSpecializationType(), Record);
Code = pch::TYPE_INJECTED_CLASS_NAME;
}
@@ -745,6 +746,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
Record.push_back(LangOpts.DollarIdents); // '$' allowed in identifiers.
Record.push_back(LangOpts.AsmPreprocessor); // Preprocessor in asm mode.
Record.push_back(LangOpts.GNUMode); // True in gnu99 mode false in c99 mode (etc)
+ Record.push_back(LangOpts.GNUKeywords); // Allow GNU-extension keywords
Record.push_back(LangOpts.ImplicitInt); // C89 implicit 'int'.
Record.push_back(LangOpts.Digraphs); // C94, C99 and C++
Record.push_back(LangOpts.HexFloats); // C99 Hexadecimal float constants.
@@ -760,6 +762,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
// modern abi enabled.
Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced
// modern abi enabled.
+ Record.push_back(LangOpts.NoConstantCFStrings); // non cfstring generation enabled..
Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings
Record.push_back(LangOpts.WritableStrings); // Allow writable strings
@@ -1103,7 +1106,7 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// that is required by llvm::MemoryBuffer::getMemBuffer (on
// the reader side).
const llvm::MemoryBuffer *Buffer
- = Content->getBuffer(PP.getDiagnostics());
+ = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
const char *Name = Buffer->getBufferIdentifier();
Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record,
llvm::StringRef(Name, strlen(Name) + 1));
@@ -2093,12 +2096,10 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
AddTypeRef(Context.getsigjmp_bufType(), Record);
AddTypeRef(Context.ObjCIdRedefinitionType, Record);
AddTypeRef(Context.ObjCClassRedefinitionType, Record);
-#if 0
- // FIXME. Accommodate for this in several PCH/Indexer tests
- AddTypeRef(Context.ObjCSelRedefinitionType, Record);
-#endif
AddTypeRef(Context.getRawBlockdescriptorType(), Record);
AddTypeRef(Context.getRawBlockdescriptorExtendedType(), Record);
+ AddTypeRef(Context.ObjCSelRedefinitionType, Record);
+ AddTypeRef(Context.getRawNSConstantStringType(), Record);
Stream.EmitRecord(pch::SPECIAL_TYPES, Record);
// Keep writing types and declarations until all types and
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index 7917280..7b780623 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -176,6 +176,7 @@ void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Writer.AddStmt(D->getBody());
Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
Record.push_back(D->getStorageClass()); // FIXME: stable encoding
+ Record.push_back(D->getStorageClassAsWritten());
Record.push_back(D->isInlineSpecified());
Record.push_back(D->isVirtualAsWritten());
Record.push_back(D->isPure());
@@ -211,6 +212,7 @@ void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Record.push_back(D->getImplementationControl());
// FIXME: stable encoding for in/out/inout/bycopy/byref/oneway
Record.push_back(D->getObjCDeclQualifier());
+ Record.push_back(D->getNumSelectorArgs());
Writer.AddTypeRef(D->getResultType(), Record);
Writer.AddTypeSourceInfo(D->getResultTypeSourceInfo(), Record);
Writer.AddSourceLocation(D->getLocEnd(), Record);
@@ -359,6 +361,7 @@ void PCHDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
void PCHDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
VisitObjCImplDecl(D);
Writer.AddDeclRef(D->getSuperClass(), Record);
+ // FIXME add writing of IvarInitializers and NumIvarInitializers.
Code = pch::DECL_OBJC_IMPLEMENTATION;
}
@@ -382,9 +385,11 @@ void PCHDeclWriter::VisitFieldDecl(FieldDecl *D) {
void PCHDeclWriter::VisitVarDecl(VarDecl *D) {
VisitDeclaratorDecl(D);
Record.push_back(D->getStorageClass()); // FIXME: stable encoding
+ Record.push_back(D->getStorageClassAsWritten());
Record.push_back(D->isThreadSpecified());
Record.push_back(D->hasCXXDirectInitializer());
Record.push_back(D->isDeclaredInCondition());
+ Record.push_back(D->isExceptionVariable());
Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
Record.push_back(D->getInit()? 1 : 0);
if (D->getInit())
@@ -425,6 +430,7 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
assert(!D->isThreadSpecified() && "PARM_VAR_DECL can't be __thread");
assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private");
assert(!D->isDeclaredInCondition() && "PARM_VAR_DECL can't be in condition");
+ assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var");
assert(D->getPreviousDeclaration() == 0 && "PARM_VAR_DECL can't be redecl");
assert(D->getInit() == 0 && "PARM_VAR_DECL never has init");
}
@@ -493,9 +499,11 @@ void PCHWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(pch::PREDEF_TYPE_NULL_ID)); // InfoType
// VarDecl
Abv->Add(BitCodeAbbrevOp(0)); // StorageClass
+ Abv->Add(BitCodeAbbrevOp(0)); // StorageClassAsWritten
Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified
Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer
Abv->Add(BitCodeAbbrevOp(0)); // isDeclaredInCondition
+ Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable
Abv->Add(BitCodeAbbrevOp(0)); // PrevDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
// ParmVarDecl
@@ -608,7 +616,7 @@ void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) {
if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset);
if (!W.Code)
- llvm::llvm_report_error(llvm::StringRef("unexpected declaration kind '") +
+ llvm::report_fatal_error(llvm::StringRef("unexpected declaration kind '") +
D->getDeclKindName() + "'");
Stream.EmitRecord(W.Code, Record, W.AbbrevToUse);
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index 9a5417c..a1993d3 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -62,6 +62,7 @@ namespace {
void VisitCharacterLiteral(CharacterLiteral *E);
void VisitParenExpr(ParenExpr *E);
void VisitUnaryOperator(UnaryOperator *E);
+ void VisitOffsetOfExpr(OffsetOfExpr *E);
void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
void VisitArraySubscriptExpr(ArraySubscriptExpr *E);
void VisitCallExpr(CallExpr *E);
@@ -393,6 +394,42 @@ void PCHStmtWriter::VisitUnaryOperator(UnaryOperator *E) {
Code = pch::EXPR_UNARY_OPERATOR;
}
+void PCHStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumComponents());
+ Record.push_back(E->getNumExpressions());
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record);
+ for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
+ const OffsetOfExpr::OffsetOfNode &ON = E->getComponent(I);
+ Record.push_back(ON.getKind()); // FIXME: Stable encoding
+ Writer.AddSourceLocation(ON.getRange().getBegin(), Record);
+ Writer.AddSourceLocation(ON.getRange().getEnd(), Record);
+ switch (ON.getKind()) {
+ case OffsetOfExpr::OffsetOfNode::Array:
+ Record.push_back(ON.getArrayExprIndex());
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Field:
+ Writer.AddDeclRef(ON.getField(), Record);
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Identifier:
+ Writer.AddIdentifierRef(ON.getFieldName(), Record);
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Base:
+ // FIXME: Implement this!
+ llvm_unreachable("PCH for offsetof(base-specifier) not implemented");
+ break;
+ }
+ }
+ for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I)
+ Writer.WriteSubStmt(E->getIndexExpr(I));
+ Code = pch::EXPR_OFFSETOF;
+}
+
void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
VisitExpr(E);
Record.push_back(E->isSizeOf());
@@ -655,7 +692,7 @@ void PCHStmtWriter::VisitObjCStringLiteral(ObjCStringLiteral *E) {
void PCHStmtWriter::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
VisitExpr(E);
- Writer.AddTypeRef(E->getEncodedType(), Record);
+ Writer.AddTypeSourceInfo(E->getEncodedTypeSourceInfo(), Record);
Writer.AddSourceLocation(E->getAtLoc(), Record);
Writer.AddSourceLocation(E->getRParenLoc(), Record);
Code = pch::EXPR_OBJC_ENCODE;
@@ -712,18 +749,33 @@ void PCHStmtWriter::VisitObjCImplicitSetterGetterRefExpr(
void PCHStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
VisitExpr(E);
Record.push_back(E->getNumArgs());
+ Record.push_back((unsigned)E->getReceiverKind()); // FIXME: stable encoding
+ switch (E->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ Writer.WriteSubStmt(E->getInstanceReceiver());
+ break;
+
+ case ObjCMessageExpr::Class:
+ Writer.AddTypeSourceInfo(E->getClassReceiverTypeInfo(), Record);
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ case ObjCMessageExpr::SuperInstance:
+ Writer.AddTypeRef(E->getSuperType(), Record);
+ Writer.AddSourceLocation(E->getSuperLoc(), Record);
+ break;
+ }
+
+ if (E->getMethodDecl()) {
+ Record.push_back(1);
+ Writer.AddDeclRef(E->getMethodDecl(), Record);
+ } else {
+ Record.push_back(0);
+ Writer.AddSelectorRef(E->getSelector(), Record);
+ }
+
Writer.AddSourceLocation(E->getLeftLoc(), Record);
Writer.AddSourceLocation(E->getRightLoc(), Record);
- Writer.AddSelectorRef(E->getSelector(), Record);
- Writer.AddDeclRef(E->getMethodDecl(), Record); // optional
- Writer.WriteSubStmt(E->getReceiver());
-
- if (!E->getReceiver()) {
- ObjCMessageExpr::ClassInfo CI = E->getClassInfo();
- Writer.AddDeclRef(CI.Decl, Record);
- Writer.AddIdentifierRef(CI.Name, Record);
- Writer.AddSourceLocation(CI.Loc, Record);
- }
for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end();
Arg != ArgEnd; ++Arg)
@@ -749,7 +801,6 @@ void PCHStmtWriter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
void PCHStmtWriter::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
Writer.WriteSubStmt(S->getCatchBody());
- Writer.WriteSubStmt(S->getNextCatchStmt());
Writer.AddDeclRef(S->getCatchParamDecl(), Record);
Writer.AddSourceLocation(S->getAtCatchLoc(), Record);
Writer.AddSourceLocation(S->getRParenLoc(), Record);
@@ -763,9 +814,13 @@ void PCHStmtWriter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
}
void PCHStmtWriter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
+ Record.push_back(S->getNumCatchStmts());
+ Record.push_back(S->getFinallyStmt() != 0);
Writer.WriteSubStmt(S->getTryBody());
- Writer.WriteSubStmt(S->getCatchStmts());
- Writer.WriteSubStmt(S->getFinallyStmt());
+ for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I)
+ Writer.WriteSubStmt(S->getCatchStmt(I));
+ if (S->getFinallyStmt())
+ Writer.WriteSubStmt(S->getFinallyStmt());
Writer.AddSourceLocation(S->getAtTryLoc(), Record);
Code = pch::STMT_OBJC_AT_TRY;
}
diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp
index 8d64a64..4df5c52 100644
--- a/lib/Frontend/PrintParserCallbacks.cpp
+++ b/lib/Frontend/PrintParserCallbacks.cpp
@@ -197,7 +197,7 @@ namespace {
}
virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
- SourceLocation KWLoc, const CXXScopeSpec &SS,
+ SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
MultiTemplateParamsArg TemplateParameterLists,
@@ -405,8 +405,8 @@ namespace {
// Objective-c statements
virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
SourceLocation RParen,
- DeclPtrTy Parm, StmtArg Body,
- StmtArg CatchList) {
+ DeclPtrTy Parm,
+ StmtArg Body) {
Out << __FUNCTION__ << "\n";
return StmtEmpty();
}
@@ -418,7 +418,8 @@ namespace {
}
virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
- StmtArg Try, StmtArg Catch,
+ StmtArg Try,
+ MultiStmtArg CatchStmts,
StmtArg Finally) {
Out << __FUNCTION__ << "\n";
return StmtEmpty();
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 02afd24..b6c18b7 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -78,6 +78,7 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI,
namespace {
class PrintPPOutputPPCallbacks : public PPCallbacks {
Preprocessor &PP;
+ SourceManager &SM;
TokenConcatenation ConcatInfo;
public:
llvm::raw_ostream &OS;
@@ -94,7 +95,8 @@ private:
public:
PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os,
bool lineMarkers, bool defines)
- : PP(pp), ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers),
+ : PP(pp), SM(PP.getSourceManager()),
+ ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers),
DumpDefines(defines) {
CurLine = 0;
CurFilename += "<uninit>";
@@ -118,9 +120,14 @@ public:
bool HandleFirstTokOnLine(Token &Tok);
- bool MoveToLine(SourceLocation Loc);
- bool AvoidConcat(const Token &PrevTok, const Token &Tok) {
- return ConcatInfo.AvoidConcat(PrevTok, Tok);
+ bool MoveToLine(SourceLocation Loc) {
+ return MoveToLine(SM.getPresumedLoc(Loc).getLine());
+ }
+ bool MoveToLine(unsigned LineNo);
+
+ bool AvoidConcat(const Token &PrevPrevTok, const Token &PrevTok,
+ const Token &Tok) {
+ return ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok);
}
void WriteLineInfo(unsigned LineNo, const char *Extra=0, unsigned ExtraLen=0);
@@ -166,9 +173,7 @@ void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
/// object. We can do this by emitting some number of \n's, or be emitting a
/// #line directive. This returns false if already at the specified line, true
/// if some newlines were emitted.
-bool PrintPPOutputPPCallbacks::MoveToLine(SourceLocation Loc) {
- unsigned LineNo = PP.getSourceManager().getInstantiationLineNumber(Loc);
-
+bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo) {
if (DisableLineMarkers) {
if (LineNo == CurLine) return false;
@@ -211,27 +216,29 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
SrcMgr::CharacteristicKind NewFileType) {
// Unless we are exiting a #include, make sure to skip ahead to the line the
// #include directive was at.
- SourceManager &SourceMgr = PP.getSourceManager();
+ SourceManager &SourceMgr = SM;
+
+ PresumedLoc UserLoc = SourceMgr.getPresumedLoc(Loc);
+ unsigned NewLine = UserLoc.getLine();
+
if (Reason == PPCallbacks::EnterFile) {
SourceLocation IncludeLoc = SourceMgr.getPresumedLoc(Loc).getIncludeLoc();
if (IncludeLoc.isValid())
MoveToLine(IncludeLoc);
} else if (Reason == PPCallbacks::SystemHeaderPragma) {
- MoveToLine(Loc);
+ MoveToLine(NewLine);
// TODO GCC emits the # directive for this directive on the line AFTER the
// directive and emits a bunch of spaces that aren't needed. Emulate this
// strange behavior.
}
-
- Loc = SourceMgr.getInstantiationLoc(Loc);
- // FIXME: Should use presumed line #!
- CurLine = SourceMgr.getInstantiationLineNumber(Loc);
+
+ CurLine = NewLine;
if (DisableLineMarkers) return;
CurFilename.clear();
- CurFilename += SourceMgr.getPresumedLoc(Loc).getFilename();
+ CurFilename += UserLoc.getFilename();
Lexer::Stringify(CurFilename);
FileType = NewFileType;
@@ -318,8 +325,7 @@ bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) {
// Print out space characters so that the first token on a line is
// indented for easy reading.
- const SourceManager &SourceMgr = PP.getSourceManager();
- unsigned ColNo = SourceMgr.getInstantiationColumnNumber(Tok.getLocation());
+ unsigned ColNo = SM.getInstantiationColumnNumber(Tok.getLocation());
// This hack prevents stuff like:
// #define HASH #
@@ -391,6 +397,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
PrintPPOutputPPCallbacks *Callbacks,
llvm::raw_ostream &OS) {
char Buffer[256];
+ Token PrevPrevTok;
Token PrevTok;
while (1) {
@@ -402,7 +409,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
// useful to look at and no concatenation could happen anyway.
(Callbacks->hasEmittedTokensOnThisLine() &&
// Don't print "-" next to "-", it would form "--".
- Callbacks->AvoidConcat(PrevTok, Tok))) {
+ Callbacks->AvoidConcat(PrevPrevTok, PrevTok, Tok))) {
OS << ' ';
}
@@ -433,6 +440,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
if (Tok.is(tok::eof)) break;
+ PrevPrevTok = PrevTok;
PrevTok = Tok;
PP.Lex(Tok);
}
@@ -448,8 +456,7 @@ static int MacroIDCompare(const void* a, const void* b) {
static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
// -dM mode just scans and ignores all tokens in the files, then dumps out
// the macro table at the end.
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
Token Tok;
do PP.Lex(Tok);
@@ -484,8 +491,6 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS,
// to -C or -CC.
PP.SetCommentRetentionState(Opts.ShowComments, Opts.ShowMacroComments);
- OS->SetBufferSize(64*1024);
-
PrintPPOutputPPCallbacks *Callbacks =
new PrintPPOutputPPCallbacks(PP, *OS, !Opts.ShowLineMarkers,
Opts.ShowMacros);
@@ -496,8 +501,7 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS,
PP.addPPCallbacks(Callbacks);
// After we have configured the preprocessor, enter the main file.
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
// Consume all of the tokens that come from the predefines buffer. Those
// should not be emitted into the output and are guaranteed to be at the
diff --git a/lib/Frontend/RewriteMacros.cpp b/lib/Frontend/RewriteMacros.cpp
index 4ffb297..954e8e2 100644
--- a/lib/Frontend/RewriteMacros.cpp
+++ b/lib/Frontend/RewriteMacros.cpp
@@ -101,8 +101,7 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
// Get the first preprocessing token.
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
Token PPTok;
PP.Lex(PPTok);
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index cba9298..1169832 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -444,7 +444,7 @@ namespace {
CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty,
CastExpr::CastKind Kind, Expr *E) {
TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation());
- return new (Ctx) CStyleCastExpr(Ty, Kind, E, TInfo,
+ return new (Ctx) CStyleCastExpr(Ty, Kind, E, CXXBaseSpecifierArray(), TInfo,
SourceLocation(), SourceLocation());
}
}
@@ -640,7 +640,9 @@ void RewriteObjC::Initialize(ASTContext &context) {
if (LangOpts.Microsoft) {
Preamble += "#undef __OBJC_RW_DLLIMPORT\n";
Preamble += "#undef __OBJC_RW_STATICIMPORT\n";
+ Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests.
Preamble += "#define __attribute__(X)\n";
+ Preamble += "#endif\n";
Preamble += "#define __weak\n";
}
else {
@@ -1237,11 +1239,26 @@ Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
// This allows us to handle chain/nested property getters.
Receiver = PropGetters[PRE];
}
- MsgExpr = new (Context) ObjCMessageExpr(*Context, dyn_cast<Expr>(Receiver),
- PDecl->getSetterName(), PDecl->getType(),
- PDecl->getSetterMethodDecl(),
- SourceLocation(), SourceLocation(),
- &ExprVec[0], 1);
+ if (isa<ObjCSuperExpr>(Receiver))
+ MsgExpr = ObjCMessageExpr::Create(*Context,
+ PDecl->getType().getNonReferenceType(),
+ /*FIXME?*/SourceLocation(),
+ Receiver->getLocStart(),
+ /*IsInstanceSuper=*/true,
+ cast<Expr>(Receiver)->getType(),
+ PDecl->getSetterName(),
+ PDecl->getSetterMethodDecl(),
+ &ExprVec[0], 1,
+ /*FIXME:*/SourceLocation());
+ else
+ MsgExpr = ObjCMessageExpr::Create(*Context,
+ PDecl->getType().getNonReferenceType(),
+ /*FIXME: */SourceLocation(),
+ cast<Expr>(Receiver),
+ PDecl->getSetterName(),
+ PDecl->getSetterMethodDecl(),
+ &ExprVec[0], 1,
+ /*FIXME:*/SourceLocation());
Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr);
// Now do the actual rewrite.
@@ -1266,11 +1283,27 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) {
// This allows us to handle chain/nested property getters.
Receiver = PropGetters[PRE];
}
- MsgExpr = new (Context) ObjCMessageExpr(*Context, dyn_cast<Expr>(Receiver),
- PDecl->getGetterName(), PDecl->getType(),
- PDecl->getGetterMethodDecl(),
- SourceLocation(), SourceLocation(),
- 0, 0);
+
+ if (isa<ObjCSuperExpr>(Receiver))
+ MsgExpr = ObjCMessageExpr::Create(*Context,
+ PDecl->getType().getNonReferenceType(),
+ /*FIXME:*/SourceLocation(),
+ Receiver->getLocStart(),
+ /*IsInstanceSuper=*/true,
+ cast<Expr>(Receiver)->getType(),
+ PDecl->getGetterName(),
+ PDecl->getGetterMethodDecl(),
+ 0, 0,
+ /*FIXME:*/SourceLocation());
+ else
+ MsgExpr = ObjCMessageExpr::Create(*Context,
+ PDecl->getType().getNonReferenceType(),
+ /*FIXME:*/SourceLocation(),
+ cast<Expr>(Receiver),
+ PDecl->getGetterName(),
+ PDecl->getGetterMethodDecl(),
+ 0, 0,
+ /*FIXME:*/SourceLocation());
Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr);
@@ -1828,8 +1861,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
assert((*startBuf == '}') && "bogus @try block");
SourceLocation lastCurlyLoc = startLoc;
- ObjCAtCatchStmt *catchList = S->getCatchStmts();
- if (catchList) {
+ if (S->getNumCatchStmts()) {
startLoc = startLoc.getFileLocWithOffset(1);
buf = " /* @catch begin */ else {\n";
buf += " id _caught = objc_exception_extract(&_stack);\n";
@@ -1847,26 +1879,27 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
}
bool sawIdTypedCatch = false;
Stmt *lastCatchBody = 0;
- while (catchList) {
- ParmVarDecl *catchDecl = catchList->getCatchParamDecl();
+ for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) {
+ ObjCAtCatchStmt *Catch = S->getCatchStmt(I);
+ VarDecl *catchDecl = Catch->getCatchParamDecl();
- if (catchList == S->getCatchStmts())
+ if (I == 0)
buf = "if ("; // we are generating code for the first catch clause
else
buf = "else if (";
- startLoc = catchList->getLocStart();
+ startLoc = Catch->getLocStart();
startBuf = SM->getCharacterData(startLoc);
assert((*startBuf == '@') && "bogus @catch location");
const char *lParenLoc = strchr(startBuf, '(');
- if (catchList->hasEllipsis()) {
+ if (Catch->hasEllipsis()) {
// Now rewrite the body...
- lastCatchBody = catchList->getCatchBody();
+ lastCatchBody = Catch->getCatchBody();
SourceLocation bodyLoc = lastCatchBody->getLocStart();
const char *bodyBuf = SM->getCharacterData(bodyLoc);
- assert(*SM->getCharacterData(catchList->getRParenLoc()) == ')' &&
+ assert(*SM->getCharacterData(Catch->getRParenLoc()) == ')' &&
"bogus @catch paren location");
assert((*bodyBuf == '{') && "bogus @catch body location");
@@ -1890,8 +1923,8 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
}
}
// Now rewrite the body...
- lastCatchBody = catchList->getCatchBody();
- SourceLocation rParenLoc = catchList->getRParenLoc();
+ lastCatchBody = Catch->getCatchBody();
+ SourceLocation rParenLoc = Catch->getRParenLoc();
SourceLocation bodyLoc = lastCatchBody->getLocStart();
const char *bodyBuf = SM->getCharacterData(bodyLoc);
const char *rParenBuf = SM->getCharacterData(rParenLoc);
@@ -1904,8 +1937,6 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
} else {
assert(false && "@catch rewrite bug");
}
- // make sure all the catch bodies get rewritten!
- catchList = catchList->getNextCatchStmt();
}
// Complete the catch list...
if (lastCatchBody) {
@@ -2054,10 +2085,10 @@ CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl(
// Now, we cast the reference to a pointer to the objc_msgSend type.
QualType pToFunc = Context->getPointerType(msgSendType);
- ImplicitCastExpr *ICE = new (Context) ImplicitCastExpr(pToFunc,
- CastExpr::CK_Unknown,
- DRE,
- /*isLvalue=*/false);
+ ImplicitCastExpr *ICE =
+ new (Context) ImplicitCastExpr(pToFunc, CastExpr::CK_Unknown,
+ DRE, CXXBaseSpecifierArray(),
+ /*isLvalue=*/false);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
@@ -2267,7 +2298,8 @@ void RewriteObjC::SynthSelGetUidFunctionDecl() {
SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SelGetUidIdent, getFuncType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) {
@@ -2364,7 +2396,8 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() {
SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
@@ -2385,7 +2418,8 @@ void RewriteObjC::SynthMsgSendFunctionDecl() {
MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...);
@@ -2409,7 +2443,8 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() {
MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...);
@@ -2430,7 +2465,8 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() {
MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
// SynthMsgSendSuperStretFunctionDecl -
@@ -2456,7 +2492,8 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {
MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...);
@@ -2477,7 +2514,8 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() {
MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
// SynthGetClassFunctionDecl - id objc_getClass(const char *name);
@@ -2493,7 +2531,8 @@ void RewriteObjC::SynthGetClassFunctionDecl() {
GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
getClassIdent, getClassType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls);
@@ -2508,9 +2547,12 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() {
false, false, 0, 0,
FunctionType::ExtInfo());
GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- getSuperClassIdent, getClassType, 0,
- FunctionDecl::Extern, false);
+ SourceLocation(),
+ getSuperClassIdent,
+ getClassType, 0,
+ FunctionDecl::Extern,
+ FunctionDecl::None,
+ false);
}
// SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name);
@@ -2526,7 +2568,8 @@ void RewriteObjC::SynthGetMetaClassFunctionDecl() {
GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
getClassIdent, getClassType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
@@ -2560,7 +2603,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
&Context->Idents.get(S), strType, 0,
- VarDecl::Static);
+ VarDecl::Static, VarDecl::None);
DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, strType, SourceLocation());
Expr *Unop = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf,
Context->getPointerType(DRE->getType()),
@@ -2665,7 +2708,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
FunctionDecl *MsgSendStretFlavor = 0;
if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) {
QualType resultType = mDecl->getResultType();
- if (resultType->isStructureType() || resultType->isUnionType())
+ if (resultType->isRecordType())
MsgSendStretFlavor = MsgSendStretFunctionDecl;
else if (resultType->isRealFloatingType())
MsgSendFlavor = MsgSendFpretFunctionDecl;
@@ -2673,203 +2716,211 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// Synthesize a call to objc_msgSend().
llvm::SmallVector<Expr*, 8> MsgExprs;
- IdentifierInfo *clsName = Exp->getClassName();
-
- // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
- if (clsName) { // class message.
- // FIXME: We need to fix Sema (and the AST for ObjCMessageExpr) to handle
- // the 'super' idiom within a class method.
- if (clsName->getName() == "super") {
- MsgSendFlavor = MsgSendSuperFunctionDecl;
- if (MsgSendStretFlavor)
- MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
- assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
-
- ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
-
- llvm::SmallVector<Expr*, 4> InitExprs;
-
- // set the receiver to self, the first argument to all methods.
- InitExprs.push_back(
- NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
- CastExpr::CK_Unknown,
- new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
- Context->getObjCIdType(),
- SourceLocation()))
- ); // set the 'receiver'.
-
- // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
- llvm::SmallVector<Expr*, 8> ClsExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
- ClsExprs.push_back(StringLiteral::Create(*Context,
- ClassDecl->getIdentifier()->getNameStart(),
- ClassDecl->getIdentifier()->getLength(),
- false, argType, SourceLocation()));
- CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
- &ClsExprs[0],
- ClsExprs.size(),
- StartLoc,
- EndLoc);
- // (Class)objc_getClass("CurrentClass")
- CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
- Context->getObjCClassType(),
- CastExpr::CK_Unknown, Cls);
- ClsExprs.clear();
- ClsExprs.push_back(ArgExpr);
- Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
- &ClsExprs[0], ClsExprs.size(),
- StartLoc, EndLoc);
-
- // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
- // To turn off a warning, type-cast to 'id'
- InitExprs.push_back( // set 'super class', using class_getSuperclass().
- NoTypeInfoCStyleCastExpr(Context,
- Context->getObjCIdType(),
- CastExpr::CK_Unknown, Cls));
- // struct objc_super
- QualType superType = getSuperStructType();
- Expr *SuperRep;
-
- if (LangOpts.Microsoft) {
- SynthSuperContructorFunctionDecl();
- // Simulate a contructor call...
- DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
- superType, SourceLocation());
- SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
- InitExprs.size(),
- superType, SourceLocation());
- // The code for super is a little tricky to prevent collision with
- // the structure definition in the header. The rewriter has it's own
- // internal definition (__rw_objc_super) that is uses. This is why
- // we need the cast below. For example:
- // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
- //
- SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
- Context->getPointerType(SuperRep->getType()),
- SourceLocation());
- SuperRep = NoTypeInfoCStyleCastExpr(Context,
- Context->getPointerType(superType),
- CastExpr::CK_Unknown, SuperRep);
- } else {
- // (struct objc_super) { <exprs from above> }
- InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(),
- &InitExprs[0], InitExprs.size(),
- SourceLocation());
- TypeSourceInfo *superTInfo
- = Context->getTrivialTypeSourceInfo(superType);
- SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
- superType, ILE, false);
- // struct objc_super *
- SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
- Context->getPointerType(SuperRep->getType()),
- SourceLocation());
- }
- MsgExprs.push_back(SuperRep);
+ switch (Exp->getReceiverKind()) {
+ case ObjCMessageExpr::SuperClass: {
+ MsgSendFlavor = MsgSendSuperFunctionDecl;
+ if (MsgSendStretFlavor)
+ MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
+ assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
+
+ ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
+
+ llvm::SmallVector<Expr*, 4> InitExprs;
+
+ // set the receiver to self, the first argument to all methods.
+ InitExprs.push_back(
+ NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CastExpr::CK_Unknown,
+ new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
+ Context->getObjCIdType(),
+ SourceLocation()))
+ ); // set the 'receiver'.
+
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
+ llvm::SmallVector<Expr*, 8> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ ClassDecl->getIdentifier()->getNameStart(),
+ ClassDecl->getIdentifier()->getLength(),
+ false, argType, SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size(),
+ StartLoc,
+ EndLoc);
+ // (Class)objc_getClass("CurrentClass")
+ CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
+ Context->getObjCClassType(),
+ CastExpr::CK_Unknown, Cls);
+ ClsExprs.clear();
+ ClsExprs.push_back(ArgExpr);
+ Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
+ &ClsExprs[0], ClsExprs.size(),
+ StartLoc, EndLoc);
+
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
+ // To turn off a warning, type-cast to 'id'
+ InitExprs.push_back( // set 'super class', using class_getSuperclass().
+ NoTypeInfoCStyleCastExpr(Context,
+ Context->getObjCIdType(),
+ CastExpr::CK_Unknown, Cls));
+ // struct objc_super
+ QualType superType = getSuperStructType();
+ Expr *SuperRep;
+
+ if (LangOpts.Microsoft) {
+ SynthSuperContructorFunctionDecl();
+ // Simulate a contructor call...
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
+ superType, SourceLocation());
+ SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
+ InitExprs.size(),
+ superType, SourceLocation());
+ // The code for super is a little tricky to prevent collision with
+ // the structure definition in the header. The rewriter has it's own
+ // internal definition (__rw_objc_super) that is uses. This is why
+ // we need the cast below. For example:
+ // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
+ //
+ SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
+ Context->getPointerType(SuperRep->getType()),
+ SourceLocation());
+ SuperRep = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(superType),
+ CastExpr::CK_Unknown, SuperRep);
} else {
- llvm::SmallVector<Expr*, 8> ClsExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
- ClsExprs.push_back(StringLiteral::Create(*Context,
- clsName->getNameStart(),
- clsName->getLength(),
- false, argType,
- SourceLocation()));
- CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
- &ClsExprs[0],
- ClsExprs.size(),
- StartLoc, EndLoc);
- MsgExprs.push_back(Cls);
+ // (struct objc_super) { <exprs from above> }
+ InitListExpr *ILE =
+ new (Context) InitListExpr(*Context, SourceLocation(),
+ &InitExprs[0], InitExprs.size(),
+ SourceLocation());
+ TypeSourceInfo *superTInfo
+ = Context->getTrivialTypeSourceInfo(superType);
+ SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
+ superType, ILE, false);
+ // struct objc_super *
+ SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
+ Context->getPointerType(SuperRep->getType()),
+ SourceLocation());
}
- } else { // instance message.
- Expr *recExpr = Exp->getReceiver();
-
- if (isSuperReceiver(recExpr)) {
- MsgSendFlavor = MsgSendSuperFunctionDecl;
- if (MsgSendStretFlavor)
- MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
- assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
- ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
- llvm::SmallVector<Expr*, 4> InitExprs;
-
- InitExprs.push_back(
- NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
- CastExpr::CK_Unknown,
- new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
- Context->getObjCIdType(),
- SourceLocation()))
- ); // set the 'receiver'.
-
- // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
- llvm::SmallVector<Expr*, 8> ClsExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
- ClsExprs.push_back(StringLiteral::Create(*Context,
- ClassDecl->getIdentifier()->getNameStart(),
- ClassDecl->getIdentifier()->getLength(),
- false, argType, SourceLocation()));
- CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
- &ClsExprs[0],
- ClsExprs.size(),
- StartLoc, EndLoc);
- // (Class)objc_getClass("CurrentClass")
- CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
- Context->getObjCClassType(),
- CastExpr::CK_Unknown, Cls);
- ClsExprs.clear();
- ClsExprs.push_back(ArgExpr);
- Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
- &ClsExprs[0], ClsExprs.size(),
- StartLoc, EndLoc);
-
- // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
- // To turn off a warning, type-cast to 'id'
- InitExprs.push_back(
- // set 'super class', using class_getSuperclass().
- NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
- CastExpr::CK_Unknown, Cls));
- // struct objc_super
- QualType superType = getSuperStructType();
- Expr *SuperRep;
-
- if (LangOpts.Microsoft) {
- SynthSuperContructorFunctionDecl();
- // Simulate a contructor call...
- DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
- superType, SourceLocation());
- SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
- InitExprs.size(),
- superType, SourceLocation());
- // The code for super is a little tricky to prevent collision with
- // the structure definition in the header. The rewriter has it's own
- // internal definition (__rw_objc_super) that is uses. This is why
- // we need the cast below. For example:
- // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
- //
- SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
- Context->getPointerType(SuperRep->getType()),
- SourceLocation());
- SuperRep = NoTypeInfoCStyleCastExpr(Context,
- Context->getPointerType(superType),
- CastExpr::CK_Unknown, SuperRep);
- } else {
- // (struct objc_super) { <exprs from above> }
- InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(),
- &InitExprs[0], InitExprs.size(),
- SourceLocation());
- TypeSourceInfo *superTInfo
- = Context->getTrivialTypeSourceInfo(superType);
- SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
- superType, ILE, false);
- }
- MsgExprs.push_back(SuperRep);
+ MsgExprs.push_back(SuperRep);
+ break;
+ }
+
+ case ObjCMessageExpr::Class: {
+ llvm::SmallVector<Expr*, 8> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ObjCInterfaceDecl *Class
+ = Exp->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ IdentifierInfo *clsName = Class->getIdentifier();
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ clsName->getNameStart(),
+ clsName->getLength(),
+ false, argType,
+ SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size(),
+ StartLoc, EndLoc);
+ MsgExprs.push_back(Cls);
+ break;
+ }
+
+ case ObjCMessageExpr::SuperInstance:{
+ MsgSendFlavor = MsgSendSuperFunctionDecl;
+ if (MsgSendStretFlavor)
+ MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
+ assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
+ ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
+ llvm::SmallVector<Expr*, 4> InitExprs;
+
+ InitExprs.push_back(
+ NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CastExpr::CK_Unknown,
+ new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
+ Context->getObjCIdType(),
+ SourceLocation()))
+ ); // set the 'receiver'.
+
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
+ llvm::SmallVector<Expr*, 8> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ ClassDecl->getIdentifier()->getNameStart(),
+ ClassDecl->getIdentifier()->getLength(),
+ false, argType, SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size(),
+ StartLoc, EndLoc);
+ // (Class)objc_getClass("CurrentClass")
+ CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
+ Context->getObjCClassType(),
+ CastExpr::CK_Unknown, Cls);
+ ClsExprs.clear();
+ ClsExprs.push_back(ArgExpr);
+ Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
+ &ClsExprs[0], ClsExprs.size(),
+ StartLoc, EndLoc);
+
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
+ // To turn off a warning, type-cast to 'id'
+ InitExprs.push_back(
+ // set 'super class', using class_getSuperclass().
+ NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CastExpr::CK_Unknown, Cls));
+ // struct objc_super
+ QualType superType = getSuperStructType();
+ Expr *SuperRep;
+
+ if (LangOpts.Microsoft) {
+ SynthSuperContructorFunctionDecl();
+ // Simulate a contructor call...
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
+ superType, SourceLocation());
+ SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
+ InitExprs.size(),
+ superType, SourceLocation());
+ // The code for super is a little tricky to prevent collision with
+ // the structure definition in the header. The rewriter has it's own
+ // internal definition (__rw_objc_super) that is uses. This is why
+ // we need the cast below. For example:
+ // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
+ //
+ SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
+ Context->getPointerType(SuperRep->getType()),
+ SourceLocation());
+ SuperRep = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(superType),
+ CastExpr::CK_Unknown, SuperRep);
} else {
- // Remove all type-casts because it may contain objc-style types; e.g.
- // Foo<Proto> *.
- while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr))
- recExpr = CE->getSubExpr();
- recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
- CastExpr::CK_Unknown, recExpr);
- MsgExprs.push_back(recExpr);
+ // (struct objc_super) { <exprs from above> }
+ InitListExpr *ILE =
+ new (Context) InitListExpr(*Context, SourceLocation(),
+ &InitExprs[0], InitExprs.size(),
+ SourceLocation());
+ TypeSourceInfo *superTInfo
+ = Context->getTrivialTypeSourceInfo(superType);
+ SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
+ superType, ILE, false);
}
+ MsgExprs.push_back(SuperRep);
+ break;
+ }
+
+ case ObjCMessageExpr::Instance: {
+ // Remove all type-casts because it may contain objc-style types; e.g.
+ // Foo<Proto> *.
+ Expr *recExpr = Exp->getInstanceReceiver();
+ while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr))
+ recExpr = CE->getSubExpr();
+ recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CastExpr::CK_Unknown, recExpr);
+ MsgExprs.push_back(recExpr);
+ break;
}
+ }
+
// Create a call to sel_registerName("selName"), it will be the 2nd argument.
llvm::SmallVector<Expr*, 8> SelExprs;
QualType argType = Context->getPointerType(Context->CharTy);
@@ -3070,7 +3121,8 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
std::string Name = "_OBJC_PROTOCOL_" + Exp->getProtocol()->getNameAsString();
IdentifierInfo *ID = &Context->Idents.get(Name);
VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
- ID, getProtocolType(), 0, VarDecl::Extern);
+ ID, getProtocolType(), 0,
+ VarDecl::Extern, VarDecl::None);
DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, getProtocolType(), SourceLocation());
Expr *DerefExpr = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf,
Context->getPointerType(DRE->getType()),
@@ -5066,8 +5118,8 @@ FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(const char *name) {
IdentifierInfo *ID = &Context->Idents.get(name);
QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy);
return FunctionDecl::Create(*Context, TUDecl,SourceLocation(),
- ID, FType, 0, FunctionDecl::Extern, false,
- false);
+ ID, FType, 0, FunctionDecl::Extern,
+ FunctionDecl::None, false, false);
}
Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
@@ -5147,7 +5199,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
&Context->Idents.get(DescData.c_str()),
Context->VoidPtrTy, 0,
- VarDecl::Static);
+ VarDecl::Static, VarDecl::None);
UnaryOperator *DescRefExpr = new (Context) UnaryOperator(
new (Context) DeclRefExpr(NewVD,
Context->VoidPtrTy, SourceLocation()),
diff --git a/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp
index ce474d3..21dc0ba 100644
--- a/lib/Frontend/StmtXML.cpp
+++ b/lib/Frontend/StmtXML.cpp
@@ -125,6 +125,7 @@ namespace {
void VisitFloatingLiteral(FloatingLiteral *Node);
void VisitStringLiteral(StringLiteral *Str);
void VisitUnaryOperator(UnaryOperator *Node);
+ void VisitOffsetOfExpr(OffsetOfExpr *Node);
void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node);
void VisitMemberExpr(MemberExpr *Node);
void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
@@ -308,6 +309,10 @@ void StmtXML::VisitUnaryOperator(UnaryOperator *Node) {
Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode()));
}
+void StmtXML::OffsetOfExpr(OffsetOfExpr *Node) {
+ DumpExpr(Node);
+}
+
void StmtXML::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
DumpExpr(Node);
Doc.addAttribute("is_sizeof", Node->isSizeOf() ? "sizeof" : "alignof");
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 4e91f8d..28bb17a 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -148,9 +148,16 @@ static void SelectInterestingSourceRegion(std::string &SourceLine,
std::string &FixItInsertionLine,
unsigned EndOfCaretToken,
unsigned Columns) {
- if (CaretLine.size() > SourceLine.size())
- SourceLine.resize(CaretLine.size(), ' ');
-
+ unsigned MaxSize = std::max(SourceLine.size(),
+ std::max(CaretLine.size(),
+ FixItInsertionLine.size()));
+ if (MaxSize > SourceLine.size())
+ SourceLine.resize(MaxSize, ' ');
+ if (MaxSize > CaretLine.size())
+ CaretLine.resize(MaxSize, ' ');
+ if (!FixItInsertionLine.empty() && MaxSize > FixItInsertionLine.size())
+ FixItInsertionLine.resize(MaxSize, ' ');
+
// Find the slice that we need to display the full caret line
// correctly.
unsigned CaretStart = 0, CaretEnd = CaretLine.size();
@@ -275,7 +282,7 @@ static void SelectInterestingSourceRegion(std::string &SourceLine,
void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
SourceRange *Ranges,
unsigned NumRanges,
- SourceManager &SM,
+ const SourceManager &SM,
const FixItHint *Hints,
unsigned NumHints,
unsigned Columns) {
@@ -796,8 +803,13 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
OutStr += " [-W";
OutStr += Opt;
OutStr += ']';
- } else if (Diagnostic::isBuiltinExtensionDiag(Info.getID())) {
- OutStr += " [-pedantic]";
+ } else {
+ // If the diagnostic is an extension diagnostic and not enabled by default
+ // then it must have been turned on with -pedantic.
+ bool EnabledByDefault;
+ if (Diagnostic::isBuiltinExtensionDiag(Info.getID(), EnabledByDefault) &&
+ !EnabledByDefault)
+ OutStr += " [-pedantic]";
}
}
diff --git a/lib/Frontend/VerifyDiagnosticsClient.cpp b/lib/Frontend/VerifyDiagnosticsClient.cpp
index 99ec910..ae36481 100644
--- a/lib/Frontend/VerifyDiagnosticsClient.cpp
+++ b/lib/Frontend/VerifyDiagnosticsClient.cpp
@@ -16,6 +16,7 @@
#include "clang/Frontend/TextDiagnosticBuffer.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Regex.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -71,97 +72,267 @@ bool VerifyDiagnosticsClient::HadErrors() {
typedef TextDiagnosticBuffer::DiagList DiagList;
typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
-/// FindDiagnostics - Go through the comment and see if it indicates expected
-/// diagnostics. If so, then put them in a diagnostic list.
+namespace {
+
+/// Directive - Abstract class representing a parsed verify directive.
///
-static void FindDiagnostics(const char *CommentStart, unsigned CommentLen,
- DiagList &ExpectedDiags,
- Preprocessor &PP, SourceLocation Pos,
- const char *ExpectedStr) {
- const char *CommentEnd = CommentStart+CommentLen;
- unsigned ExpectedStrLen = strlen(ExpectedStr);
-
- // Find all expected-foo diagnostics in the string and add them to
- // ExpectedDiags.
- while (CommentStart != CommentEnd) {
- CommentStart = std::find(CommentStart, CommentEnd, 'e');
- if (unsigned(CommentEnd-CommentStart) < ExpectedStrLen) return;
-
- // If this isn't expected-foo, ignore it.
- if (memcmp(CommentStart, ExpectedStr, ExpectedStrLen)) {
- ++CommentStart;
- continue;
- }
+class Directive {
+public:
+ static Directive* Create(bool RegexKind, const SourceLocation &Location,
+ const std::string &Text, unsigned Count);
+public:
+ SourceLocation Location;
+ const std::string Text;
+ unsigned Count;
+
+ virtual ~Directive() { }
+
+ // Returns true if directive text is valid.
+ // Otherwise returns false and populates E.
+ virtual bool isValid(std::string &Error) = 0;
+
+ // Returns true on match.
+ virtual bool Match(const std::string &S) = 0;
+
+protected:
+ Directive(const SourceLocation &Location, const std::string &Text,
+ unsigned Count)
+ : Location(Location), Text(Text), Count(Count) { }
+
+private:
+ Directive(const Directive&); // DO NOT IMPLEMENT
+ void operator=(const Directive&); // DO NOT IMPLEMENT
+};
+
+/// StandardDirective - Directive with string matching.
+///
+class StandardDirective : public Directive {
+public:
+ StandardDirective(const SourceLocation &Location, const std::string &Text,
+ unsigned Count)
+ : Directive(Location, Text, Count) { }
+
+ virtual bool isValid(std::string &Error) {
+ // all strings are considered valid; even empty ones
+ return true;
+ }
+
+ virtual bool Match(const std::string &S) {
+ return S.find(Text) != std::string::npos ||
+ Text.find(S) != std::string::npos;
+ }
+};
+
+/// RegexDirective - Directive with regular-expression matching.
+///
+class RegexDirective : public Directive {
+public:
+ RegexDirective(const SourceLocation &Location, const std::string &Text,
+ unsigned Count)
+ : Directive(Location, Text, Count), Regex(Text) { }
+
+ virtual bool isValid(std::string &Error) {
+ if (Regex.isValid(Error))
+ return true;
+ return false;
+ }
+
+ virtual bool Match(const std::string &S) {
+ return Regex.match(S);
+ }
- CommentStart += ExpectedStrLen;
-
- // Skip whitespace.
- while (CommentStart != CommentEnd &&
- isspace(CommentStart[0]))
- ++CommentStart;
-
- // Default, if we find the '{' now, is 1 time.
- int Times = 1;
- int Temp = 0;
- // In extended syntax, there could be a digit now.
- while (CommentStart != CommentEnd &&
- CommentStart[0] >= '0' && CommentStart[0] <= '9') {
- Temp *= 10;
- Temp += CommentStart[0] - '0';
- ++CommentStart;
+private:
+ llvm::Regex Regex;
+};
+
+typedef std::vector<Directive*> DirectiveList;
+
+/// ExpectedData - owns directive objects and deletes on destructor.
+///
+struct ExpectedData {
+ DirectiveList Errors;
+ DirectiveList Warnings;
+ DirectiveList Notes;
+
+ ~ExpectedData() {
+ DirectiveList* Lists[] = { &Errors, &Warnings, &Notes, 0 };
+ for (DirectiveList **PL = Lists; *PL; ++PL) {
+ DirectiveList * const L = *PL;
+ for (DirectiveList::iterator I = L->begin(), E = L->end(); I != E; ++I)
+ delete *I;
}
- if (Temp > 0)
- Times = Temp;
-
- // Skip whitespace again.
- while (CommentStart != CommentEnd &&
- isspace(CommentStart[0]))
- ++CommentStart;
-
- // We should have a {{ now.
- if (CommentEnd-CommentStart < 2 ||
- CommentStart[0] != '{' || CommentStart[1] != '{') {
- if (std::find(CommentStart, CommentEnd, '{') != CommentEnd)
- PP.Diag(Pos, diag::err_verify_bogus_characters);
- else
- PP.Diag(Pos, diag::err_verify_missing_start);
- return;
+ }
+};
+
+class ParseHelper
+{
+public:
+ ParseHelper(const char *Begin, const char *End)
+ : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { }
+
+ // Return true if string literal is next.
+ bool Next(const std::string &S) {
+ std::string::size_type LEN = S.length();
+ P = C;
+ PEnd = C + LEN;
+ if (PEnd > End)
+ return false;
+ return !memcmp(P, S.c_str(), LEN);
+ }
+
+ // Return true if number is next.
+ // Output N only if number is next.
+ bool Next(unsigned &N) {
+ unsigned TMP = 0;
+ P = C;
+ for (; P < End && P[0] >= '0' && P[0] <= '9'; ++P) {
+ TMP *= 10;
+ TMP += P[0] - '0';
}
- CommentStart += 2;
-
- // Find the }}.
- const char *ExpectedEnd = CommentStart;
- while (1) {
- ExpectedEnd = std::find(ExpectedEnd, CommentEnd, '}');
- if (CommentEnd-ExpectedEnd < 2) {
- PP.Diag(Pos, diag::err_verify_missing_end);
- return;
- }
+ if (P == C)
+ return false;
+ PEnd = P;
+ N = TMP;
+ return true;
+ }
+
+ // Return true if string literal is found.
+ // When true, P marks begin-position of S in content.
+ bool Search(const std::string &S) {
+ P = std::search(C, End, S.begin(), S.end());
+ PEnd = P + S.length();
+ return P != End;
+ }
+
+ // Advance 1-past previous next/search.
+ // Behavior is undefined if previous next/search failed.
+ bool Advance() {
+ C = PEnd;
+ return C < End;
+ }
+
+ // Skip zero or more whitespace.
+ void SkipWhitespace() {
+ for (; C < End && isspace(*C); ++C)
+ ;
+ }
+
+ // Return true if EOF reached.
+ bool Done() {
+ return !(C < End);
+ }
+
+ const char * const Begin; // beginning of expected content
+ const char * const End; // end of expected content (1-past)
+ const char *C; // position of next char in content
+ const char *P;
+
+private:
+ const char *PEnd; // previous next/search subject end (1-past)
+};
+
+} // namespace anonymous
+
+/// ParseDirective - Go through the comment and see if it indicates expected
+/// diagnostics. If so, then put them in the appropriate directive list.
+///
+static void ParseDirective(const char *CommentStart, unsigned CommentLen,
+ ExpectedData &ED, Preprocessor &PP,
+ SourceLocation Pos) {
+ // A single comment may contain multiple directives.
+ for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) {
+ // search for token: expected
+ if (!PH.Search("expected"))
+ break;
+ PH.Advance();
+
+ // next token: -
+ if (!PH.Next("-"))
+ continue;
+ PH.Advance();
+
+ // next token: { error | warning | note }
+ DirectiveList* DL = NULL;
+ if (PH.Next("error"))
+ DL = &ED.Errors;
+ else if (PH.Next("warning"))
+ DL = &ED.Warnings;
+ else if (PH.Next("note"))
+ DL = &ED.Notes;
+ else
+ continue;
+ PH.Advance();
- if (ExpectedEnd[1] == '}')
- break;
+ // default directive kind
+ bool RegexKind = false;
+ const char* KindStr = "string";
- ++ExpectedEnd; // Skip over singular }'s
+ // next optional token: -
+ if (PH.Next("-re")) {
+ PH.Advance();
+ RegexKind = true;
+ KindStr = "regex";
}
- std::string Msg(CommentStart, ExpectedEnd);
- std::string::size_type FindPos;
- while ((FindPos = Msg.find("\\n")) != std::string::npos)
- Msg.replace(FindPos, 2, "\n");
- // Add is possibly multiple times.
- for (int i = 0; i < Times; ++i)
- ExpectedDiags.push_back(std::make_pair(Pos, Msg));
+ // skip optional whitespace
+ PH.SkipWhitespace();
+
+ // next optional token: positive integer
+ unsigned Count = 1;
+ if (PH.Next(Count))
+ PH.Advance();
+
+ // skip optional whitespace
+ PH.SkipWhitespace();
+
+ // next token: {{
+ if (!PH.Next("{{")) {
+ PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin),
+ diag::err_verify_missing_start) << KindStr;
+ continue;
+ }
+ PH.Advance();
+ const char* const ContentBegin = PH.C; // mark content begin
- CommentStart = ExpectedEnd;
+ // search for token: }}
+ if (!PH.Search("}}")) {
+ PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin),
+ diag::err_verify_missing_end) << KindStr;
+ continue;
+ }
+ const char* const ContentEnd = PH.P; // mark content end
+ PH.Advance();
+
+ // build directive text; convert \n to newlines
+ std::string Text;
+ llvm::StringRef NewlineStr = "\\n";
+ llvm::StringRef Content(ContentBegin, ContentEnd-ContentBegin);
+ size_t CPos = 0;
+ size_t FPos;
+ while ((FPos = Content.find(NewlineStr, CPos)) != llvm::StringRef::npos) {
+ Text += Content.substr(CPos, FPos-CPos);
+ Text += '\n';
+ CPos = FPos + NewlineStr.size();
+ }
+ if (Text.empty())
+ Text.assign(ContentBegin, ContentEnd);
+
+ // construct new directive
+ Directive *D = Directive::Create(RegexKind, Pos, Text, Count);
+ std::string Error;
+ if (D->isValid(Error))
+ DL->push_back(D);
+ else {
+ PP.Diag(Pos.getFileLocWithOffset(ContentBegin-PH.Begin),
+ diag::err_verify_invalid_content)
+ << KindStr << Error;
+ }
}
}
/// FindExpectedDiags - Lex the main source file to find all of the
// expected errors and warnings.
-static void FindExpectedDiags(Preprocessor &PP,
- DiagList &ExpectedErrors,
- DiagList &ExpectedWarnings,
- DiagList &ExpectedNotes) {
+static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED) {
// Create a raw lexer to pull all the comments out of the main file. We don't
// want to look in #include'd headers for expected-error strings.
SourceManager &SM = PP.getSourceManager();
@@ -185,17 +356,8 @@ static void FindExpectedDiags(Preprocessor &PP,
std::string Comment = PP.getSpelling(Tok);
if (Comment.empty()) continue;
- // Find all expected errors.
- FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP,
- Tok.getLocation(), "expected-error");
-
- // Find all expected warnings.
- FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP,
- Tok.getLocation(), "expected-warning");
-
- // Find all expected notes.
- FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP,
- Tok.getLocation(), "expected-note");
+ // Find all expected errors/warnings/notes.
+ ParseDirective(&Comment[0], Comment.size(), ED, PP, Tok.getLocation());
};
}
@@ -225,49 +387,68 @@ static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
return std::distance(diag_begin, diag_end);
}
-/// CompareDiagLists - Compare two diagnostic lists and return the difference
-/// between them.
+static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
+ DirectiveList &DL, const char *Kind,
+ bool Expected) {
+ if (DL.empty())
+ return 0;
+
+ llvm::SmallString<256> Fmt;
+ llvm::raw_svector_ostream OS(Fmt);
+ for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) {
+ Directive& D = **I;
+ if (D.Location.isInvalid() || !SourceMgr)
+ OS << "\n (frontend)";
+ else
+ OS << "\n Line " << SourceMgr->getInstantiationLineNumber(D.Location);
+ OS << ": " << D.Text;
+ }
+
+ Diags.Report(diag::err_verify_inconsistent_diags)
+ << Kind << !Expected << OS.str();
+ return DL.size();
+}
+
+/// CheckLists - Compare expected to seen diagnostic lists and return the
+/// the difference between them.
///
-static unsigned CompareDiagLists(Diagnostic &Diags,
- SourceManager &SourceMgr,
- const_diag_iterator d1_begin,
- const_diag_iterator d1_end,
- const_diag_iterator d2_begin,
- const_diag_iterator d2_end,
- const char *Label) {
- DiagList LeftOnly;
- DiagList Left(d1_begin, d1_end);
+static unsigned CheckLists(Diagnostic &Diags, SourceManager &SourceMgr,
+ const char *Label,
+ DirectiveList &Left,
+ const_diag_iterator d2_begin,
+ const_diag_iterator d2_end) {
+ DirectiveList LeftOnly;
DiagList Right(d2_begin, d2_end);
- for (const_diag_iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
- unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(I->first);
- const std::string &Diag1 = I->second;
+ for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
+ Directive& D = **I;
+ unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(D.Location);
- DiagList::iterator II, IE;
- for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
- unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first);
- if (LineNo1 != LineNo2) continue;
+ for (unsigned i = 0; i < D.Count; ++i) {
+ DiagList::iterator II, IE;
+ for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
+ unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first);
+ if (LineNo1 != LineNo2)
+ continue;
- const std::string &Diag2 = II->second;
- if (Diag2.find(Diag1) != std::string::npos ||
- Diag1.find(Diag2) != std::string::npos) {
- break;
+ const std::string &RightText = II->second;
+ if (D.Match(RightText))
+ break;
+ }
+ if (II == IE) {
+ // Not found.
+ LeftOnly.push_back(*I);
+ } else {
+ // Found. The same cannot be found twice.
+ Right.erase(II);
}
- }
- if (II == IE) {
- // Not found.
- LeftOnly.push_back(*I);
- } else {
- // Found. The same cannot be found twice.
- Right.erase(II);
}
}
// Now all that's left in Right are those that were not matched.
- return (PrintProblem(Diags, &SourceMgr,
- LeftOnly.begin(), LeftOnly.end(), Label, true) +
- PrintProblem(Diags, &SourceMgr,
- Right.begin(), Right.end(), Label, false));
+ return (PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true) +
+ PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(),
+ Label, false));
}
/// CheckResults - This compares the expected results to those that
@@ -276,9 +457,7 @@ static unsigned CompareDiagLists(Diagnostic &Diags,
///
static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr,
const TextDiagnosticBuffer &Buffer,
- const DiagList &ExpectedErrors,
- const DiagList &ExpectedWarnings,
- const DiagList &ExpectedNotes) {
+ ExpectedData &ED) {
// We want to capture the delta between what was expected and what was
// seen.
//
@@ -287,31 +466,22 @@ static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr,
unsigned NumProblems = 0;
// See if there are error mismatches.
- NumProblems += CompareDiagLists(Diags, SourceMgr,
- ExpectedErrors.begin(), ExpectedErrors.end(),
- Buffer.err_begin(), Buffer.err_end(),
- "error");
+ NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors,
+ Buffer.err_begin(), Buffer.err_end());
// See if there are warning mismatches.
- NumProblems += CompareDiagLists(Diags, SourceMgr,
- ExpectedWarnings.begin(),
- ExpectedWarnings.end(),
- Buffer.warn_begin(), Buffer.warn_end(),
- "warning");
+ NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings,
+ Buffer.warn_begin(), Buffer.warn_end());
// See if there are note mismatches.
- NumProblems += CompareDiagLists(Diags, SourceMgr,
- ExpectedNotes.begin(),
- ExpectedNotes.end(),
- Buffer.note_begin(), Buffer.note_end(),
- "note");
+ NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,
+ Buffer.note_begin(), Buffer.note_end());
return NumProblems;
}
-
void VerifyDiagnosticsClient::CheckDiagnostics() {
- DiagList ExpectedErrors, ExpectedWarnings, ExpectedNotes;
+ ExpectedData ED;
// Ensure any diagnostics go to the primary client.
DiagnosticClient *CurClient = Diags.getClient();
@@ -320,13 +490,11 @@ void VerifyDiagnosticsClient::CheckDiagnostics() {
// If we have a preprocessor, scan the source for expected diagnostic
// markers. If not then any diagnostics are unexpected.
if (CurrentPreprocessor) {
- FindExpectedDiags(*CurrentPreprocessor, ExpectedErrors, ExpectedWarnings,
- ExpectedNotes);
+ FindExpectedDiags(*CurrentPreprocessor, ED);
// Check that the expected diagnostics occurred.
NumErrors += CheckResults(Diags, CurrentPreprocessor->getSourceManager(),
- *Buffer,
- ExpectedErrors, ExpectedWarnings, ExpectedNotes);
+ *Buffer, ED);
} else {
NumErrors += (PrintProblem(Diags, 0,
Buffer->err_begin(), Buffer->err_end(),
@@ -344,3 +512,10 @@ void VerifyDiagnosticsClient::CheckDiagnostics() {
// Reset the buffer, we have processed all the diagnostics in it.
Buffer.reset(new TextDiagnosticBuffer());
}
+
+Directive* Directive::Create(bool RegexKind, const SourceLocation &Location,
+ const std::string &Text, unsigned Count) {
+ if (RegexKind)
+ return new RegexDirective(Location, Text, Count);
+ return new StandardDirective(Location, Text, Count);
+}
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
index ea9635e..84c4f5d 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Frontend/Warnings.cpp
@@ -35,6 +35,12 @@ void clang::ProcessWarningOptions(Diagnostic &Diags,
const DiagnosticOptions &Opts) {
Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);
+
+ // Handle -ferror-limit
+ if (Opts.ErrorLimit)
+ Diags.setErrorLimit(Opts.ErrorLimit);
+ if (Opts.TemplateBacktraceLimit)
+ Diags.setTemplateBacktraceLimit(Opts.TemplateBacktraceLimit);
// If -pedantic or -pedantic-errors was specified, then we want to map all
// extension diagnostics onto WARNING or ERROR unless the user has futz'd
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index e63291b..047fdb3 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -1,4 +1,6 @@
set(files
+ altivec.h
+ arm_neon.h
emmintrin.h
float.h
iso646.h
diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h
new file mode 100644
index 0000000..1cd0db8
--- /dev/null
+++ b/lib/Headers/altivec.h
@@ -0,0 +1,1483 @@
+/*===---- altivec.h - Standard header for type generic math ---------------===*\
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+\*===----------------------------------------------------------------------===*/
+
+#ifndef __ALTIVEC_H
+#define __ALTIVEC_H
+
+#ifndef __ALTIVEC__
+#error "AltiVec support not enabled"
+#endif
+
+/* constants for mapping CR6 bits to predicate result. */
+
+#define __CR6_EQ 0
+#define __CR6_EQ_REV 1
+#define __CR6_LT 2
+#define __CR6_LT_REV 3
+
+#define _ATTRS_o_ai __attribute__((__overloadable__, __always_inline__))
+
+/* vec_abs */
+
+#define __builtin_vec_abs vec_abs
+#define __builtin_altivec_abs_v16qi vec_abs
+#define __builtin_altivec_abs_v8hi vec_abs
+#define __builtin_altivec_abs_v4si vec_abs
+
+static vector signed char _ATTRS_o_ai
+vec_abs(vector signed char a)
+{
+ return __builtin_altivec_vmaxsb(a, -a);
+}
+
+static vector signed short _ATTRS_o_ai
+vec_abs(vector signed short a)
+{
+ return __builtin_altivec_vmaxsh(a, -a);
+}
+
+static vector signed int _ATTRS_o_ai
+vec_abs(vector signed int a)
+{
+ return __builtin_altivec_vmaxsw(a, -a);
+}
+
+static vector float _ATTRS_o_ai
+vec_abs(vector float a)
+{
+ vector unsigned int res = (vector unsigned int)a &
+ (vector unsigned int)(0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF);
+ return (vector float)res;
+}
+
+/* vec_abss */
+
+#define __builtin_vec_abss vec_abss
+#define __builtin_altivec_abss_v16qi vec_abss
+#define __builtin_altivec_abss_v8hi vec_abss
+#define __builtin_altivec_abss_v4si vec_abss
+
+static vector signed char _ATTRS_o_ai
+vec_abss(vector signed char a)
+{
+ return __builtin_altivec_vmaxsb(a, __builtin_altivec_vsubsbs(
+ (vector signed char)(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), a));
+}
+
+static vector signed short _ATTRS_o_ai
+vec_abss(vector signed short a)
+{
+ return __builtin_altivec_vmaxsh(a, __builtin_altivec_vsubshs(
+ (vector signed short)(0, 0, 0, 0, 0, 0, 0, 0), a));
+}
+
+static vector signed int _ATTRS_o_ai
+vec_abss(vector signed int a)
+{
+ return __builtin_altivec_vmaxsw(a, __builtin_altivec_vsubsws(
+ (vector signed int)(0, 0, 0, 0), a));
+}
+
+/* vec_add */
+
+#define __builtin_altivec_vaddubm vec_add
+#define __builtin_altivec_vadduhm vec_add
+#define __builtin_altivec_vadduwm vec_add
+#define __builtin_altivec_vaddfp vec_add
+#define __builtin_vec_vaddubm vec_add
+#define __builtin_vec_vadduhm vec_add
+#define __builtin_vec_vadduwm vec_add
+#define __builtin_vec_vaddfp vec_add
+#define vec_vaddubm vec_add
+#define vec_vadduhm vec_add
+#define vec_vadduwm vec_add
+#define vec_vaddfp vec_add
+
+static vector signed char _ATTRS_o_ai
+vec_add(vector signed char a, vector signed char b)
+{
+ return a + b;
+}
+
+static vector unsigned char _ATTRS_o_ai
+vec_add(vector unsigned char a, vector unsigned char b)
+{
+ return a + b;
+}
+
+static vector short _ATTRS_o_ai
+vec_add(vector short a, vector short b)
+{
+ return a + b;
+}
+
+static vector unsigned short _ATTRS_o_ai
+vec_add(vector unsigned short a, vector unsigned short b)
+{
+ return a + b;
+}
+
+static vector int _ATTRS_o_ai
+vec_add(vector int a, vector int b)
+{
+ return a + b;
+}
+
+static vector unsigned int _ATTRS_o_ai
+vec_add(vector unsigned int a, vector unsigned int b)
+{
+ return a + b;
+}
+
+static vector float _ATTRS_o_ai
+vec_add(vector float a, vector float b)
+{
+ return a + b;
+}
+
+/* vec_addc */
+
+#define __builtin_vec_addc __builtin_altivec_vaddcuw
+#define vec_vaddcuw __builtin_altivec_vaddcuw
+#define vec_addc __builtin_altivec_vaddcuw
+
+/* vec_adds */
+
+#define __builtin_vec_vaddsbs __builtin_altivec_vaddsbs
+#define __builtin_vec_vaddubs __builtin_altivec_vaddubs
+#define __builtin_vec_vaddshs __builtin_altivec_vaddshs
+#define __builtin_vec_vadduhs __builtin_altivec_vadduhs
+#define __builtin_vec_vaddsws __builtin_altivec_vaddsws
+#define __builtin_vec_vadduws __builtin_altivec_vadduws
+#define vec_vaddsbs __builtin_altivec_vaddsbs
+#define vec_vaddubs __builtin_altivec_vaddubs
+#define vec_vaddshs __builtin_altivec_vaddshs
+#define vec_vadduhs __builtin_altivec_vadduhs
+#define vec_vaddsws __builtin_altivec_vaddsws
+#define vec_vadduws __builtin_altivec_vadduws
+
+static vector signed char _ATTRS_o_ai
+vec_adds(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vaddsbs(a, b);
+}
+
+static vector unsigned char _ATTRS_o_ai
+vec_adds(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vaddubs(a, b);
+}
+
+static vector short _ATTRS_o_ai
+vec_adds(vector short a, vector short b)
+{
+ return __builtin_altivec_vaddshs(a, b);
+}
+
+static vector unsigned short _ATTRS_o_ai
+vec_adds(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vadduhs(a, b);
+}
+
+static vector int _ATTRS_o_ai
+vec_adds(vector int a, vector int b)
+{
+ return __builtin_altivec_vaddsws(a, b);
+}
+
+static vector unsigned int _ATTRS_o_ai
+vec_adds(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vadduws(a, b);
+}
+
+/* vec_sub */
+
+#define __builtin_altivec_vsububm vec_sub
+#define __builtin_altivec_vsubuhm vec_sub
+#define __builtin_altivec_vsubuwm vec_sub
+#define __builtin_altivec_vsubfp vec_sub
+#define __builtin_vec_vsububm vec_sub
+#define __builtin_vec_vsubuhm vec_sub
+#define __builtin_vec_vsubuwm vec_sub
+#define __builtin_vec_vsubfp vec_sub
+#define vec_vsububm vec_sub
+#define vec_vsubuhm vec_sub
+#define vec_vsubuwm vec_sub
+#define vec_vsubfp vec_sub
+
+static vector signed char _ATTRS_o_ai
+vec_sub(vector signed char a, vector signed char b)
+{
+ return a - b;
+}
+
+static vector unsigned char _ATTRS_o_ai
+vec_sub(vector unsigned char a, vector unsigned char b)
+{
+ return a - b;
+}
+
+static vector short _ATTRS_o_ai
+vec_sub(vector short a, vector short b)
+{
+ return a - b;
+}
+
+static vector unsigned short _ATTRS_o_ai
+vec_sub(vector unsigned short a, vector unsigned short b)
+{
+ return a - b;
+}
+
+static vector int _ATTRS_o_ai
+vec_sub(vector int a, vector int b)
+{
+ return a - b;
+}
+
+static vector unsigned int _ATTRS_o_ai
+vec_sub(vector unsigned int a, vector unsigned int b)
+{
+ return a - b;
+}
+
+static vector float _ATTRS_o_ai
+vec_sub(vector float a, vector float b)
+{
+ return a - b;
+}
+
+/* vec_subs */
+
+#define __builtin_vec_vsubsbs __builtin_altivec_vsubsbs
+#define __builtin_vec_vsububs __builtin_altivec_vsububs
+#define __builtin_vec_vsubshs __builtin_altivec_vsubshs
+#define __builtin_vec_vsubuhs __builtin_altivec_vsubuhs
+#define __builtin_vec_vsubsws __builtin_altivec_vsubsws
+#define __builtin_vec_vsubuws __builtin_altivec_vsubuws
+#define vec_vsubsbs __builtin_altivec_vsubsbs
+#define vec_vsububs __builtin_altivec_vsububs
+#define vec_vsubshs __builtin_altivec_vsubshs
+#define vec_vsubuhs __builtin_altivec_vsubuhs
+#define vec_vsubsws __builtin_altivec_vsubsws
+#define vec_vsubuws __builtin_altivec_vsubuws
+
+static vector signed char _ATTRS_o_ai
+vec_subs(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vsubsbs(a, b);
+}
+
+static vector unsigned char _ATTRS_o_ai
+vec_subs(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vsububs(a, b);
+}
+
+static vector short _ATTRS_o_ai
+vec_subs(vector short a, vector short b)
+{
+ return __builtin_altivec_vsubshs(a, b);
+}
+
+static vector unsigned short _ATTRS_o_ai
+vec_subs(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vsubuhs(a, b);
+}
+
+static vector int _ATTRS_o_ai
+vec_subs(vector int a, vector int b)
+{
+ return __builtin_altivec_vsubsws(a, b);
+}
+
+static vector unsigned int _ATTRS_o_ai
+vec_subs(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vsubuws(a, b);
+}
+
+/* vec_avg */
+
+#define __builtin_vec_vavgsb __builtin_altivec_vavgsb
+#define __builtin_vec_vavgub __builtin_altivec_vavgub
+#define __builtin_vec_vavgsh __builtin_altivec_vavgsh
+#define __builtin_vec_vavguh __builtin_altivec_vavguh
+#define __builtin_vec_vavgsw __builtin_altivec_vavgsw
+#define __builtin_vec_vavguw __builtin_altivec_vavguw
+#define vec_vavgsb __builtin_altivec_vavgsb
+#define vec_vavgub __builtin_altivec_vavgub
+#define vec_vavgsh __builtin_altivec_vavgsh
+#define vec_vavguh __builtin_altivec_vavguh
+#define vec_vavgsw __builtin_altivec_vavgsw
+#define vec_vavguw __builtin_altivec_vavguw
+
+static vector signed char _ATTRS_o_ai
+vec_avg(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vavgsb(a, b);
+}
+
+static vector unsigned char _ATTRS_o_ai
+vec_avg(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vavgub(a, b);
+}
+
+static vector short _ATTRS_o_ai
+vec_avg(vector short a, vector short b)
+{
+ return __builtin_altivec_vavgsh(a, b);
+}
+
+static vector unsigned short _ATTRS_o_ai
+vec_avg(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vavguh(a, b);
+}
+
+static vector int _ATTRS_o_ai
+vec_avg(vector int a, vector int b)
+{
+ return __builtin_altivec_vavgsw(a, b);
+}
+
+static vector unsigned int _ATTRS_o_ai
+vec_avg(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vavguw(a, b);
+}
+
+/* vec_st */
+
+#define __builtin_vec_st vec_st
+#define vec_stvx vec_st
+
+static void _ATTRS_o_ai
+vec_st(vector signed char a, int b, vector signed char *c)
+{
+ __builtin_altivec_stvx((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_st(vector unsigned char a, int b, vector unsigned char *c)
+{
+ __builtin_altivec_stvx((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_st(vector short a, int b, vector short *c)
+{
+ __builtin_altivec_stvx((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_st(vector unsigned short a, int b, vector unsigned short *c)
+{
+ __builtin_altivec_stvx((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_st(vector int a, int b, vector int *c)
+{
+ __builtin_altivec_stvx(a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_st(vector unsigned int a, int b, vector unsigned int *c)
+{
+ __builtin_altivec_stvx((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_st(vector float a, int b, vector float *c)
+{
+ __builtin_altivec_stvx((vector int)a, b, (void *)c);
+}
+
+/* vec_stl */
+
+#define __builtin_vec_stl vec_stl
+#define vec_stvxl vec_stl
+
+static void _ATTRS_o_ai
+vec_stl(vector signed char a, int b, vector signed char *c)
+{
+ __builtin_altivec_stvxl((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_stl(vector unsigned char a, int b, vector unsigned char *c)
+{
+ __builtin_altivec_stvxl((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_stl(vector short a, int b, vector short *c)
+{
+ __builtin_altivec_stvxl((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_stl(vector unsigned short a, int b, vector unsigned short *c)
+{
+ __builtin_altivec_stvxl((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_stl(vector int a, int b, vector int *c)
+{
+ __builtin_altivec_stvxl(a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_stl(vector unsigned int a, int b, vector unsigned int *c)
+{
+ __builtin_altivec_stvxl((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_stl(vector float a, int b, vector float *c)
+{
+ __builtin_altivec_stvxl((vector int)a, b, (void *)c);
+}
+
+/* vec_ste */
+
+#define __builtin_vec_stvebx __builtin_altivec_stvebx
+#define __builtin_vec_stvehx __builtin_altivec_stvehx
+#define __builtin_vec_stvewx __builtin_altivec_stvewx
+#define vec_stvebx __builtin_altivec_stvebx
+#define vec_stvehx __builtin_altivec_stvehx
+#define vec_stvewx __builtin_altivec_stvewx
+
+static void _ATTRS_o_ai
+vec_ste(vector signed char a, int b, vector signed char *c)
+{
+ __builtin_altivec_stvebx((vector char)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_ste(vector unsigned char a, int b, vector unsigned char *c)
+{
+ __builtin_altivec_stvebx((vector char)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_ste(vector short a, int b, vector short *c)
+{
+ __builtin_altivec_stvehx(a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_ste(vector unsigned short a, int b, vector unsigned short *c)
+{
+ __builtin_altivec_stvehx((vector short)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_ste(vector int a, int b, vector int *c)
+{
+ __builtin_altivec_stvewx(a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_ste(vector unsigned int a, int b, vector unsigned int *c)
+{
+ __builtin_altivec_stvewx((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_ste(vector float a, int b, vector float *c)
+{
+ __builtin_altivec_stvewx((vector int)a, b, (void *)c);
+}
+
+/* vec_cmpb */
+
+#define vec_cmpb __builtin_altivec_vcmpbfp
+#define vec_vcmpbfp __builtin_altivec_vcmpbfp
+#define __builtin_vec_cmpb __builtin_altivec_vcmpbfp
+
+/* vec_cmpeq */
+
+#define __builtin_vec_cmpeq vec_cmpeq
+
+static vector /*bool*/ char _ATTRS_o_ai
+vec_cmpeq(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpequb((vector char)a, (vector char)b);
+}
+
+static vector /*bool*/ char _ATTRS_o_ai
+vec_cmpeq(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpequb((vector char)a, (vector char)b);
+}
+
+static vector /*bool*/ short _ATTRS_o_ai
+vec_cmpeq(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpequh(a, b);
+}
+
+static vector /*bool*/ short _ATTRS_o_ai
+vec_cmpeq(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpequh((vector short)a, (vector short)b);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmpeq(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpequw(a, b);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmpeq(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpequw((vector int)a, (vector int)b);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmpeq(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpeqfp(a, b);
+}
+
+/* vec_cmpge */
+
+#define vec_cmpge __builtin_altivec_vcmpgefp
+#define vec_vcmpgefp __builtin_altivec_vcmpgefp
+#define __builtin_vec_cmpge __builtin_altivec_vcmpgefp
+
+/* vec_cmpgt */
+
+#define vec_vcmpgtsb __builtin_altivec_vcmpgtsb
+#define vec_vcmpgtub __builtin_altivec_vcmpgtub
+#define vec_vcmpgtsh __builtin_altivec_vcmpgtsh
+#define vec_vcmpgtuh __builtin_altivec_vcmpgtuh
+#define vec_vcmpgtsw __builtin_altivec_vcmpgtsw
+#define vec_vcmpgtuw __builtin_altivec_vcmpgtuw
+#define vec_vcmpgtfp __builtin_altivec_vcmpgtfp
+#define __builtin_vec_vcmpgtsb __builtin_altivec_vcmpgtsb
+#define __builtin_vec_vcmpgtub __builtin_altivec_vcmpgtub
+#define __builtin_vec_vcmpgtsh __builtin_altivec_vcmpgtsh
+#define __builtin_vec_vcmpgtuh __builtin_altivec_vcmpgtuh
+#define __builtin_vec_vcmpgtsw __builtin_altivec_vcmpgtsw
+#define __builtin_vec_vcmpgtuw __builtin_altivec_vcmpgtuw
+#define __builtin_vec_vcmpgtfp __builtin_altivec_vcmpgtfp
+
+static vector /*bool*/ char _ATTRS_o_ai
+vec_cmpgt(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb(a, b);
+}
+
+static vector /*bool*/ char _ATTRS_o_ai
+vec_cmpgt(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub(a, b);
+}
+
+static vector /*bool*/ short _ATTRS_o_ai
+vec_cmpgt(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh(a, b);
+}
+
+static vector /*bool*/ short _ATTRS_o_ai
+vec_cmpgt(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh(a, b);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmpgt(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw(a, b);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmpgt(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw(a, b);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmpgt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp(a, b);
+}
+
+/* vec_cmple */
+
+#define __builtin_vec_cmple vec_cmple
+
+static vector /*bool*/ int __attribute__((__always_inline__))
+vec_cmple(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgefp(b, a);
+}
+
+/* vec_cmplt */
+
+#define __builtin_vec_cmplt vec_cmplt
+
+static vector /*bool*/ char _ATTRS_o_ai
+vec_cmplt(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb(b, a);
+}
+
+static vector /*bool*/ char _ATTRS_o_ai
+vec_cmplt(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub(b, a);
+}
+
+static vector /*bool*/ short _ATTRS_o_ai
+vec_cmplt(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh(b, a);
+}
+
+static vector /*bool*/ short _ATTRS_o_ai
+vec_cmplt(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh(b, a);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmplt(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw(b, a);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmplt(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw(b, a);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmplt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp(b, a);
+}
+
+/* vec_max */
+
+#define __builtin_vec_vmaxsb __builtin_altivec_vmaxsb
+#define __builtin_vec_vmaxub __builtin_altivec_vmaxub
+#define __builtin_vec_vmaxsh __builtin_altivec_vmaxsh
+#define __builtin_vec_vmaxuh __builtin_altivec_vmaxuh
+#define __builtin_vec_vmaxsw __builtin_altivec_vmaxsw
+#define __builtin_vec_vmaxuw __builtin_altivec_vmaxuw
+#define __builtin_vec_vmaxfp __builtin_altivec_vmaxfp
+#define vec_vmaxsb __builtin_altivec_vmaxsb
+#define vec_vmaxub __builtin_altivec_vmaxub
+#define vec_vmaxsh __builtin_altivec_vmaxsh
+#define vec_vmaxuh __builtin_altivec_vmaxuh
+#define vec_vmaxsw __builtin_altivec_vmaxsw
+#define vec_vmaxuw __builtin_altivec_vmaxuw
+#define vec_vmaxfp __builtin_altivec_vmaxfp
+#define __builtin_vec_max vec_max
+
+static vector signed char _ATTRS_o_ai
+vec_max(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vmaxsb(a, b);
+}
+
+static vector unsigned char _ATTRS_o_ai
+vec_max(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vmaxub(a, b);
+}
+
+static vector short _ATTRS_o_ai
+vec_max(vector short a, vector short b)
+{
+ return __builtin_altivec_vmaxsh(a, b);
+}
+
+static vector unsigned short _ATTRS_o_ai
+vec_max(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vmaxuh(a, b);
+}
+
+static vector int _ATTRS_o_ai
+vec_max(vector int a, vector int b)
+{
+ return __builtin_altivec_vmaxsw(a, b);
+}
+
+static vector unsigned int _ATTRS_o_ai
+vec_max(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vmaxuw(a, b);
+}
+
+static vector float _ATTRS_o_ai
+vec_max(vector float a, vector float b)
+{
+ return __builtin_altivec_vmaxfp(a, b);
+}
+
+/* vec_mfvscr */
+
+#define __builtin_vec_mfvscr __builtin_altivec_mfvscr
+#define vec_mfvscr __builtin_altivec_mfvscr
+
+/* vec_min */
+
+#define __builtin_vec_vminsb __builtin_altivec_vminsb
+#define __builtin_vec_vminub __builtin_altivec_vminub
+#define __builtin_vec_vminsh __builtin_altivec_vminsh
+#define __builtin_vec_vminuh __builtin_altivec_vminuh
+#define __builtin_vec_vminsw __builtin_altivec_vminsw
+#define __builtin_vec_vminuw __builtin_altivec_vminuw
+#define __builtin_vec_vminfp __builtin_altivec_vminfp
+#define vec_vminsb __builtin_altivec_vminsb
+#define vec_vminub __builtin_altivec_vminub
+#define vec_vminsh __builtin_altivec_vminsh
+#define vec_vminuh __builtin_altivec_vminuh
+#define vec_vminsw __builtin_altivec_vminsw
+#define vec_vminuw __builtin_altivec_vminuw
+#define vec_vminfp __builtin_altivec_vminfp
+#define __builtin_vec_min vec_min
+
+static vector signed char _ATTRS_o_ai
+vec_min(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vminsb(a, b);
+}
+
+static vector unsigned char _ATTRS_o_ai
+vec_min(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vminub(a, b);
+}
+
+static vector short _ATTRS_o_ai
+vec_min(vector short a, vector short b)
+{
+ return __builtin_altivec_vminsh(a, b);
+}
+
+static vector unsigned short _ATTRS_o_ai
+vec_min(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vminuh(a, b);
+}
+
+static vector int _ATTRS_o_ai
+vec_min(vector int a, vector int b)
+{
+ return __builtin_altivec_vminsw(a, b);
+}
+
+static vector unsigned int _ATTRS_o_ai
+vec_min(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vminuw(a, b);
+}
+
+static vector float _ATTRS_o_ai
+vec_min(vector float a, vector float b)
+{
+ return __builtin_altivec_vminfp(a, b);
+}
+
+/* vec_mtvscr */
+
+#define __builtin_vec_mtvscr __builtin_altivec_mtvscr
+#define vec_mtvscr __builtin_altivec_mtvscr
+
+/* ------------------------------ predicates ------------------------------------ */
+
+static int __attribute__((__always_inline__))
+__builtin_vec_vcmpeq_p(char CR6_param, vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpeqfp_p(CR6_param, a, b);
+}
+
+static int __attribute__((__always_inline__))
+__builtin_vec_vcmpge_p(char CR6_param, vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgefp_p(CR6_param, a, b);
+}
+
+static int __attribute__((__always_inline__))
+__builtin_vec_vcmpgt_p(char CR6_param, vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(CR6_param, a, b);
+}
+
+/* vec_all_eq */
+
+static int _ATTRS_o_ai
+vec_all_eq(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_eq(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_eq(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_eq(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_eq(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_eq(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_eq(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT, a, b);
+}
+
+/* vec_all_ge */
+
+static int _ATTRS_o_ai
+vec_all_ge(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_ge(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_ge(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_ge(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_ge(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_ge(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_ge(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT, b, a);
+}
+
+/* vec_all_gt */
+
+static int _ATTRS_o_ai
+vec_all_gt(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_gt(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_gt(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_gt(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_gt(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_gt(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_gt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT, a, b);
+}
+
+/* vec_all_in */
+
+static int __attribute__((__always_inline__))
+vec_all_in(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpbfp_p(__CR6_EQ, a, b);
+}
+
+/* vec_all_le */
+
+static int _ATTRS_o_ai
+vec_all_le(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_le(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_le(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_le(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_le(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_le(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_le(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, a, b);
+}
+
+/* vec_all_lt */
+
+static int _ATTRS_o_ai
+vec_all_lt(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_lt(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_lt(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_lt(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_lt(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_lt(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_lt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT, b, a);
+}
+
+/* vec_all_nan */
+
+static int __attribute__((__always_inline__))
+vec_all_nan(vector float a)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, a, a);
+}
+
+/* vec_all_ne */
+
+static int _ATTRS_o_ai
+vec_all_ne(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_ne(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_ne(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_ne(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_ne(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_ne(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_ne(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, a, b);
+}
+
+/* vec_all_nge */
+
+static int __attribute__((__always_inline__))
+vec_all_nge(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgefp_p(__CR6_EQ, a, b);
+}
+
+/* vec_all_ngt */
+
+static int __attribute__((__always_inline__))
+vec_all_ngt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, a, b);
+}
+
+/* vec_all_nle */
+
+static int __attribute__((__always_inline__))
+vec_all_nle(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgefp_p(__CR6_EQ, b, a);
+}
+
+/* vec_all_nlt */
+
+static int __attribute__((__always_inline__))
+vec_all_nlt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, b, a);
+}
+
+/* vec_all_numeric */
+
+static int __attribute__((__always_inline__))
+vec_all_numeric(vector float a)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT, a, a);
+}
+
+/* vec_any_eq */
+
+static int _ATTRS_o_ai
+vec_any_eq(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_eq(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_eq(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_eq(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, (vector short)a, (vector short)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_eq(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_eq(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_eq(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, a, b);
+}
+
+/* vec_any_ge */
+
+static int _ATTRS_o_ai
+vec_any_ge(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_ge(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_ge(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_ge(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_ge(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_ge(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_ge(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, b, a);
+}
+
+/* vec_any_gt */
+
+static int _ATTRS_o_ai
+vec_any_gt(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_gt(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_gt(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_gt(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_gt(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_gt(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_gt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, a, b);
+}
+
+/* vec_any_le */
+
+static int _ATTRS_o_ai
+vec_any_le(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_le(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_le(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_le(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_le(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_le(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_le(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, a, b);
+}
+
+/* vec_any_lt */
+
+static int _ATTRS_o_ai
+vec_any_lt(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_lt(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_lt(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_lt(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_lt(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_lt(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_lt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, b, a);
+}
+
+/* vec_any_nan */
+
+static int __attribute__((__always_inline__))
+vec_any_nan(vector float a)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, a, a);
+}
+
+/* vec_any_ne */
+
+static int _ATTRS_o_ai
+vec_any_ne(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_ne(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_ne(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_ne(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, (vector short)a, (vector short)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_ne(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_ne(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_ne(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, a, b);
+}
+
+/* vec_any_nge */
+
+static int __attribute__((__always_inline__))
+vec_any_nge(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgefp_p(__CR6_LT_REV, a, b);
+}
+
+/* vec_any_ngt */
+
+static int __attribute__((__always_inline__))
+vec_any_ngt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, a, b);
+}
+
+/* vec_any_nle */
+
+static int __attribute__((__always_inline__))
+vec_any_nle(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgefp_p(__CR6_LT_REV, b, a);
+}
+
+/* vec_any_nlt */
+
+static int __attribute__((__always_inline__))
+vec_any_nlt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, b, a);
+}
+
+/* vec_any_numeric */
+
+static int __attribute__((__always_inline__))
+vec_any_numeric(vector float a)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, a, a);
+}
+
+/* vec_any_out */
+
+static int __attribute__((__always_inline__))
+vec_any_out(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpbfp_p(__CR6_EQ_REV, a, b);
+}
+
+#undef _ATTRS_o_ai
+
+#endif /* __ALTIVEC_H */
diff --git a/lib/Headers/arm_neon.h b/lib/Headers/arm_neon.h
new file mode 100644
index 0000000..4508a27
--- /dev/null
+++ b/lib/Headers/arm_neon.h
@@ -0,0 +1,537 @@
+/*===---- arm_neon.h - NEON intrinsics --------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __ARM_NEON_H
+#define __ARM_NEON_H
+
+#ifndef __ARM_NEON__
+#error "NEON support not enabled"
+#endif
+
+// NEON document appears to be specified in terms of stdint types.
+#include <stdint.h>
+
+// Define some NEON-specific scalar types for floats and polynomials.
+typedef float float32_t;
+typedef uint8_t poly8_t;
+
+// FIXME: probably need a 'poly' attribute or something for correct codegen to
+// disambiguate from uint16_t.
+typedef uint16_t poly16_t;
+
+typedef __attribute__(( __vector_size__(8) )) int8_t __neon_int8x8_t;
+typedef __attribute__(( __vector_size__(16) )) int8_t __neon_int8x16_t;
+typedef __attribute__(( __vector_size__(8) )) int16_t __neon_int16x4_t;
+typedef __attribute__(( __vector_size__(16) )) int16_t __neon_int16x8_t;
+typedef __attribute__(( __vector_size__(8) )) int32_t __neon_int32x2_t;
+typedef __attribute__(( __vector_size__(16) )) int32_t __neon_int32x4_t;
+typedef __attribute__(( __vector_size__(8) )) int64_t __neon_int64x1_t;
+typedef __attribute__(( __vector_size__(16) )) int64_t __neon_int64x2_t;
+typedef __attribute__(( __vector_size__(8) )) uint8_t __neon_uint8x8_t;
+typedef __attribute__(( __vector_size__(16) )) uint8_t __neon_uint8x16_t;
+typedef __attribute__(( __vector_size__(8) )) uint16_t __neon_uint16x4_t;
+typedef __attribute__(( __vector_size__(16) )) uint16_t __neon_uint16x8_t;
+typedef __attribute__(( __vector_size__(8) )) uint32_t __neon_uint32x2_t;
+typedef __attribute__(( __vector_size__(16) )) uint32_t __neon_uint32x4_t;
+typedef __attribute__(( __vector_size__(8) )) uint64_t __neon_uint64x1_t;
+typedef __attribute__(( __vector_size__(16) )) uint64_t __neon_uint64x2_t;
+typedef __attribute__(( __vector_size__(8) )) uint16_t __neon_float16x4_t;
+typedef __attribute__(( __vector_size__(16) )) uint16_t __neon_float16x8_t;
+typedef __attribute__(( __vector_size__(8) )) float32_t __neon_float32x2_t;
+typedef __attribute__(( __vector_size__(16) )) float32_t __neon_float32x4_t;
+typedef __attribute__(( __vector_size__(8) )) poly8_t __neon_poly8x8_t;
+typedef __attribute__(( __vector_size__(16) )) poly8_t __neon_poly8x16_t;
+typedef __attribute__(( __vector_size__(8) )) poly16_t __neon_poly16x4_t;
+typedef __attribute__(( __vector_size__(16) )) poly16_t __neon_poly16x8_t;
+
+typedef struct __int8x8_t {
+ __neon_int8x8_t val;
+} int8x8_t;
+
+typedef struct __int8x16_t {
+ __neon_int8x16_t val;
+} int8x16_t;
+
+typedef struct __int16x4_t {
+ __neon_int16x4_t val;
+} int16x4_t;
+
+typedef struct __int16x8_t {
+ __neon_int16x8_t val;
+} int16x8_t;
+
+typedef struct __int32x2_t {
+ __neon_int32x2_t val;
+} int32x2_t;
+
+typedef struct __int32x4_t {
+ __neon_int32x4_t val;
+} int32x4_t;
+
+typedef struct __int64x1_t {
+ __neon_int64x1_t val;
+} int64x1_t;
+
+typedef struct __int64x2_t {
+ __neon_int64x2_t val;
+} int64x2_t;
+
+typedef struct __uint8x8_t {
+ __neon_uint8x8_t val;
+} uint8x8_t;
+
+typedef struct __uint8x16_t {
+ __neon_uint8x16_t val;
+} uint8x16_t;
+
+typedef struct __uint16x4_t {
+ __neon_uint16x4_t val;
+} uint16x4_t;
+
+typedef struct __uint16x8_t {
+ __neon_uint16x8_t val;
+} uint16x8_t;
+
+typedef struct __uint32x2_t {
+ __neon_uint32x2_t val;
+} uint32x2_t;
+
+typedef struct __uint32x4_t {
+ __neon_uint32x4_t val;
+} uint32x4_t;
+
+typedef struct __uint64x1_t {
+ __neon_uint64x1_t val;
+} uint64x1_t;
+
+typedef struct __uint64x2_t {
+ __neon_uint64x2_t val;
+} uint64x2_t;
+
+typedef struct __float16x4_t {
+ __neon_float16x4_t val;
+} float16x4_t;
+
+typedef struct __float16x8_t {
+ __neon_float16x8_t val;
+} float16x8_t;
+
+typedef struct __float32x2_t {
+ __neon_float32x2_t val;
+} float32x2_t;
+
+typedef struct __float32x4_t {
+ __neon_float32x4_t val;
+} float32x4_t;
+
+typedef struct __poly8x8_t {
+ __neon_poly8x8_t val;
+} poly8x8_t;
+
+typedef struct __poly8x16_t {
+ __neon_poly8x16_t val;
+} poly8x16_t;
+
+typedef struct __poly16x4_t {
+ __neon_poly16x4_t val;
+} poly16x4_t;
+
+typedef struct __poly16x8_t {
+ __neon_poly16x8_t val;
+} poly16x8_t;
+
+// FIXME: write tool to stamp out the structure-of-array types, possibly gen this whole file.
+
+// Intrinsics, per ARM document DUI0348B
+#define __ai static __attribute__((__always_inline__))
+
+#define INTTYPES_WIDE(op, builtin) \
+ __ai int16x8_t op##_s8(int16x8_t a, int8x8_t b) { return (int16x8_t){ builtin(a.val, b.val) }; } \
+ __ai int32x4_t op##_s16(int32x4_t a, int16x4_t b) { return (int32x4_t){ builtin(a.val, b.val) }; } \
+ __ai int64x2_t op##_s32(int64x2_t a, int32x2_t b) { return (int64x2_t){ builtin(a.val, b.val) }; } \
+ __ai uint16x8_t op##_u8(uint16x8_t a, uint8x8_t b) { return (uint16x8_t){ builtin(a.val, b.val) }; } \
+ __ai uint32x4_t op##_u16(uint32x4_t a, uint16x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; } \
+ __ai uint64x2_t op##_u32(uint64x2_t a, uint32x2_t b) { return (uint64x2_t){ builtin(a.val, b.val) }; }
+
+#define INTTYPES_WIDENING(op, builtin) \
+ __ai int16x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int16x8_t){ builtin(a.val, b.val) }; } \
+ __ai int32x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int32x4_t){ builtin(a.val, b.val) }; } \
+ __ai int64x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int64x2_t){ builtin(a.val, b.val) }; } \
+ __ai uint16x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint16x8_t){ builtin(a.val, b.val) }; } \
+ __ai uint32x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; } \
+ __ai uint64x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint64x2_t){ builtin(a.val, b.val) }; }
+
+#define INTTYPES_WIDENING_MUL(op, builtin) \
+ __ai int16x8_t op##_s8(int16x8_t a, int8x8_t b, int8x8_t c) { return (int16x8_t){ builtin(a.val, b.val, c.val) }; } \
+ __ai int32x4_t op##_s16(int32x4_t a, int16x4_t b, int16x4_t c) { return (int32x4_t){ builtin(a.val, b.val, c.val) }; } \
+ __ai int64x2_t op##_s32(int64x2_t a, int32x2_t b, int32x2_t c) { return (int64x2_t){ builtin(a.val, b.val, c.val) }; } \
+ __ai uint16x8_t op##_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) { return (uint16x8_t){ builtin(a.val, b.val, c.val) }; } \
+ __ai uint32x4_t op##_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) { return (uint32x4_t){ builtin(a.val, b.val, c.val) }; } \
+ __ai uint64x2_t op##_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) { return (uint64x2_t){ builtin(a.val, b.val, c.val) }; }
+
+#define INTTYPES_NARROWING(op, builtin) \
+ __ai int8x8_t op##_s16(int16x8_t a, int16x8_t b) { return (int8x8_t){ builtin(a.val, b.val) }; } \
+ __ai int16x4_t op##_s32(int32x4_t a, int32x4_t b) { return (int16x4_t){ builtin(a.val, b.val) }; } \
+ __ai int32x2_t op##_s64(int64x2_t a, int64x2_t b) { return (int32x2_t){ builtin(a.val, b.val) }; } \
+ __ai uint8x8_t op##_u16(uint16x8_t a, uint16x8_t b) { return (uint8x8_t){ builtin(a.val, b.val) }; } \
+ __ai uint16x4_t op##_u32(uint32x4_t a, uint32x4_t b) { return (uint16x4_t){ builtin(a.val, b.val) }; } \
+ __ai uint32x2_t op##_u64(uint64x2_t a, uint64x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; }
+
+#define INTTYPES_ADD_32(op, builtin) \
+ __ai int8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){ builtin(a.val, b.val) }; } \
+ __ai int16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){ builtin(a.val, b.val) }; } \
+ __ai int32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){ builtin(a.val, b.val) }; } \
+ __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){ builtin(a.val, b.val) }; } \
+ __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){ builtin(a.val, b.val) }; } \
+ __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; } \
+ __ai int8x16_t op##q_s8(int8x16_t a, int8x16_t b) { return (int8x16_t){ builtin(a.val, b.val) }; } \
+ __ai int16x8_t op##q_s16(int16x8_t a, int16x8_t b) { return (int16x8_t){ builtin(a.val, b.val) }; } \
+ __ai int32x4_t op##q_s32(int32x4_t a, int32x4_t b) { return (int32x4_t){ builtin(a.val, b.val) }; } \
+ __ai uint8x16_t op##q_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){ builtin(a.val, b.val) }; } \
+ __ai uint16x8_t op##q_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){ builtin(a.val, b.val) }; } \
+ __ai uint32x4_t op##q_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; }
+
+#define INTTYPES_ADD_64(op, builtin) \
+ __ai int64x1_t op##_s64(int64x1_t a, int64x1_t b) { return (int64x1_t){ builtin(a.val, b.val) }; } \
+ __ai uint64x1_t op##_u64(uint64x1_t a, uint64x1_t b) { return (uint64x1_t){ builtin(a.val, b.val) }; } \
+ __ai int64x2_t op##q_s64(int64x2_t a, int64x2_t b) { return (int64x2_t){ builtin(a.val, b.val) }; } \
+ __ai uint64x2_t op##q_u64(uint64x2_t a, uint64x2_t b) { return (uint64x2_t){ builtin(a.val, b.val) }; }
+
+#define FLOATTYPES_CMP(op, builtin) \
+ __ai uint32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; } \
+ __ai uint32x4_t op##q_f32(float32x4_t a, float32x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; }
+
+#define INT_FLOAT_CMP_OP(op, cc) \
+ __ai uint8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (uint8x8_t){(__neon_uint8x8_t)(a.val cc b.val)}; } \
+ __ai uint16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (uint16x4_t){(__neon_uint16x4_t)(a.val cc b.val)}; } \
+ __ai uint32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (uint32x2_t){(__neon_uint32x2_t)(a.val cc b.val)}; } \
+ __ai uint32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (uint32x2_t){(__neon_uint32x2_t)(a.val cc b.val)}; } \
+ __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){a.val cc b.val}; } \
+ __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){a.val cc b.val}; } \
+ __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){a.val cc b.val}; } \
+ __ai uint8x16_t op##q_s8(int8x16_t a, int8x16_t b) { return (uint8x16_t){(__neon_uint8x16_t)(a.val cc b.val)}; } \
+ __ai uint16x8_t op##q_s16(int16x8_t a, int16x8_t b) { return (uint16x8_t){(__neon_uint16x8_t)(a.val cc b.val)}; } \
+ __ai uint32x4_t op##q_s32(int32x4_t a, int32x4_t b) { return (uint32x4_t){(__neon_uint32x4_t)(a.val cc b.val)}; } \
+ __ai uint32x4_t op##q_f32(float32x4_t a, float32x4_t b) { return (uint32x4_t){(__neon_uint32x4_t)(a.val cc b.val)}; } \
+ __ai uint8x16_t op##q_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){a.val cc b.val}; } \
+ __ai uint16x8_t op##q_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){a.val cc b.val}; } \
+ __ai uint32x4_t op##q_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){a.val cc b.val}; }
+
+#define INT_UNARY(op, builtin) \
+ __ai int8x8_t op##_s8(int8x8_t a) { return (int8x8_t){ builtin(a.val) }; } \
+ __ai int16x4_t op##_s16(int16x4_t a) { return (int16x4_t){ builtin(a.val) }; } \
+ __ai int32x2_t op##_s32(int32x2_t a) { return (int32x2_t){ builtin(a.val) }; } \
+ __ai int8x16_t op##q_s8(int8x16_t a) { return (int8x16_t){ builtin(a.val) }; } \
+ __ai int16x8_t op##q_s16(int16x8_t a) { return (int16x8_t){ builtin(a.val) }; } \
+ __ai int32x4_t op##q_s32(int32x4_t a) { return (int32x4_t){ builtin(a.val) }; }
+
+#define FP_UNARY(op, builtin) \
+ __ai float32x2_t op##_f32(float32x2_t a) { return (float32x2_t){ builtin(a.val) }; } \
+ __ai float32x4_t op##q_f32(float32x4_t a) { return (float32x4_t){ builtin(a.val) }; }
+
+#define FP_BINARY(op, builtin) \
+ __ai float32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (float32x2_t){ builtin(a.val, b.val) }; } \
+ __ai float32x4_t op##q_f32(float32x4_t a, float32x4_t b) { return (float32x4_t){ builtin(a.val, b.val) }; }
+
+#define INT_FP_PAIRWISE_ADD(op, builtin) \
+ __ai int8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){ builtin(a.val, b.val) }; } \
+ __ai int16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){ builtin(a.val, b.val) }; } \
+ __ai int32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){ builtin(a.val, b.val) }; } \
+ __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){ builtin(a.val, b.val) }; } \
+ __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){ builtin(a.val, b.val) }; } \
+ __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; } \
+ __ai float32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (float32x2_t){ builtin(a.val, b.val) }; }
+
+#define INT_LOGICAL_OP(op, lop) \
+ __ai int8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){ a.val lop b.val }; } \
+ __ai int16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){ a.val lop b.val }; } \
+ __ai int32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){ a.val lop b.val }; } \
+ __ai int64x1_t op##_s64(int64x1_t a, int64x1_t b) { return (int64x1_t){ a.val lop b.val }; } \
+ __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){ a.val lop b.val }; } \
+ __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){ a.val lop b.val }; } \
+ __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){ a.val lop b.val }; } \
+ __ai uint64x1_t op##_u64(uint64x1_t a, uint64x1_t b) { return (uint64x1_t){ a.val lop b.val }; } \
+ __ai int8x16_t op##q_s8(int8x16_t a, int8x16_t b) { return (int8x16_t){ a.val lop b.val }; } \
+ __ai int16x8_t op##q_s16(int16x8_t a, int16x8_t b) { return (int16x8_t){ a.val lop b.val }; } \
+ __ai int32x4_t op##q_s32(int32x4_t a, int32x4_t b) { return (int32x4_t){ a.val lop b.val }; } \
+ __ai int64x2_t op##q_s64(int64x2_t a, int64x2_t b) { return (int64x2_t){ a.val lop b.val }; } \
+ __ai uint8x16_t op##q_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){ a.val lop b.val }; } \
+ __ai uint16x8_t op##q_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){ a.val lop b.val }; } \
+ __ai uint32x4_t op##q_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){ a.val lop b.val }; } \
+ __ai uint64x2_t op##q_u64(uint64x2_t a, uint64x2_t b) { return (uint64x2_t){ a.val lop b.val }; }
+
+// vector add
+__ai int8x8_t vadd_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){a.val + b.val}; }
+__ai int16x4_t vadd_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){a.val + b.val}; }
+__ai int32x2_t vadd_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){a.val + b.val}; }
+__ai int64x1_t vadd_s64(int64x1_t a, int64x1_t b) { return (int64x1_t){a.val + b.val}; }
+__ai float32x2_t vadd_f32(float32x2_t a, float32x2_t b) { return (float32x2_t){a.val + b.val}; }
+__ai uint8x8_t vadd_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){a.val + b.val}; }
+__ai uint16x4_t vadd_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){a.val + b.val}; }
+__ai uint32x2_t vadd_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){a.val + b.val}; }
+__ai uint64x1_t vadd_u64(uint64x1_t a, uint64x1_t b) { return (uint64x1_t){a.val + b.val}; }
+__ai int8x16_t vaddq_s8(int8x16_t a, int8x16_t b) { return (int8x16_t){a.val + b.val}; }
+__ai int16x8_t vaddq_s16(int16x8_t a, int16x8_t b) { return (int16x8_t){a.val + b.val}; }
+__ai int32x4_t vaddq_s32(int32x4_t a, int32x4_t b) { return (int32x4_t){a.val + b.val}; }
+__ai int64x2_t vaddq_s64(int64x2_t a, int64x2_t b) { return (int64x2_t){a.val + b.val}; }
+__ai float32x4_t vaddq_f32(float32x4_t a, float32x4_t b) { return (float32x4_t){a.val + b.val}; }
+__ai uint8x16_t vaddq_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){a.val + b.val}; }
+__ai uint16x8_t vaddq_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){a.val + b.val}; }
+__ai uint32x4_t vaddq_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){a.val + b.val}; }
+__ai uint64x2_t vaddq_u64(uint64x2_t a, uint64x2_t b) { return (uint64x2_t){a.val + b.val}; }
+
+// vector long add
+INTTYPES_WIDENING(vaddl, __builtin_neon_vaddl)
+
+// vector wide add
+INTTYPES_WIDE(vaddw, __builtin_neon_vaddw)
+
+// halving add
+// rounding halving add
+INTTYPES_ADD_32(vhadd, __builtin_neon_vhadd)
+INTTYPES_ADD_32(vrhadd, __builtin_neon_vrhadd)
+
+// saturating add
+INTTYPES_ADD_32(vqadd, __builtin_neon_vqadd)
+INTTYPES_ADD_64(vqadd, __builtin_neon_vqadd)
+
+// add high half
+// rounding add high half
+INTTYPES_NARROWING(vaddhn, __builtin_neon_vaddhn)
+INTTYPES_NARROWING(vraddhn, __builtin_neon_vraddhn)
+
+// multiply
+// mul-poly
+
+// multiple accumulate
+// multiple subtract
+
+// multiple accumulate long
+// multiple subtract long
+INTTYPES_WIDENING_MUL(vmlal, __builtin_neon_vmlal)
+INTTYPES_WIDENING_MUL(vmlsl, __builtin_neon_vmlsl)
+
+// saturating doubling multiply high
+// saturating rounding doubling multiply high
+
+// saturating doubling multiply accumulate long
+// saturating doubling multiply subtract long
+
+// long multiply
+// long multiply-poly
+INTTYPES_WIDENING(vmull, __builtin_neon_vmull)
+__ai poly16x8_t vmull_p8(poly8x8_t a, poly8x8_t b) { return (poly16x8_t){ __builtin_neon_vmull(a.val, b.val) }; }
+
+// saturating doubling long multiply
+
+// subtract
+
+// long subtract
+INTTYPES_WIDENING(vsubl, __builtin_neon_vsubl)
+
+// wide subtract
+INTTYPES_WIDE(vsubw, __builtin_neon_vsubw)
+
+// saturating subtract
+INTTYPES_ADD_32(vqsub, __builtin_neon_vqsub)
+INTTYPES_ADD_64(vqsub, __builtin_neon_vqsub)
+
+// halving subtract
+INTTYPES_ADD_32(vhsub, __builtin_neon_vhsub)
+
+// subtract high half
+// rounding subtract high half
+INTTYPES_NARROWING(vsubhn, __builtin_neon_vsubhn)
+INTTYPES_NARROWING(vrsubhn, __builtin_neon_vrsubhn)
+
+// compare eq
+// compare ge
+// compare le
+// compare gt
+// compare lt
+INT_FLOAT_CMP_OP(vceq, ==)
+INT_FLOAT_CMP_OP(vcge, >=)
+INT_FLOAT_CMP_OP(vcle, <=)
+INT_FLOAT_CMP_OP(vcgt, >)
+INT_FLOAT_CMP_OP(vclt, <)
+
+// compare eq-poly
+
+// compare abs ge
+// compare abs le
+// compare abs gt
+// compare abs lt
+FLOATTYPES_CMP(vcage, __builtin_neon_vcage)
+FLOATTYPES_CMP(vcale, __builtin_neon_vcale)
+FLOATTYPES_CMP(vcagt, __builtin_neon_vcagt)
+FLOATTYPES_CMP(vcalt, __builtin_neon_vcalt)
+
+// test bits
+
+// abs diff
+INTTYPES_ADD_32(vabd, __builtin_neon_vabd)
+FP_BINARY(vabd, __builtin_neon_vabd)
+
+// abs diff long
+INTTYPES_WIDENING(vabdl, __builtin_neon_vabdl)
+
+// abs diff accumulate
+// abs diff accumulate long
+
+// max
+// min
+INTTYPES_ADD_32(vmax, __builtin_neon_vmax)
+FP_BINARY(vmax, __builtin_neon_vmax)
+INTTYPES_ADD_32(vmin, __builtin_neon_vmin)
+FP_BINARY(vmin, __builtin_neon_vmin)
+
+// pairwise add
+// pairwise max
+// pairwise min
+INT_FP_PAIRWISE_ADD(vpadd, __builtin_neon_vpadd)
+INT_FP_PAIRWISE_ADD(vpmax, __builtin_neon_vpmax)
+INT_FP_PAIRWISE_ADD(vpmin, __builtin_neon_vpmin)
+
+// long pairwise add
+// long pairwise add accumulate
+
+// recip
+// recip sqrt
+FP_BINARY(vrecps, __builtin_neon_vrecps)
+FP_BINARY(vrsqrts, __builtin_neon_vrsqrts)
+
+// shl by vec
+// saturating shl by vec
+// rounding shl by vec
+// saturating rounding shl by vec
+
+// shr by constant
+// shl by constant
+// rounding shr by constant
+// shr by constant and accumulate
+// rounding shr by constant and accumulate
+// saturating shl by constant
+// s->u saturating shl by constant
+// narrowing saturating shr by constant
+// s->u narrowing saturating shr by constant
+// s->u rounding narrowing saturating shr by constant
+// narrowing saturating shr by constant
+// rounding narrowing shr by constant
+// rounding narrowing saturating shr by constant
+// widening shl by constant
+
+// shr and insert
+// shl and insert
+
+// loads and stores, single vector
+// loads and stores, lane
+// loads, dupe
+
+// loads and stores, arrays
+
+// vget,vgetq lane
+// vset, vsetq lane
+
+// vcreate
+// vdup, vdupq
+// vmov, vmovq
+// vdup_lane, vdupq_lane
+// vcombine
+// vget_high, vget_low
+
+// vcvt {u,s} <-> f, f <-> f16
+// narrow
+// long move (unpack)
+// saturating narrow
+// saturating narrow s->u
+
+// table lookup
+// extended table lookup
+
+// mla with scalar
+// widening mla with scalar
+// widening saturating doubling mla with scalar
+// mls with scalar
+// widening mls with scalar
+// widening saturating doubling mls with scalar
+// mul by scalar
+// long mul with scalar
+// long mul by scalar
+// saturating doubling long mul with scalar
+// saturating doubling long mul by scalar
+// saturating doubling mul high with scalar
+// saturating doubling mul high by scalar
+// saturating rounding doubling mul high with scalar
+// saturating rounding doubling mul high by scalar
+// mla with scalar
+// widening mla with sclar
+// widening saturating doubling mla with scalar
+// mls with scalar
+// widening mls with scalar
+// widening saturating doubling mls with scalar
+
+// extract
+
+// endian swap (vrev)
+
+// negate
+
+// abs
+// saturating abs
+// saturating negate
+// count leading signs
+INT_UNARY(vabs, __builtin_neon_vabs)
+FP_UNARY(vabs, __builtin_neon_vabs)
+INT_UNARY(vqabs, __builtin_neon_vqabs)
+INT_UNARY(vqneg, __builtin_neon_vqneg)
+INT_UNARY(vcls, __builtin_neon_vcls)
+
+// count leading zeroes
+// popcount
+
+// recip_est
+// recip_sqrt_est
+
+// not-poly
+// not
+
+// and
+// or
+// xor
+// andn
+// orn
+INT_LOGICAL_OP(vand, &)
+INT_LOGICAL_OP(vorr, |)
+INT_LOGICAL_OP(veor, ^)
+INT_LOGICAL_OP(vbic, &~)
+INT_LOGICAL_OP(vorn, |~)
+
+// bitselect
+
+// transpose elts
+// interleave elts
+// deinterleave elts
+
+// vreinterpret
+
+#endif /* __ARM_NEON_H */
diff --git a/lib/Headers/nmmintrin.h b/lib/Headers/nmmintrin.h
index f24352b..cc213ce 100644
--- a/lib/Headers/nmmintrin.h
+++ b/lib/Headers/nmmintrin.h
@@ -32,4 +32,4 @@
just include it now then. */
#include <smmintrin.h>
#endif /* __SSE4_2__ */
-#endif /* _NMMINTRIN_H */ \ No newline at end of file
+#endif /* _NMMINTRIN_H */
diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h
index 15b6eaa..1785f31 100644
--- a/lib/Headers/stdint.h
+++ b/lib/Headers/stdint.h
@@ -218,11 +218,18 @@ typedef __uint_least8_t uint_fast8_t;
#define __intn_t(n) __stdint_join3( int, n, _t)
#define __uintn_t(n) __stdint_join3(uint, n, _t)
+#ifndef _INTPTR_T
#ifndef __intptr_t_defined
typedef __intn_t(__INTPTR_WIDTH__) intptr_t;
#define __intptr_t_defined
+#define _INTPTR_T
#endif
+#endif
+
+#ifndef _UINTPTR_T
typedef __uintn_t(__INTPTR_WIDTH__) uintptr_t;
+#define _UINTPTR_T
+#endif
/* C99 7.18.1.5 Greatest-width integer types.
*/
diff --git a/lib/Headers/tmmintrin.h b/lib/Headers/tmmintrin.h
index 09ebc23..07fea1c 100644
--- a/lib/Headers/tmmintrin.h
+++ b/lib/Headers/tmmintrin.h
@@ -67,7 +67,7 @@ _mm_abs_epi32(__m128i a)
}
#define _mm_alignr_epi8(a, b, n) (__builtin_ia32_palignr128((a), (b), (n)))
-#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n*8)))
+#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n)))
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_hadd_epi16(__m128i a, __m128i b)
diff --git a/lib/Index/ASTLocation.cpp b/lib/Index/ASTLocation.cpp
index c24f3bf..091bc78 100644
--- a/lib/Index/ASTLocation.cpp
+++ b/lib/Index/ASTLocation.cpp
@@ -87,7 +87,7 @@ void ASTLocation::print(llvm::raw_ostream &OS) const {
case N_Decl:
OS << "[Decl: " << AsDecl()->getDeclKindName() << " ";
if (const NamedDecl *ND = dyn_cast<NamedDecl>(AsDecl()))
- OS << ND->getNameAsString();
+ OS << ND;
break;
case N_Stmt:
@@ -97,7 +97,7 @@ void ASTLocation::print(llvm::raw_ostream &OS) const {
case N_NamedRef:
OS << "[NamedRef: " << AsNamedRef().ND->getDeclKindName() << " ";
- OS << AsNamedRef().ND->getNameAsString();
+ OS << AsNamedRef().ND;
break;
case N_Type: {
diff --git a/lib/Index/Analyzer.cpp b/lib/Index/Analyzer.cpp
index 7b414f2..1354fe6 100644
--- a/lib/Index/Analyzer.cpp
+++ b/lib/Index/Analyzer.cpp
@@ -153,9 +153,10 @@ public:
ObjCInterfaceDecl *MsgD = 0;
ObjCMessageExpr *Msg = cast<ObjCMessageExpr>(ASTLoc.AsStmt());
- if (Msg->getReceiver()) {
+ switch (Msg->getReceiverKind()) {
+ case ObjCMessageExpr::Instance: {
const ObjCObjectPointerType *OPT =
- Msg->getReceiver()->getType()->getAsObjCInterfacePointerType();
+ Msg->getInstanceReceiver()->getType()->getAsObjCInterfacePointerType();
// Can be anything! Accept it as a possibility..
if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType())
@@ -171,15 +172,34 @@ public:
// Should be an instance method.
if (!IsInstanceMethod)
return false;
+ break;
+ }
- } else {
+ case ObjCMessageExpr::Class: {
+ // Expecting class method.
+ if (IsInstanceMethod)
+ return false;
+
+ MsgD = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+ }
+
+ case ObjCMessageExpr::SuperClass:
// Expecting class method.
if (IsInstanceMethod)
return false;
- MsgD = Msg->getClassInfo().Decl;
- // FIXME: Case when we only have an identifier.
- assert(MsgD && "Identifier only");
+ MsgD = Msg->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ // Expecting instance method.
+ if (!IsInstanceMethod)
+ return false;
+
+ MsgD = Msg->getSuperType()->getAs<ObjCObjectPointerType>()
+ ->getInterfaceDecl();
+ break;
}
assert(MsgD);
@@ -248,31 +268,44 @@ public:
ObjCInterfaceDecl *MsgD = 0;
while (true) {
- if (Msg->getReceiver() == 0) {
- CanBeClassMethod = true;
- MsgD = Msg->getClassInfo().Decl;
- // FIXME: Case when we only have an identifier.
- assert(MsgD && "Identifier only");
- break;
- }
+ switch (Msg->getReceiverKind()) {
+ case ObjCMessageExpr::Instance: {
+ const ObjCObjectPointerType *OPT =
+ Msg->getInstanceReceiver()->getType()
+ ->getAsObjCInterfacePointerType();
+
+ if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) {
+ CanBeInstanceMethod = CanBeClassMethod = true;
+ break;
+ }
- const ObjCObjectPointerType *OPT =
- Msg->getReceiver()->getType()->getAsObjCInterfacePointerType();
+ if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) {
+ CanBeClassMethod = true;
+ break;
+ }
- if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) {
- CanBeInstanceMethod = CanBeClassMethod = true;
+ MsgD = OPT->getInterfaceDecl();
+ assert(MsgD);
+ CanBeInstanceMethod = true;
break;
}
+
+ case ObjCMessageExpr::Class:
+ CanBeClassMethod = true;
+ MsgD = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
- if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) {
+ case ObjCMessageExpr::SuperClass:
CanBeClassMethod = true;
+ MsgD = Msg->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
break;
- }
- MsgD = OPT->getInterfaceDecl();
- assert(MsgD);
- CanBeInstanceMethod = true;
- break;
+ case ObjCMessageExpr::SuperInstance:
+ CanBeInstanceMethod = true;
+ MsgD = Msg->getSuperType()->getAs<ObjCObjectPointerType>()
+ ->getInterfaceDecl();
+ break;
+ }
}
assert(CanBeInstanceMethod || CanBeClassMethod);
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 19f25ea..74e8d74 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -1874,9 +1874,10 @@ LexNextToken:
if (PP->isCurrentLexer(this)) {
// Start a new token. If this is a #include or something, the PP may
// want us starting at the beginning of the line again. If so, set
- // the StartOfLine flag.
+ // the StartOfLine flag and clear LeadingSpace.
if (IsAtStartOfLine) {
Result.setFlag(Token::StartOfLine);
+ Result.clearFlag(Token::LeadingSpace);
IsAtStartOfLine = false;
}
goto LexNextToken; // GCC isn't tail call eliminating.
@@ -2024,9 +2025,10 @@ LexNextToken:
if (PP->isCurrentLexer(this)) {
// Start a new token. If this is a #include or something, the PP may
// want us starting at the beginning of the line again. If so, set
- // the StartOfLine flag.
+ // the StartOfLine flag and clear LeadingSpace.
if (IsAtStartOfLine) {
Result.setFlag(Token::StartOfLine);
+ Result.clearFlag(Token::LeadingSpace);
IsAtStartOfLine = false;
}
goto LexNextToken; // GCC isn't tail call eliminating.
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 1cfa0e3..f425582 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -654,6 +654,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
llvm::APInt LitVal(PP.getTargetInfo().getIntWidth(), 0);
unsigned NumCharsSoFar = 0;
+ bool Warned = false;
while (begin[0] != '\'') {
uint64_t ResultChar;
if (begin[0] != '\\') // If this is a normal character, consume it.
@@ -670,8 +671,10 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
} else {
// Narrow character literals act as though their value is concatenated
// in this implementation, but warn on overflow.
- if (LitVal.countLeadingZeros() < 8)
+ if (LitVal.countLeadingZeros() < 8 && !Warned) {
PP.Diag(Loc, diag::warn_char_constant_too_large);
+ Warned = true;
+ }
LitVal <<= 8;
}
}
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 757ba90..417724b 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -716,7 +716,8 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID);
if (Callbacks)
- Callbacks->FileChanged(DigitTok.getLocation(), PPCallbacks::RenameFile,
+ Callbacks->FileChanged(CurPPLexer->getSourceLocation(),
+ PPCallbacks::RenameFile,
SrcMgr::C_User);
}
@@ -865,7 +866,7 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
else if (IsSystemHeader)
FileKind = SrcMgr::C_System;
- Callbacks->FileChanged(DigitTok.getLocation(), Reason, FileKind);
+ Callbacks->FileChanged(CurPPLexer->getSourceLocation(), Reason, FileKind);
}
}
@@ -1087,11 +1088,6 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
return;
}
- // Ask HeaderInfo if we should enter this #include file. If not, #including
- // this file will have no effect.
- if (!HeaderInfo.ShouldEnterIncludeFile(File, isImport))
- return;
-
// The #included file will be considered to be a system header if either it is
// in a system include directory, or if the #includer is a system include
// header.
@@ -1099,6 +1095,14 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
std::max(HeaderInfo.getFileDirFlavor(File),
SourceMgr.getFileCharacteristic(FilenameTok.getLocation()));
+ // Ask HeaderInfo if we should enter this #include file. If not, #including
+ // this file will have no effect.
+ if (!HeaderInfo.ShouldEnterIncludeFile(File, isImport)) {
+ if (Callbacks)
+ Callbacks->FileSkipped(*File, FilenameTok, FileCharacter);
+ return;
+ }
+
// Look up the file, create a File ID for it.
FileID FID = SourceMgr.createFileID(File, FilenameTok.getLocation(),
FileCharacter);
@@ -1108,10 +1112,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
}
// Finally, if all is good, enter the new file!
- std::string ErrorStr;
- if (EnterSourceFile(FID, CurDir, ErrorStr))
- Diag(FilenameTok, diag::err_pp_error_opening_file)
- << std::string(SourceMgr.getFileEntryForID(FID)->getName()) << ErrorStr;
+ EnterSourceFile(FID, CurDir, FilenameTok.getLocation());
}
/// HandleIncludeNextDirective - Implements #include_next.
@@ -1666,4 +1667,3 @@ void Preprocessor::HandleElifDirective(Token &ElifToken) {
return SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
/*FoundElse*/CI.FoundElse);
}
-
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index 335d3db..4a40405 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -64,8 +64,8 @@ PreprocessorLexer *Preprocessor::getCurrentFileLexer() const {
/// EnterSourceFile - Add a source file to the top of the include stack and
/// start lexing tokens from it instead of the current buffer.
-bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
- std::string &ErrorStr) {
+void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
+ SourceLocation Loc) {
assert(CurTokenLexer == 0 && "Cannot #include a file inside a macro!");
++NumEnteredSourceFiles;
@@ -75,19 +75,23 @@ bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
if (PTH) {
if (PTHLexer *PL = PTH->CreateLexer(FID)) {
EnterSourceFileWithPTH(PL, CurDir);
- return false;
+ return;
}
}
// Get the MemoryBuffer for this FID, if it fails, we fail.
bool Invalid = false;
- const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID,
- &Invalid);
- if (Invalid)
- return true;
+ const llvm::MemoryBuffer *InputFile =
+ getSourceManager().getBuffer(FID, Loc, &Invalid);
+ if (Invalid) {
+ SourceLocation FileStart = SourceMgr.getLocForStartOfFile(FID);
+ Diag(Loc, diag::err_pp_error_opening_file)
+ << std::string(SourceMgr.getBufferName(FileStart)) << "";
+ return;
+ }
EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir);
- return false;
+ return;
}
/// EnterSourceFileWithLexer - Add a source file to the top of the include stack
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 1c6a5ad..71bb4fc 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -487,28 +487,29 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
const LangOptions &LangOpts = PP.getLangOptions();
return llvm::StringSwitch<bool>(II->getName())
+ .Case("attribute_analyzer_noreturn", true)
+ .Case("attribute_cf_returns_not_retained", true)
+ .Case("attribute_cf_returns_retained", true)
+ .Case("attribute_ext_vector_type", true)
+ .Case("attribute_ns_returns_not_retained", true)
+ .Case("attribute_ns_returns_retained", true)
+ .Case("attribute_objc_ivar_unused", true)
+ .Case("attribute_overloadable", true)
.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_attributes", LangOpts.CPlusPlus0x)
.Case("cxx_auto_type", LangOpts.CPlusPlus0x)
+ .Case("cxx_decltype", LangOpts.CPlusPlus0x)
+ .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x)
.Case("cxx_exceptions", LangOpts.Exceptions)
- .Case("cxx_attributes", LangOpts.CPlusPlus0x)
+ .Case("cxx_rtti", LangOpts.RTTI)
.Case("cxx_static_assert", LangOpts.CPlusPlus0x)
.Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
- .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x)
+ .Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
+ //.Case("cxx_concepts", false)
+ //.Case("cxx_lambdas", false)
+ //.Case("cxx_nullptr", false)
//.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_cf_returns_not_retained", true)
- .Case("attribute_cf_returns_retained", true)
- .Case("attribute_ns_returns_not_retained", true)
- .Case("attribute_ns_returns_retained", true)
- .Case("attribute_objc_ivar_unused", true)
.Default(false);
}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 4598383..ce6d9ab 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -490,7 +490,7 @@ SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc,
/// EnterMainSourceFile - Enter the specified FileID as the main source file,
/// which implicitly adds the builtin defines etc.
-bool Preprocessor::EnterMainSourceFile() {
+void Preprocessor::EnterMainSourceFile() {
// We do not allow the preprocessor to reenter the main file. Doing so will
// cause FileID's to accumulate information from both runs (e.g. #line
// information) and predefined macros aren't guaranteed to be set properly.
@@ -498,9 +498,7 @@ bool Preprocessor::EnterMainSourceFile() {
FileID MainFileID = SourceMgr.getMainFileID();
// Enter the main file source buffer.
- std::string ErrorStr;
- if (EnterSourceFile(MainFileID, 0, ErrorStr))
- return true;
+ EnterSourceFile(MainFileID, 0, SourceLocation());
// Tell the header info that the main file was entered. If the file is later
// #imported, it won't be re-entered.
@@ -515,7 +513,7 @@ bool Preprocessor::EnterMainSourceFile() {
assert(!FID.isInvalid() && "Could not create FileID for predefines?");
// Start parsing the predefines.
- return EnterSourceFile(FID, 0, ErrorStr);
+ EnterSourceFile(FID, 0, SourceLocation());
}
void Preprocessor::EndSourceFile() {
diff --git a/lib/Lex/TokenConcatenation.cpp b/lib/Lex/TokenConcatenation.cpp
index 51d2e23..fc6db21 100644
--- a/lib/Lex/TokenConcatenation.cpp
+++ b/lib/Lex/TokenConcatenation.cpp
@@ -124,7 +124,8 @@ static char GetFirstChar(Preprocessor &PP, const Token &Tok) {
/// but the resulting output won't have incorrect concatenations going on.
/// Examples include "..", which we print with a space between, because we
/// don't want to track enough to tell "x.." from "...".
-bool TokenConcatenation::AvoidConcat(const Token &PrevTok,
+bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
+ const Token &PrevTok,
const Token &Tok) const {
// First, check to see if the tokens were directly adjacent in the original
// source. If they were, it must be okay to stick them together: if there
@@ -192,7 +193,8 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevTok,
return isalnum(FirstChar) || Tok.is(tok::numeric_constant) ||
FirstChar == '+' || FirstChar == '-' || FirstChar == '.';
case tok::period: // ..., .*, .1234
- return FirstChar == '.' || isdigit(FirstChar) ||
+ return (FirstChar == '.' && PrevPrevTok.is(tok::period)) ||
+ isdigit(FirstChar) ||
(PP.getLangOptions().CPlusPlus && FirstChar == '*');
case tok::amp: // &&
return FirstChar == '&';
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index 3cd74d5..bae2a09 100644
--- a/lib/Parse/AttributeList.cpp
+++ b/lib/Parse/AttributeList.cpp
@@ -23,7 +23,7 @@ AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc,
AttributeList *n, bool declspec, bool cxx0x)
: AttrName(aName), AttrLoc(aLoc), ScopeName(sName), ScopeLoc(sLoc),
ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(n),
- DeclspecAttribute(declspec), CXX0XAttribute(cxx0x) {
+ DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false) {
if (numArgs == 0)
Args = 0;
@@ -105,6 +105,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("overloadable", AT_overloadable)
.Case("address_space", AT_address_space)
.Case("always_inline", AT_always_inline)
+ .Case("returns_twice", IgnoredAttribute)
.Case("vec_type_hint", IgnoredAttribute)
.Case("objc_exception", AT_objc_exception)
.Case("ext_vector_type", AT_ext_vector_type)
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index 11865ab..5dc08b3 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -433,6 +433,7 @@ void DeclSpec::SaveWrittenBuiltinSpecs() {
void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
// Before possibly changing their values, save specs as written.
SaveWrittenBuiltinSpecs();
+ SaveStorageSpecifierAsWritten();
// Check the type specifier components first.
SourceManager &SrcMgr = PP.getSourceManager();
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index 5f48897..5a03767 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -26,11 +26,40 @@ ActionBase::~ActionBase() {}
/// Out-of-line virtual destructor to provide home for Action class.
Action::~Action() {}
+Action::ObjCMessageKind Action::getObjCMessageKind(Scope *S,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ bool IsSuper,
+ bool HasTrailingDot,
+ TypeTy *&ReceiverType) {
+ ReceiverType = 0;
+
+ if (IsSuper && !HasTrailingDot && S->isInObjcMethodScope())
+ return ObjCSuperMessage;
+
+ if (TypeTy *TyName = getTypeName(*Name, NameLoc, S)) {
+ DeclSpec DS;
+ const char *PrevSpec = 0;
+ unsigned DiagID = 0;
+ if (!DS.SetTypeSpecType(DeclSpec::TST_typename, NameLoc, PrevSpec,
+ DiagID, TyName)) {
+ DS.SetRangeEnd(NameLoc);
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ TypeResult Ty = ActOnTypeName(S, DeclaratorInfo);
+ if (!Ty.isInvalid())
+ ReceiverType = Ty.get();
+ }
+ return ObjCClassMessage;
+ }
+
+ return ObjCInstanceMessage;
+}
+
// Defined out-of-line here because of dependecy on AttributeList
Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope,
SourceLocation UsingLoc,
SourceLocation NamespcLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *NamespcName,
AttributeList *AttrList) {
@@ -47,7 +76,7 @@ Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope,
AccessSpecifier AS,
bool HasUsingKeyword,
SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
bool IsTypeName,
@@ -144,7 +173,7 @@ void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
/// FIXME: Use the passed CXXScopeSpec for accurate C++ type checking.
Action::TypeTy *
MinimalAction::getTypeName(IdentifierInfo &II, SourceLocation Loc,
- Scope *S, const CXXScopeSpec *SS,
+ Scope *S, CXXScopeSpec *SS,
bool isClassName, TypeTy *ObjectType) {
if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>())
if (TI->isTypeName)
@@ -161,7 +190,7 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *,
TemplateNameKind
MinimalAction::isTemplateName(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringScope,
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 87e22fa..5405c0c 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -29,12 +29,14 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D,
"Current token not a '{', ':' or 'try'!");
Action::MultiTemplateParamsArg TemplateParams(Actions,
- TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0,
- TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0);
+ TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0,
+ TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0);
+
DeclPtrTy FnD;
if (D.getDeclSpec().isFriendSpecified())
// FIXME: Friend templates
- FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true, move(TemplateParams));
+ FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true,
+ move(TemplateParams));
else // FIXME: pass template information through
FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D,
move(TemplateParams), 0, 0,
@@ -53,7 +55,7 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D,
// We may have a constructor initializer or function-try-block here.
if (kind == tok::colon || kind == tok::kw_try) {
// Consume everything up to (and including) the left brace.
- if (!ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks, tok::semi)) {
+ if (!ConsumeAndStoreUntil(tok::l_brace, Toks)) {
// We didn't find the left-brace we expected after the
// constructor initializer.
if (Tok.is(tok::semi)) {
@@ -72,13 +74,13 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D,
ConsumeBrace();
}
// Consume everything up to (and including) the matching right brace.
- ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
// If we're in a function-try-block, we need to store all the catch blocks.
if (kind == tok::kw_try) {
while (Tok.is(tok::kw_catch)) {
- ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks);
- ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
+ ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false);
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
}
}
@@ -98,7 +100,8 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
// The current scope is still active if we're the top-level class.
// Otherwise we'll need to push and enter a new scope.
bool HasClassScope = !Class.TopLevelClass;
- ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, HasClassScope);
+ ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
+ HasClassScope);
if (HasClassScope)
Actions.ActOnStartDelayedMemberDeclarations(CurScope, Class.TagOrTemplate);
@@ -217,12 +220,17 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
"ParseFunctionTryBlock left tokens in the token stream!");
continue;
}
- if (Tok.is(tok::colon))
+ if (Tok.is(tok::colon)) {
ParseConstructorInitializer(LM.D);
- else
+
+ // Error recovery.
+ if (!Tok.is(tok::l_brace)) {
+ Actions.ActOnFinishFunctionBody(LM.D, Action::StmtArg(Actions));
+ continue;
+ }
+ } else
Actions.ActOnDefaultCtorInitializers(LM.D);
- // FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'??
ParseFunctionStatementBody(LM.D);
assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
Tok.getLocation()) &&
@@ -238,14 +246,12 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
/// ConsumeAndStoreUntil - Consume and store the token at the passed token
/// container until the token 'T' is reached (which gets
/// consumed/stored too, if ConsumeFinalToken).
-/// If EarlyAbortIf is specified, then we will stop early if we find that
-/// token at the top level.
+/// If StopAtSemi is true, then we will stop early at a ';' character.
/// Returns true if token 'T1' or 'T2' was found.
/// NOTE: This is a specialized version of Parser::SkipUntil.
bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
CachedTokens &Toks,
- tok::TokenKind EarlyAbortIf,
- bool ConsumeFinalToken) {
+ bool StopAtSemi, bool ConsumeFinalToken) {
// We always want this function to consume at least one token if the first
// token isn't T and if not at EOF.
bool isFirstTokenConsumed = true;
@@ -259,10 +265,6 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
return true;
}
- // If we found the early-abort token, return.
- if (Tok.is(EarlyAbortIf))
- return false;
-
switch (Tok.getKind()) {
case tok::eof:
// Ran out of tokens.
@@ -272,19 +274,19 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
// Recursively consume properly-nested parens.
Toks.push_back(Tok);
ConsumeParen();
- ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks);
+ ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
break;
case tok::l_square:
// Recursively consume properly-nested square brackets.
Toks.push_back(Tok);
ConsumeBracket();
- ConsumeAndStoreUntil(tok::r_square, tok::unknown, Toks);
+ ConsumeAndStoreUntil(tok::r_square, Toks, /*StopAtSemi=*/false);
break;
case tok::l_brace:
// Recursively consume properly-nested braces.
Toks.push_back(Tok);
ConsumeBrace();
- ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
break;
// Okay, we found a ']' or '}' or ')', which we think should be balanced.
@@ -316,6 +318,10 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
Toks.push_back(Tok);
ConsumeStringToken();
break;
+ case tok::semi:
+ if (StopAtSemi)
+ return false;
+ // FALL THROUGH.
default:
// consume this token.
Toks.push_back(Tok);
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index c85b6ee..91050e0 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -904,7 +904,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// reinforced by the NAD status of core issue 635.
TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue());
- if (DSContext == DSC_top_level && TemplateId->Name &&
+ if ((DSContext == DSC_top_level ||
+ (DSContext == DSC_class && DS.isFriendSpecified())) &&
+ TemplateId->Name &&
Actions.isCurrentClassName(*TemplateId->Name, CurScope, &SS)) {
if (isConstructorDeclarator()) {
// The user meant this to be an out-of-line constructor
@@ -949,7 +951,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// 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 &&
+ if ((DSContext == DSC_top_level ||
+ (DSContext == DSC_class && DS.isFriendSpecified())) &&
Actions.isCurrentClassName(*Next.getIdentifierInfo(), CurScope,
&SS)) {
if (isConstructorDeclarator())
@@ -1434,6 +1437,11 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
switch (Tok.getKind()) {
case tok::identifier: // foo::bar
+ // If we already have a type specifier, this identifier is not a type.
+ if (DS.getTypeSpecType() != DeclSpec::TST_unspecified ||
+ DS.getTypeSpecWidth() != DeclSpec::TSW_unspecified ||
+ DS.getTypeSpecSign() != DeclSpec::TSS_unspecified)
+ return false;
// Check for need to substitute AltiVec keyword tokens.
if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
break;
@@ -1892,15 +1900,6 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
return;
}
- // enums cannot be templates.
- if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) {
- Diag(Tok, diag::err_enum_template);
-
- // Skip the rest of this declarator, up until the comma or semicolon.
- SkipUntil(tok::comma, true);
- return;
- }
-
// If an identifier is present, consume and remember it.
IdentifierInfo *Name = 0;
SourceLocation NameLoc;
@@ -1924,23 +1923,69 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
TUK = Action::TUK_Declaration;
else
TUK = Action::TUK_Reference;
+
+ // enums cannot be templates, although they can be referenced from a
+ // template.
+ if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
+ TUK != Action::TUK_Reference) {
+ Diag(Tok, diag::err_enum_template);
+
+ // Skip the rest of this declarator, up until the comma or semicolon.
+ SkipUntil(tok::comma, true);
+ return;
+ }
+
bool Owned = false;
bool IsDependent = false;
+ SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc;
+ const char *PrevSpec = 0;
+ unsigned DiagID;
DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK,
StartLoc, SS, Name, NameLoc, Attr.get(),
AS,
Action::MultiTemplateParamsArg(Actions),
Owned, IsDependent);
- assert(!IsDependent && "didn't expect dependent enum");
+ if (IsDependent) {
+ // This enum has a dependent nested-name-specifier. Handle it as a
+ // dependent tag.
+ if (!Name) {
+ DS.SetTypeSpecError();
+ Diag(Tok, diag::err_expected_type_name_after_typename);
+ return;
+ }
+
+ TypeResult Type = Actions.ActOnDependentTag(CurScope, DeclSpec::TST_enum,
+ TUK, SS, Name, StartLoc,
+ NameLoc);
+ if (Type.isInvalid()) {
+ DS.SetTypeSpecError();
+ return;
+ }
+
+ if (DS.SetTypeSpecType(DeclSpec::TST_typename, TSTLoc, PrevSpec, DiagID,
+ Type.get(), false))
+ Diag(StartLoc, DiagID) << PrevSpec;
+
+ return;
+ }
+ if (!TagDecl.get()) {
+ // The action failed to produce an enumeration tag. If this is a
+ // definition, consume the entire definition.
+ if (Tok.is(tok::l_brace)) {
+ ConsumeBrace();
+ SkipUntil(tok::r_brace);
+ }
+
+ DS.SetTypeSpecError();
+ return;
+ }
+
if (Tok.is(tok::l_brace))
ParseEnumBody(StartLoc, TagDecl);
// FIXME: The DeclSpec should keep the locations of both the keyword and the
// name (if there is one).
- SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc;
- const char *PrevSpec = 0;
- unsigned DiagID;
if (DS.SetTypeSpecType(DeclSpec::TST_enum, TSTLoc, PrevSpec, DiagID,
TagDecl.getAs<void>(), Owned))
Diag(StartLoc, DiagID) << PrevSpec;
@@ -2427,7 +2472,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); // ignore fail
- if (SS.isSet()) {
+ if (SS.isNotEmpty()) {
if (Tok.isNot(tok::star)) {
// The scope spec really belongs to the direct-declarator.
D.getCXXScopeSpec() = SS;
@@ -2583,36 +2628,42 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
if (getLang().CPlusPlus && D.mayHaveIdentifier()) {
// ParseDeclaratorInternal might already have parsed the scope.
- bool afterCXXScope = D.getCXXScopeSpec().isSet();
- if (!afterCXXScope) {
+ if (D.getCXXScopeSpec().isEmpty()) {
ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0,
true);
- afterCXXScope = D.getCXXScopeSpec().isSet();
}
- if (afterCXXScope) {
+ if (D.getCXXScopeSpec().isValid()) {
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();
- }
-
+ }
+
if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) ||
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();
+ bool AllowConstructorName;
+ if (D.getDeclSpec().hasTypeSpecifier())
+ AllowConstructorName = false;
+ else if (D.getCXXScopeSpec().isSet())
+ AllowConstructorName =
+ (D.getContext() == Declarator::FileContext ||
+ (D.getContext() == Declarator::MemberContext &&
+ D.getDeclSpec().isFriendSpecified()));
+ else
+ AllowConstructorName = (D.getContext() == Declarator::MemberContext);
+
if (ParseUnqualifiedId(D.getCXXScopeSpec(),
/*EnteringContext=*/true,
/*AllowDestructorName=*/true,
AllowConstructorName,
/*ObjectType=*/0,
- D.getName())) {
+ D.getName()) ||
+ // Once we're past the identifier, if the scope was bad, mark the
+ // whole declarator bad.
+ D.getCXXScopeSpec().isInvalid()) {
D.SetIdentifier(0, Tok.getLocation());
D.setInvalidType(true);
} else {
@@ -2974,7 +3025,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
DefArgToks = new CachedTokens;
if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks,
- tok::semi, false)) {
+ /*StopAtSemi=*/true,
+ /*ConsumeFinalToken=*/false)) {
delete DefArgToks;
DefArgToks = 0;
Actions.ActOnParamDefaultArgumentError(Param);
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 813c24c..015ac5b 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -178,7 +178,7 @@ Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS,
DeclPtrTy LinkageSpec
= Actions.ActOnStartLinkageSpecification(CurScope,
/*FIXME: */SourceLocation(),
- Loc, Lang.data(), Lang.size(),
+ Loc, Lang,
Tok.is(tok::l_brace)? Tok.getLocation()
: SourceLocation());
@@ -465,7 +465,7 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
/// simple-template-id
///
Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
- const CXXScopeSpec *SS) {
+ CXXScopeSpec *SS) {
// Check whether we have a template-id that names a type.
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId
@@ -780,9 +780,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
Action::DeclResult TagOrTempResult = true; // invalid
Action::TypeResult TypeResult = true; // invalid
- // FIXME: When TUK == TUK_Reference and we have a template-id, we need
- // to turn that template-id into a type.
-
bool Owned = false;
if (TemplateId) {
// Explicit specialization, class template partial specialization,
@@ -806,7 +803,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateArgsPtr,
TemplateId->RAngleLoc,
AttrList);
- } else if (TUK == Action::TUK_Reference) {
+
+ // Friend template-ids are treated as references unless
+ // they have template headers, in which case they're ill-formed
+ // (FIXME: "template <class T> friend class A<T>::B<int>;").
+ // We diagnose this error in ActOnClassTemplateSpecialization.
+ } else if (TUK == Action::TUK_Reference ||
+ (TUK == Action::TUK_Friend &&
+ TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) {
TypeResult
= Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
TemplateId->TemplateNameLoc,
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index af91021..b9e632a 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -29,30 +29,6 @@
#include "llvm/ADT/SmallString.h"
using namespace clang;
-/// PrecedenceLevels - These are precedences for the binary/ternary operators in
-/// the C99 grammar. These have been named to relate with the C99 grammar
-/// productions. Low precedences numbers bind more weakly than high numbers.
-namespace prec {
- enum Level {
- Unknown = 0, // Not binary operator.
- Comma = 1, // ,
- Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
- Conditional = 3, // ?
- LogicalOr = 4, // ||
- LogicalAnd = 5, // &&
- InclusiveOr = 6, // |
- ExclusiveOr = 7, // ^
- And = 8, // &
- Equality = 9, // ==, !=
- Relational = 10, // >=, <=, >, <
- Shift = 11, // <<, >>
- Additive = 12, // -, +
- Multiplicative = 13, // *, /, %
- PointerToMember = 14 // .*, ->*
- };
-}
-
-
/// getBinOpPrecedence - Return the precedence of the specified binary operator
/// token. This returns:
///
@@ -268,11 +244,11 @@ Parser::OwningExprResult Parser::ParseAssignmentExpression() {
/// expressions and other binary operators for these expressions as well.
Parser::OwningExprResult
Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc,
- SourceLocation NameLoc,
- IdentifierInfo *ReceiverName,
+ SourceLocation SuperLoc,
+ TypeTy *ReceiverType,
ExprArg ReceiverExpr) {
- OwningExprResult R(ParseObjCMessageExpressionBody(LBracLoc, NameLoc,
- ReceiverName,
+ OwningExprResult R(ParseObjCMessageExpressionBody(LBracLoc, SuperLoc,
+ ReceiverType,
move(ReceiverExpr)));
if (R.isInvalid()) return move(R);
R = ParsePostfixExpressionSuffix(move(R));
@@ -297,10 +273,10 @@ Parser::OwningExprResult Parser::ParseConstantExpression() {
/// ParseRHSOfBinaryExpression - Parse a binary expression that starts with
/// LHS and has a precedence of at least MinPrec.
Parser::OwningExprResult
-Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
- unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(),
- GreaterThanIsOperator,
- getLang().CPlusPlus0x);
+Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) {
+ prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(),
+ GreaterThanIsOperator,
+ getLang().CPlusPlus0x);
SourceLocation ColonLoc;
while (1) {
@@ -335,14 +311,15 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
Diag(Tok, diag::ext_gnu_conditional_expr);
}
- if (Tok.isNot(tok::colon)) {
- Diag(Tok, diag::err_expected_colon);
+ if (Tok.is(tok::colon)) {
+ // Eat the colon.
+ ColonLoc = ConsumeToken();
+ } else {
+ Diag(Tok, diag::err_expected_colon)
+ << FixItHint::CreateInsertion(Tok.getLocation(), ": ");
Diag(OpToken, diag::note_matching) << "?";
- return ExprError();
+ ColonLoc = Tok.getLocation();
}
-
- // Eat the colon.
- ColonLoc = ConsumeToken();
}
// Parse another leaf here for the RHS of the operator.
@@ -362,7 +339,7 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
// Remember the precedence of this operator and get the precedence of the
// operator immediately to the right of the RHS.
- unsigned ThisPrec = NextTokPrec;
+ prec::Level ThisPrec = NextTokPrec;
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
getLang().CPlusPlus0x);
@@ -379,7 +356,8 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
// is okay, to bind exactly as tightly. For example, compile A=B=C=D as
// A=(B=(C=D)), where each paren is a level of recursion here.
// The function takes ownership of the RHS.
- RHS = ParseRHSOfBinaryExpression(move(RHS), ThisPrec + !isRightAssoc);
+ RHS = ParseRHSOfBinaryExpression(move(RHS),
+ static_cast<prec::Level>(ThisPrec + !isRightAssoc));
if (RHS.isInvalid())
return move(RHS);
@@ -480,7 +458,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// [OBJC] '@encode' '(' type-name ')'
/// [OBJC] objc-string-literal
/// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
-/// [C++] typename-specifier '(' expression-list[opt] ')' [TODO]
+/// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
/// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
/// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
@@ -500,14 +478,14 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
///
/// id-expression: [C++ 5.1]
/// unqualified-id
-/// qualified-id [TODO]
+/// qualified-id
///
/// unqualified-id: [C++ 5.1]
/// identifier
/// operator-function-id
-/// conversion-function-id [TODO]
-/// '~' class-name [TODO]
-/// template-id [TODO]
+/// conversion-function-id
+/// '~' class-name
+/// template-id
///
/// new-expression: [C++ 5.3.4]
/// '::'[opt] 'new' new-placement[opt] new-type-id
@@ -637,11 +615,11 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
IdentifierInfo &II = *Tok.getIdentifierInfo();
SourceLocation ILoc = ConsumeToken();
- // Support 'Class.property' notation. We don't use
- // isTokObjCMessageIdentifierReceiver(), since it allows 'super' (which is
- // inappropriate here).
+ // Support 'Class.property' and 'super.property' notation.
if (getLang().ObjC1 && Tok.is(tok::period) &&
- Actions.getTypeName(II, ILoc, CurScope)) {
+ (Actions.getTypeName(II, ILoc, CurScope) ||
+ // Allow the base to be 'super' if in an objc-method.
+ (&II == Ident_super && CurScope->isInObjcMethodScope()))) {
SourceLocation DotLoc = ConsumeToken();
if (Tok.isNot(tok::identifier)) {
@@ -810,6 +788,14 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
}
case tok::annot_cxxscope: { // [C++] id-expression: qualified-id
+ // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
+ // (We can end up in this situation after tentative parsing.)
+ if (TryAnnotateTypeOrScopeToken())
+ return ExprError();
+ if (!Tok.is(tok::annot_cxxscope))
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, TypeOfCast);
+
Token Next = NextToken();
if (Next.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId
@@ -897,11 +883,16 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
}
case tok::caret:
return ParsePostfixExpressionSuffix(ParseBlockLiteralExpression());
+ case tok::code_completion:
+ Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression);
+ ConsumeToken();
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, TypeOfCast);
case tok::l_square:
// These can be followed by postfix-expr pieces.
if (getLang().ObjC1)
return ParsePostfixExpressionSuffix(ParseObjCMessageExpression());
- // FALL THROUGH.
+ // FALL THROUGH.
default:
NotCastExpr = true;
return ExprError();
@@ -1431,10 +1422,19 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
CastTy = Ty.get();
- if (stopIfCastExpr) {
- // Note that this doesn't parse the subsequent cast-expression, it just
- // returns the parsed type to the callee.
+ // Note that this doesn't parse the subsequent cast-expression, it just
+ // returns the parsed type to the callee.
+ if (stopIfCastExpr)
return OwningExprResult(Actions);
+
+ // Reject the cast of super idiom in ObjC.
+ if (Tok.is(tok::identifier) && getLang().ObjC1 &&
+ Tok.getIdentifierInfo() == Ident_super &&
+ CurScope->isInObjcMethodScope() &&
+ GetLookAheadToken(1).isNot(tok::period)) {
+ Diag(Tok.getLocation(), diag::err_illegal_super_cast)
+ << SourceRange(OpenLoc, RParenLoc);
+ return ExprError();
}
// Parse the cast-expression that follows it next.
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 8528f8f..146762b 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -749,6 +749,36 @@ bool Parser::ParseCXXCondition(OwningExprResult &ExprResult,
return false;
}
+/// \brief Determine whether the current token starts a C++
+/// simple-type-specifier.
+bool Parser::isCXXSimpleTypeSpecifier() const {
+ switch (Tok.getKind()) {
+ case tok::annot_typename:
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_int:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_wchar_t:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ case tok::kw_bool:
+ // FIXME: C++0x decltype support.
+ // GNU typeof support.
+ case tok::kw_typeof:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
/// This should only be called when the current token is known to be part of
/// simple-type-specifier.
@@ -837,6 +867,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID);
break;
+ // FIXME: C++0x decltype support.
// GNU typeof support.
case tok::kw_typeof:
ParseTypeofSpecifier(DS);
@@ -1703,7 +1734,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
// Store the tokens of the parentheses. We will parse them after we determine
// the context that follows them.
- if (!ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks, tok::semi)) {
+ if (!ConsumeAndStoreUntil(tok::r_paren, Toks)) {
// We didn't find the ')' we expected.
MatchRHSPunctuation(tok::r_paren, LParenLoc);
return ExprError();
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 9154d8d..a382a9a 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -14,6 +14,7 @@
#include "clang/Parse/Designator.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Scope.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -33,6 +34,19 @@ static bool MayBeDesignationStart(tok::TokenKind K, Preprocessor &PP) {
}
}
+static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
+ Designation &Desig) {
+ // If we have exactly one array designator, this used the GNU
+ // 'designation: array-designator' extension, otherwise there should be no
+ // designators at all!
+ if (Desig.getNumDesignators() == 1 &&
+ (Desig.getDesignator(0).isArrayDesignator() ||
+ Desig.getDesignator(0).isArrayRangeDesignator()))
+ P.Diag(Loc, diag::ext_gnu_missing_equal_designator);
+ else if (Desig.getNumDesignators() > 0)
+ P.Diag(Loc, diag::err_expected_equal_designator);
+}
+
/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
/// checking to see if the token stream starts with a designator.
///
@@ -123,33 +137,97 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
// [4][foo bar] -> obsolete GNU designation with objc message send.
//
SourceLocation StartLoc = ConsumeBracket();
+ OwningExprResult Idx(Actions);
+
+ // If Objective-C is enabled and this is a typename (class message
+ // send) or send to 'super', parse this as a message send
+ // expression. We handle C++ and C separately, since C++ requires
+ // much more complicated parsing.
+ if (getLang().ObjC1 && getLang().CPlusPlus) {
+ // Send to 'super'.
+ if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
+ NextToken().isNot(tok::period) && CurScope->isInObjcMethodScope()) {
+ CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
+ return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
+ ConsumeToken(), 0,
+ ExprArg(Actions));
+ }
+
+ // Parse the receiver, which is either a type or an expression.
+ bool IsExpr;
+ void *TypeOrExpr;
+ if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
+ SkipUntil(tok::r_square);
+ return ExprError();
+ }
+
+ // If the receiver was a type, we have a class message; parse
+ // the rest of it.
+ if (!IsExpr) {
+ CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
+ return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
+ SourceLocation(),
+ TypeOrExpr,
+ ExprArg(Actions));
+ }
- // If Objective-C is enabled and this is a typename or other identifier
- // receiver, parse this as a message send expression.
- if (getLang().ObjC1 && isTokObjCMessageIdentifierReceiver()) {
- // If we have exactly one array designator, this used the GNU
- // 'designation: array-designator' extension, otherwise there should be no
- // designators at all!
- if (Desig.getNumDesignators() == 1 &&
- (Desig.getDesignator(0).isArrayDesignator() ||
- Desig.getDesignator(0).isArrayRangeDesignator()))
- Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
- else if (Desig.getNumDesignators() > 0)
- Diag(Tok, diag::err_expected_equal_designator);
-
- IdentifierInfo *Name = Tok.getIdentifierInfo();
- SourceLocation NameLoc = ConsumeToken();
- return ParseAssignmentExprWithObjCMessageExprStart(
- StartLoc, NameLoc, Name, ExprArg(Actions));
+ // If the receiver was an expression, we still don't know
+ // whether we have a message send or an array designator; just
+ // adopt the expression for further analysis below.
+ // FIXME: potentially-potentially evaluated expression above?
+ Idx = OwningExprResult(Actions, TypeOrExpr);
+ } else if (getLang().ObjC1 && Tok.is(tok::identifier)) {
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ SourceLocation IILoc = Tok.getLocation();
+ TypeTy *ReceiverType;
+ // Three cases. This is a message send to a type: [type foo]
+ // This is a message send to super: [super foo]
+ // This is a message sent to an expr: [super.bar foo]
+ switch (Action::ObjCMessageKind Kind
+ = Actions.getObjCMessageKind(CurScope, II, IILoc,
+ II == Ident_super,
+ NextToken().is(tok::period),
+ ReceiverType)) {
+ case Action::ObjCSuperMessage:
+ case Action::ObjCClassMessage:
+ CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
+ if (Kind == Action::ObjCSuperMessage)
+ return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
+ ConsumeToken(),
+ 0,
+ ExprArg(Actions));
+ ConsumeToken(); // the identifier
+ if (!ReceiverType) {
+ SkipUntil(tok::r_square);
+ return ExprError();
+ }
+
+ return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
+ SourceLocation(),
+ ReceiverType,
+ ExprArg(Actions));
+
+ case Action::ObjCInstanceMessage:
+ // Fall through; we'll just parse the expression and
+ // (possibly) treat this like an Objective-C message send
+ // later.
+ break;
+ }
}
+ // Parse the index expression, if we haven't already gotten one
+ // above (which can only happen in Objective-C++).
// Note that we parse this as an assignment expression, not a constant
// expression (allowing *=, =, etc) to handle the objc case. Sema needs
// to validate that the expression is a constant.
- OwningExprResult Idx(ParseAssignmentExpression());
- if (Idx.isInvalid()) {
- SkipUntil(tok::r_square);
- return move(Idx);
+ // FIXME: We also need to tell Sema that we're in a
+ // potentially-potentially evaluated context.
+ if (!Idx.get()) {
+ Idx = ParseAssignmentExpression();
+ if (Idx.isInvalid()) {
+ SkipUntil(tok::r_square);
+ return move(Idx);
+ }
}
// Given an expression, we could either have a designator (if the next
@@ -158,17 +236,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
// an assignment-expression production.
if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) &&
Tok.isNot(tok::r_square)) {
-
- // If we have exactly one array designator, this used the GNU
- // 'designation: array-designator' extension, otherwise there should be no
- // designators at all!
- if (Desig.getNumDesignators() == 1 &&
- (Desig.getDesignator(0).isArrayDesignator() ||
- Desig.getDesignator(0).isArrayRangeDesignator()))
- Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
- else if (Desig.getNumDesignators() > 0)
- Diag(Tok, diag::err_expected_equal_designator);
-
+ CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig);
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
SourceLocation(),
0, move(Idx));
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 243be0e..7b1ecf6 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -142,13 +142,13 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
// We have a class or category name - consume it.
IdentifierInfo *nameId = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken();
- bool Err = false;
- if (Tok.is(tok::l_paren)) { // we have a category.
+ if (Tok.is(tok::l_paren) &&
+ !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.
SourceLocation lparenLoc = ConsumeParen();
SourceLocation categoryLoc, rparenLoc;
IdentifierInfo *categoryId = 0;
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCInterfaceCategory(CurScope, nameId);
+ Actions.CodeCompleteObjCInterfaceCategory(CurScope, nameId, nameLoc);
ConsumeToken();
}
@@ -157,12 +157,6 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
categoryId = Tok.getIdentifierInfo();
categoryLoc = ConsumeToken();
}
- else if (isKnownToBeTypeSpecifier(Tok)) {
- // Fall thru after diagnosing for better error recovery.
- Diag(Tok, diag::err_expected_minus_or_plus);
- ConsumeToken();
- Err = true;
- }
else if (!getLang().ObjC2) {
Diag(Tok, diag::err_expected_ident); // missing category name.
return DeclPtrTy();
@@ -173,34 +167,32 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
return DeclPtrTy();
}
rparenLoc = ConsumeParen();
- if (!Err) {
- // Next, we need to check for any protocol references.
- SourceLocation LAngleLoc, EndProtoLoc;
- llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs;
- llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
- if (Tok.is(tok::less) &&
- ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
+ // Next, we need to check for any protocol references.
+ SourceLocation LAngleLoc, EndProtoLoc;
+ llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs;
+ llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
+ if (Tok.is(tok::less) &&
+ ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
LAngleLoc, EndProtoLoc))
- return DeclPtrTy();
+ return DeclPtrTy();
- if (attrList) // categories don't support attributes.
- Diag(Tok, diag::err_objc_no_attributes_on_category);
-
- DeclPtrTy CategoryType =
- Actions.ActOnStartCategoryInterface(atLoc,
- nameId, nameLoc,
- categoryId, categoryLoc,
- ProtocolRefs.data(),
- ProtocolRefs.size(),
- ProtocolLocs.data(),
- EndProtoLoc);
- if (Tok.is(tok::l_brace))
+ if (attrList) // categories don't support attributes.
+ Diag(Tok, diag::err_objc_no_attributes_on_category);
+
+ DeclPtrTy CategoryType =
+ Actions.ActOnStartCategoryInterface(atLoc,
+ nameId, nameLoc,
+ categoryId, categoryLoc,
+ ProtocolRefs.data(),
+ ProtocolRefs.size(),
+ ProtocolLocs.data(),
+ EndProtoLoc);
+ if (Tok.is(tok::l_brace))
ParseObjCClassInstanceVariables(CategoryType, tok::objc_private,
atLoc);
- ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword);
- return CategoryType;
- }
+ ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword);
+ return CategoryType;
}
// Parse a class interface.
IdentifierInfo *superClassId = 0;
@@ -211,7 +203,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
// Code completion of superclass names.
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCSuperclass(CurScope, nameId);
+ Actions.CodeCompleteObjCSuperclass(CurScope, nameId, nameLoc);
ConsumeToken();
}
@@ -242,7 +234,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, atLoc);
ParseObjCInterfaceDeclList(ClsType, tok::objc_interface);
- return Err ? DeclPtrTy() : ClsType;
+ return ClsType;
}
/// The Objective-C property callback. This should be defined where
@@ -787,6 +779,12 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
tok::ObjCKeywordKind MethodImplKind) {
ParsingDeclRAIIObject PD(*this);
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus,
+ /*ReturnType=*/0, IDecl);
+ ConsumeToken();
+ }
+
// Parse the return type if present.
TypeTy *ReturnType = 0;
ObjCDeclSpec DSRet;
@@ -798,6 +796,12 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
MethodAttrs.reset(ParseGNUAttributes());
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus,
+ ReturnType, IDecl);
+ ConsumeToken();
+ }
+
// Now parse the selector.
SourceLocation selLoc;
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);
@@ -811,7 +815,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
return DeclPtrTy();
}
- llvm::SmallVector<Declarator, 8> CargNames;
+ llvm::SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo;
if (Tok.isNot(tok::colon)) {
// If attributes exist after the method, parse them.
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
@@ -822,7 +826,9 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
DeclPtrTy Result
= Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
mType, IDecl, DSRet, ReturnType, Sel,
- 0, CargNames, MethodAttrs.get(),
+ 0,
+ CParamInfo.data(), CParamInfo.size(),
+ MethodAttrs.get(),
MethodImplKind);
PD.complete(Result);
return Result;
@@ -885,7 +891,13 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// Parse the declarator.
Declarator ParmDecl(DS, Declarator::PrototypeContext);
ParseDeclarator(ParmDecl);
- CargNames.push_back(ParmDecl);
+ IdentifierInfo *ParmII = ParmDecl.getIdentifier();
+ DeclPtrTy Param = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
+ CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
+ ParmDecl.getIdentifierLoc(),
+ Param,
+ 0));
+
}
// FIXME: Add support for optional parmameter list...
@@ -901,7 +913,8 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
DeclPtrTy Result
= Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
mType, IDecl, DSRet, ReturnType, Sel,
- &ArgInfos[0], CargNames,
+ &ArgInfos[0],
+ CParamInfo.data(), CParamInfo.size(),
MethodAttrs.get(),
MethodImplKind, isVariadic);
PD.complete(Result);
@@ -1053,7 +1066,8 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
= P.Actions.ActOnIvar(P.CurScope,
FD.D.getDeclSpec().getSourceRange().getBegin(),
IDecl, FD.D, FD.BitfieldSize, visibility);
- AllIvarDecls.push_back(Field);
+ if (Field)
+ AllIvarDecls.push_back(Field);
return Field;
}
} Callback(*this, interfaceDecl, visibility, AllIvarDecls);
@@ -1207,7 +1221,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
IdentifierInfo *categoryId = 0;
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCImplementationCategory(CurScope, nameId);
+ Actions.CodeCompleteObjCImplementationCategory(CurScope, nameId, nameLoc);
ConsumeToken();
}
@@ -1404,8 +1418,12 @@ Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
break;
ConsumeToken(); // consume ','
}
- if (Tok.isNot(tok::semi))
+ if (Tok.isNot(tok::semi)) {
Diag(Tok, diag::err_expected_semi_after) << "@dynamic";
+ SkipUntil(tok::semi);
+ }
+ else
+ ConsumeToken(); // consume ';'
return DeclPtrTy();
}
@@ -1422,7 +1440,8 @@ Parser::OwningStmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
return StmtError();
}
}
- ConsumeToken(); // consume ';'
+ // consume ';'
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@throw");
return Actions.ActOnObjCAtThrowStmt(atLoc, move(Res), CurScope);
}
@@ -1482,7 +1501,7 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
Diag(Tok, diag::err_expected_lbrace);
return StmtError();
}
- OwningStmtResult CatchStmts(Actions);
+ StmtVector CatchStmts(Actions);
OwningStmtResult FinallyStmt(Actions);
ParseScope TryScope(this, Scope::DeclScope);
OwningStmtResult TryBody(ParseCompoundStatementBody());
@@ -1515,11 +1534,9 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
Declarator ParmDecl(DS, Declarator::PrototypeContext);
ParseDeclarator(ParmDecl);
- // Inform the actions module about the parameter declarator, so it
+ // Inform the actions module about the declarator, so it
// gets added to the current scope.
- // FIXME. Probably can build a VarDecl and avoid setting DeclContext.
- FirstPart = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
- Actions.ActOnObjCCatchParam(FirstPart);
+ FirstPart = Actions.ActOnObjCExceptionDecl(CurScope, ParmDecl);
} else
ConsumeToken(); // consume '...'
@@ -1537,9 +1554,14 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
Diag(Tok, diag::err_expected_lbrace);
if (CatchBody.isInvalid())
CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
- CatchStmts = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
- RParenLoc, FirstPart, move(CatchBody),
- move(CatchStmts));
+
+ OwningStmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
+ RParenLoc,
+ FirstPart,
+ move(CatchBody));
+ if (!Catch.isInvalid())
+ CatchStmts.push_back(Catch.release());
+
} else {
Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
<< "@catch clause";
@@ -1568,7 +1590,9 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
Diag(atLoc, diag::err_missing_catch_finally);
return StmtError();
}
- return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody), move(CatchStmts),
+
+ return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody),
+ move_arg(CatchStmts),
move(FinallyStmt));
}
@@ -1604,7 +1628,8 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() {
SourceLocation BraceLoc = Tok.getLocation();
// Enter a scope for the method body.
- ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
+ ParseScope BodyScope(this,
+ Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope);
// Tell the actions module that we have entered a method definition with the
// specified Declarator for the method.
@@ -1683,39 +1708,191 @@ Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
}
}
+/// \brirg Parse the receiver of an Objective-C++ message send.
+///
+/// This routine parses the receiver of a message send in
+/// Objective-C++ either as a type or as an expression. Note that this
+/// routine must not be called to parse a send to 'super', since it
+/// has no way to return such a result.
+///
+/// \param IsExpr Whether the receiver was parsed as an expression.
+///
+/// \param TypeOrExpr If the receiver was parsed as an expression (\c
+/// IsExpr is true), the parsed expression. If the receiver was parsed
+/// as a type (\c IsExpr is false), the parsed type.
+///
+/// \returns True if an error occurred during parsing or semantic
+/// analysis, in which case the arguments do not have valid
+/// values. Otherwise, returns false for a successful parse.
+///
+/// objc-receiver: [C++]
+/// 'super' [not parsed here]
+/// expression
+/// simple-type-specifier
+/// typename-specifier
+
+bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
+ if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
+ Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope))
+ TryAnnotateTypeOrScopeToken();
+
+ if (!isCXXSimpleTypeSpecifier()) {
+ // objc-receiver:
+ // expression
+ OwningExprResult Receiver = ParseExpression();
+ if (Receiver.isInvalid())
+ return true;
+
+ IsExpr = true;
+ TypeOrExpr = Receiver.take();
+ return false;
+ }
+
+ // objc-receiver:
+ // typename-specifier
+ // simple-type-specifier
+ // expression (that starts with one of the above)
+ DeclSpec DS;
+ ParseCXXSimpleTypeSpecifier(DS);
+
+ if (Tok.is(tok::l_paren)) {
+ // If we see an opening parentheses at this point, we are
+ // actually parsing an expression that starts with a
+ // function-style cast, e.g.,
+ //
+ // postfix-expression:
+ // simple-type-specifier ( expression-list [opt] )
+ // typename-specifier ( expression-list [opt] )
+ //
+ // Parse the remainder of this case, then the (optional)
+ // postfix-expression suffix, followed by the (optional)
+ // right-hand side of the binary expression. We have an
+ // instance method.
+ OwningExprResult Receiver = ParseCXXTypeConstructExpression(DS);
+ if (!Receiver.isInvalid())
+ Receiver = ParsePostfixExpressionSuffix(move(Receiver));
+ if (!Receiver.isInvalid())
+ Receiver = ParseRHSOfBinaryExpression(move(Receiver), prec::Comma);
+ if (Receiver.isInvalid())
+ return true;
+
+ IsExpr = true;
+ TypeOrExpr = Receiver.take();
+ return false;
+ }
+
+ // We have a class message. Turn the simple-type-specifier or
+ // typename-specifier we parsed into a type and parse the
+ // remainder of the class message.
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ TypeResult Type = Actions.ActOnTypeName(CurScope, DeclaratorInfo);
+ if (Type.isInvalid())
+ return true;
+
+ IsExpr = false;
+ TypeOrExpr = Type.get();
+ return false;
+}
+
/// objc-message-expr:
/// '[' objc-receiver objc-message-args ']'
///
-/// objc-receiver:
+/// objc-receiver: [C]
+/// 'super'
/// expression
/// class-name
/// type-name
+///
Parser::OwningExprResult Parser::ParseObjCMessageExpression() {
assert(Tok.is(tok::l_square) && "'[' expected");
SourceLocation LBracLoc = ConsumeBracket(); // consume '['
- // Parse receiver
- if (isTokObjCMessageIdentifierReceiver()) {
- IdentifierInfo *ReceiverName = Tok.getIdentifierInfo();
- if (ReceiverName != Ident_super || GetLookAheadToken(1).isNot(tok::period)) {
- SourceLocation NameLoc = ConsumeToken();
- return ParseObjCMessageExpressionBody(LBracLoc, NameLoc, ReceiverName,
+ if (getLang().CPlusPlus) {
+ // We completely separate the C and C++ cases because C++ requires
+ // more complicated (read: slower) parsing.
+
+ // Handle send to super.
+ // FIXME: This doesn't benefit from the same typo-correction we
+ // get in Objective-C.
+ if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
+ NextToken().isNot(tok::period) && CurScope->isInObjcMethodScope())
+ return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), 0,
ExprArg(Actions));
+
+ // Parse the receiver, which is either a type or an expression.
+ bool IsExpr;
+ void *TypeOrExpr;
+ if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
+ SkipUntil(tok::r_square);
+ return ExprError();
}
- }
+ if (IsExpr)
+ return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 0,
+ OwningExprResult(Actions, TypeOrExpr));
+
+ return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
+ TypeOrExpr, ExprArg(Actions));
+ } else if (Tok.is(tok::identifier)) {
+ IdentifierInfo *Name = Tok.getIdentifierInfo();
+ SourceLocation NameLoc = Tok.getLocation();
+ TypeTy *ReceiverType;
+ switch (Actions.getObjCMessageKind(CurScope, Name, NameLoc,
+ Name == Ident_super,
+ NextToken().is(tok::period),
+ ReceiverType)) {
+ case Action::ObjCSuperMessage:
+ return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), 0,
+ ExprArg(Actions));
+
+ case Action::ObjCClassMessage:
+ if (!ReceiverType) {
+ SkipUntil(tok::r_square);
+ return ExprError();
+ }
+
+ ConsumeToken(); // the type name
+
+ return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
+ ReceiverType,
+ ExprArg(Actions));
+
+ case Action::ObjCInstanceMessage:
+ // Fall through to parse an expression.
+ break;
+ }
+ }
+
+ // Otherwise, an arbitrary expression can be the receiver of a send.
OwningExprResult Res(ParseExpression());
if (Res.isInvalid()) {
SkipUntil(tok::r_square);
return move(Res);
}
- return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
- 0, move(Res));
+ return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 0,
+ move(Res));
}
-/// ParseObjCMessageExpressionBody - Having parsed "'[' objc-receiver", parse
-/// the rest of a message expression.
+/// \brief Parse the remainder of an Objective-C message following the
+/// '[' objc-receiver.
+///
+/// This routine handles sends to super, class messages (sent to a
+/// class name), and instance messages (sent to an object), and the
+/// target is represented by \p SuperLoc, \p ReceiverType, or \p
+/// ReceiverExpr, respectively. Only one of these parameters may have
+/// a valid value.
+///
+/// \param LBracLoc The location of the opening '['.
+///
+/// \param SuperLoc If this is a send to 'super', the location of the
+/// 'super' keyword that indicates a send to the superclass.
+///
+/// \param ReceiverType If this is a class message, the type of the
+/// class we are sending a message to.
+///
+/// \param ReceiverExpr If this is an instance message, the expression
+/// used to compute the receiver object.
///
/// objc-message-args:
/// objc-selector
@@ -1737,13 +1914,14 @@ Parser::OwningExprResult Parser::ParseObjCMessageExpression() {
///
Parser::OwningExprResult
Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
- SourceLocation NameLoc,
- IdentifierInfo *ReceiverName,
+ SourceLocation SuperLoc,
+ TypeTy *ReceiverType,
ExprArg ReceiverExpr) {
if (Tok.is(tok::code_completion)) {
- if (ReceiverName)
- Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverName, NameLoc,
- 0, 0);
+ if (SuperLoc.isValid())
+ Actions.CodeCompleteObjCSuperMessage(CurScope, SuperLoc, 0, 0);
+ else if (ReceiverType)
+ Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverType, 0, 0);
else
Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(),
0, 0);
@@ -1789,8 +1967,12 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// Code completion after each argument.
if (Tok.is(tok::code_completion)) {
- if (ReceiverName)
- Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverName, NameLoc,
+ if (SuperLoc.isValid())
+ Actions.CodeCompleteObjCSuperMessage(CurScope, SuperLoc,
+ KeyIdents.data(),
+ KeyIdents.size());
+ else if (ReceiverType)
+ Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverType,
KeyIdents.data(),
KeyIdents.size());
else
@@ -1851,15 +2033,23 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
KeyIdents.push_back(selIdent);
Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]);
- // We've just parsed a keyword message.
- if (ReceiverName)
- return Owned(Actions.ActOnClassMessage(CurScope, ReceiverName, Sel,
- LBracLoc, NameLoc, SelectorLoc,
- RBracLoc,
- KeyExprs.take(), KeyExprs.size()));
- return Owned(Actions.ActOnInstanceMessage(ReceiverExpr.release(), Sel,
- LBracLoc, SelectorLoc, RBracLoc,
- KeyExprs.take(), KeyExprs.size()));
+ if (SuperLoc.isValid())
+ return Actions.ActOnSuperMessage(CurScope, SuperLoc, Sel,
+ LBracLoc, SelectorLoc, RBracLoc,
+ Action::MultiExprArg(Actions,
+ KeyExprs.take(),
+ KeyExprs.size()));
+ else if (ReceiverType)
+ return Actions.ActOnClassMessage(CurScope, ReceiverType, Sel,
+ LBracLoc, SelectorLoc, RBracLoc,
+ Action::MultiExprArg(Actions,
+ KeyExprs.take(),
+ KeyExprs.size()));
+ return Actions.ActOnInstanceMessage(CurScope, move(ReceiverExpr), Sel,
+ LBracLoc, SelectorLoc, RBracLoc,
+ Action::MultiExprArg(Actions,
+ KeyExprs.take(),
+ KeyExprs.size()));
}
Parser::OwningExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index b208c50..9b22270 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -643,6 +643,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) {
if (Tok.is(tok::kw_else)) {
ElseLoc = ConsumeToken();
+ ElseStmtLoc = Tok.getLocation();
// C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do
@@ -656,12 +657,14 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) {
ParseScope InnerScope(this, Scope::DeclScope,
C99orCXX && Tok.isNot(tok::l_brace));
- bool WithinElse = CurScope->isWithinElse();
- CurScope->setWithinElse(true);
- ElseStmtLoc = Tok.getLocation();
+ // Regardless of whether or not InnerScope actually pushed a scope, set the
+ // ElseScope flag for the innermost scope so we can diagnose use of the if
+ // condition variable in C++.
+ unsigned OldFlags = CurScope->getFlags();
+ CurScope->setFlags(OldFlags | Scope::ElseScope);
ElseStmt = ParseStatement();
- CurScope->setWithinElse(WithinElse);
-
+ CurScope->setFlags(OldFlags);
+
// Pop the 'else' scope if needed.
InnerScope.Exit();
}
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 516a9a6..a6c6d3f 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -14,6 +14,7 @@
#include "clang/Parse/Parser.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Template.h"
using namespace clang;
/// isCXXDeclarationStatement - C++-specialized function that disambiguates
@@ -761,6 +762,17 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw___vector:
return TPResult::True();
+ case tok::annot_template_id: {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (TemplateId->Kind != TNK_Type_template)
+ return TPResult::False();
+ CXXScopeSpec SS;
+ AnnotateTemplateIdTokenAsType(&SS);
+ assert(Tok.is(tok::annot_typename));
+ goto case_typename;
+ }
+
case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed
// We've already annotated a scope; try to annotate a type.
if (TryAnnotateTypeOrScopeToken())
@@ -801,6 +813,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw_double:
case tok::kw_void:
case tok::annot_typename:
+ case_typename:
if (NextToken().is(tok::l_paren))
return TPResult::Ambiguous();
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 489586c..6dbb99e 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -668,9 +668,15 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// If we have a colon, then we're probably parsing a C++
// ctor-initializer.
- if (Tok.is(tok::colon))
+ if (Tok.is(tok::colon)) {
ParseConstructorInitializer(Res);
- else
+
+ // Recover from error.
+ if (!Tok.is(tok::l_brace)) {
+ Actions.ActOnFinishFunctionBody(Res, Action::StmtArg(Actions));
+ return Res;
+ }
+ } else
Actions.ActOnDefaultCtorInitializers(Res);
return ParseFunctionStatementBody(Res);
@@ -1046,7 +1052,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext))
return true;
- if (!SS.isSet())
+ if (SS.isEmpty())
return false;
// Push the current token back into the token stream (or revert it if it is
diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp
index 7b78070..5fe0649 100644
--- a/lib/Rewrite/HTMLRewrite.cpp
+++ b/lib/Rewrite/HTMLRewrite.cpp
@@ -533,6 +533,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
std::string Expansion = EscapeText(TmpPP.getSpelling(Tok));
unsigned LineLen = Expansion.size();
+ Token PrevPrevTok;
Token PrevTok = Tok;
// Okay, eat this token, getting the next one.
TmpPP.Lex(Tok);
@@ -553,13 +554,14 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
// If the tokens were already space separated, or if they must be to avoid
// them being implicitly pasted, add a space between them.
if (Tok.hasLeadingSpace() ||
- ConcatInfo.AvoidConcat(PrevTok, Tok))
+ ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok))
Expansion += ' ';
// Escape any special characters in the token text.
Expansion += EscapeText(TmpPP.getSpelling(Tok));
LineLen += Expansion.size();
+ PrevPrevTok = PrevTok;
PrevTok = Tok;
TmpPP.Lex(Tok);
}
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp
index bf8ba70..376678a 100644
--- a/lib/Rewrite/Rewriter.cpp
+++ b/lib/Rewrite/Rewriter.cpp
@@ -20,6 +20,12 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+llvm::raw_ostream &RewriteBuffer::write(llvm::raw_ostream &os) const {
+ // FIXME: eliminate the copy by writing out each chunk at a time
+ os << std::string(begin(), end());
+ return os;
+}
+
void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) {
// Nothing to remove, exit early.
if (Size == 0) return;
@@ -222,5 +228,3 @@ bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) {
ReplaceText(From->getLocStart(), Size, Str);
return false;
}
-
-
diff --git a/lib/Runtime/Makefile b/lib/Runtime/Makefile
index 9a3c347..580215a 100644
--- a/lib/Runtime/Makefile
+++ b/lib/Runtime/Makefile
@@ -26,6 +26,7 @@ PROJ_resources_lib := $(PROJ_resources)/lib
# Expect compiler-rt to be in llvm/projects/compiler-rt
COMPILERRT_SRC_ROOT := $(LLVM_SRC_ROOT)/projects/compiler-rt
+ifndef CLANG_NO_RUNTIME
ifeq ($(shell test -d $(COMPILERRT_SRC_ROOT) && echo OK),OK)
# Select the compiler-rt configuration to use, and install directory.
@@ -97,3 +98,4 @@ install-local:: $(RuntimeDirs:%=RuntimeLibraryInstall.%)
clean-local:: CleanRuntimeLibraries
endif
+endif
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index d1f00ca..6ded0a3 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -25,7 +25,6 @@
#include "clang/Analysis/Analyses/ReachableCode.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/Support/Casting.h"
-#include <queue>
using namespace clang;
@@ -75,7 +74,6 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
// The CFG leaves in dead things, and we don't want the dead code paths to
// confuse us, so we mark all live things first.
- std::queue<CFGBlock*> workq;
llvm::BitVector live(cfg->getNumBlockIDs());
unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(),
live);
@@ -149,7 +147,8 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
bool NoReturnEdge = false;
if (CallExpr *C = dyn_cast<CallExpr>(S)) {
- if (B.succ_begin()[0] != &cfg->getExit()) {
+ if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit())
+ == B.succ_end()) {
HasAbnormalEdge = true;
continue;
}
@@ -190,7 +189,7 @@ struct CheckFallThroughDiagnostics {
unsigned diag_NeverFallThroughOrReturn;
bool funMode;
- static CheckFallThroughDiagnostics MakeForFunction() {
+ static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) {
CheckFallThroughDiagnostics D;
D.diag_MaybeFallThrough_HasNoReturn =
diag::warn_falloff_noreturn_function;
@@ -200,8 +199,19 @@ struct CheckFallThroughDiagnostics {
diag::warn_falloff_noreturn_function;
D.diag_AlwaysFallThrough_ReturnsNonVoid =
diag::warn_falloff_nonvoid_function;
- D.diag_NeverFallThroughOrReturn =
- diag::warn_suggest_noreturn_function;
+
+ // Don't suggest that virtual functions be marked "noreturn", since they
+ // might be overridden by non-noreturn functions.
+ bool isVirtualMethod = false;
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func))
+ isVirtualMethod = Method->isVirtual();
+
+ if (!isVirtualMethod)
+ D.diag_NeverFallThroughOrReturn =
+ diag::warn_suggest_noreturn_function;
+ else
+ D.diag_NeverFallThroughOrReturn = 0;
+
D.funMode = true;
return D;
}
@@ -297,7 +307,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
CD.diag_AlwaysFallThrough_ReturnsNonVoid);
break;
case NeverFallThroughOrReturn:
- if (ReturnsVoid && !HasNoReturn)
+ if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn)
S.Diag(Compound->getLBracLoc(),
CD.diag_NeverFallThroughOrReturn);
break;
@@ -325,8 +335,7 @@ clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
void clang::sema::
AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
- const Decl *D, QualType BlockTy,
- const bool analyzeStaticInline) {
+ const Decl *D, QualType BlockTy) {
assert(BlockTy.isNull() || isa<BlockDecl>(D));
@@ -336,12 +345,14 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// don't bother trying.
// (2) The code already has problems; running the analysis just takes more
// time.
- if (S.getDiagnostics().hasErrorOccurred())
+ Diagnostic &Diags = S.getDiagnostics();
+
+ if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
return;
// Do not do any analysis for declarations in system headers if we are
// going to just ignore them.
- if (S.getDiagnostics().getSuppressSystemWarnings() &&
+ if (Diags.getSuppressSystemWarnings() &&
S.SourceMgr.isInSystemHeader(D->getLocation()))
return;
@@ -350,17 +361,6 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// we'll do the analysis at instantiation time.
if (FD->isDependentContext())
return;
-
- // Only analyze 'static inline' functions when explicitly asked.
- if (!analyzeStaticInline && FD->isInlineSpecified() &&
- FD->getStorageClass() == FunctionDecl::Static) {
- FD = FD->getCanonicalDecl();
- VisitFlag &visitFlag = VisitedFD[FD];
- if (visitFlag == Pending)
- visitFlag = Visited;
- else
- return;
- }
}
const Stmt *Body = D->getBody();
@@ -369,61 +369,16 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// Don't generate EH edges for CallExprs as we'd like to avoid the n^2
// explosion for destrutors that can result and the compile time hit.
AnalysisContext AC(D, false);
- bool performedCheck = false;
// Warning: check missing 'return'
if (P.enableCheckFallThrough) {
const CheckFallThroughDiagnostics &CD =
(isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()
- : CheckFallThroughDiagnostics::MakeForFunction());
+ : CheckFallThroughDiagnostics::MakeForFunction(D));
CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC);
- performedCheck = true;
}
// Warning: check for unreachable code
- if (P.enableCheckUnreachable) {
+ if (P.enableCheckUnreachable)
CheckUnreachable(S, AC);
- performedCheck = true;
- }
-
- // If this block or function calls a 'static inline' function,
- // we should analyze those functions as well.
- if (performedCheck) {
- // The CFG should already be constructed, so this should not
- // incur any extra cost. We might not have a CFG, however, for
- // invalid code.
- if (const CFG *cfg = AC.getCFG()) {
- // All CallExprs are block-level expressions in the CFG. This means
- // that walking the basic blocks in the CFG is more efficient
- // than walking the entire AST to find all calls.
- for (CFG::const_iterator I=cfg->begin(), E=cfg->end(); I!=E; ++I) {
- const CFGBlock *B = *I;
- for (CFGBlock::const_iterator BI=B->begin(), BE=B->end(); BI!=BE; ++BI)
- if (const CallExpr *CE = dyn_cast<CallExpr>(*BI))
- if (const DeclRefExpr *DR =
- dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenCasts()))
- if (const FunctionDecl *calleeD =
- dyn_cast<FunctionDecl>(DR->getDecl())) {
- calleeD = calleeD->getCanonicalDecl();
- if (calleeD->isInlineSpecified() &&
- calleeD->getStorageClass() == FunctionDecl::Static) {
- // Have we analyzed this static inline function before?
- VisitFlag &visitFlag = VisitedFD[calleeD];
- if (visitFlag == NotVisited) {
- // Mark the callee visited prior to analyzing it
- // so we terminate in case of recursion.
- if (calleeD->getBody()) {
- visitFlag = Visited;
- IssueWarnings(DefaultPolicy, calleeD, QualType(), true);
- }
- else {
- // Delay warnings until we encounter the definition.
- visitFlag = Pending;
- }
- }
- }
- }
- }
- }
- }
}
diff --git a/lib/Sema/AnalysisBasedWarnings.h b/lib/Sema/AnalysisBasedWarnings.h
index b5db8af..dea19ba 100644
--- a/lib/Sema/AnalysisBasedWarnings.h
+++ b/lib/Sema/AnalysisBasedWarnings.h
@@ -47,9 +47,7 @@ public:
Policy getDefaultPolicy() { return DefaultPolicy; }
- void IssueWarnings(Policy P, const Decl *D, QualType BlockTy = QualType(),
- const bool analyzeStaticInline = false);
-
+ void IssueWarnings(Policy P, const Decl *D, QualType BlockTy = QualType());
};
}} // end namespace clang::sema
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index 5483a29..0ef9a15 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -86,7 +86,7 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text)
break;
case CK_Colon:
- this->Text = ": ";
+ this->Text = ":";
break;
case CK_SemiColon:
@@ -425,7 +425,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
OS << "COMPLETION: ";
switch (Results[I].Kind) {
case Result::RK_Declaration:
- OS << Results[I].Declaration->getNameAsString() ;
+ OS << Results[I].Declaration;
if (Results[I].Hidden)
OS << " (Hidden)";
if (CodeCompletionString *CCS
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 1c761b9..0694294 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -155,8 +155,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
BuildScopeInformation(TryPart, Scopes.size()-1);
// Jump from the catch to the finally or try is not valid.
- for (ObjCAtCatchStmt *AC = AT->getCatchStmts(); AC;
- AC = AC->getNextCatchStmt()) {
+ for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) {
+ ObjCAtCatchStmt *AC = AT->getCatchStmt(I);
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_objc_catch,
AC->getAtCatchLoc()));
diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h
index f310c25..0961299 100644
--- a/lib/Sema/Lookup.h
+++ b/lib/Sema/Lookup.h
@@ -124,7 +124,6 @@ public:
};
typedef UnresolvedSetImpl::iterator iterator;
- typedef bool (*ResultFilter)(NamedDecl*, unsigned IDNS);
LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc,
Sema::LookupNameKind LookupKind,
@@ -136,7 +135,6 @@ public:
Name(Name),
NameLoc(NameLoc),
LookupKind(LookupKind),
- IsAcceptableFn(0),
IDNS(0),
Redecl(Redecl != Sema::NotForRedeclaration),
HideTags(true),
@@ -156,7 +154,6 @@ public:
Name(Other.Name),
NameLoc(Other.NameLoc),
LookupKind(Other.LookupKind),
- IsAcceptableFn(Other.IsAcceptableFn),
IDNS(Other.IDNS),
Redecl(Other.Redecl),
HideTags(Other.HideTags),
@@ -242,8 +239,7 @@ public:
/// \brief Tests whether the given declaration is acceptable.
bool isAcceptableDecl(NamedDecl *D) const {
- assert(IsAcceptableFn);
- return IsAcceptableFn(D, IDNS);
+ return D->isInIdentifierNamespace(IDNS);
}
/// \brief Returns the identifier namespace mask for this lookup.
@@ -282,6 +278,18 @@ public:
NamingClass = Record;
}
+ /// \brief Returns the base object type associated with this lookup;
+ /// important for [class.protected]. Most lookups do not have an
+ /// associated base object.
+ QualType getBaseObjectType() const {
+ return BaseObjectType;
+ }
+
+ /// \brief Sets the base object type for this lookup.
+ void setBaseObjectType(QualType T) {
+ BaseObjectType = T;
+ }
+
/// \brief Add a declaration to these results with its natural access.
/// Does not test the acceptance criteria.
void addDecl(NamedDecl *D) {
@@ -331,6 +339,11 @@ public:
} else {
ResultKind = Found;
resolveKind();
+
+ if (Paths && (ResultKind != Ambiguous)) {
+ deletePaths(Paths);
+ Paths = 0;
+ }
}
}
@@ -550,6 +563,7 @@ private:
UnresolvedSet<8> Decls;
CXXBasePaths *Paths;
CXXRecordDecl *NamingClass;
+ QualType BaseObjectType;
// Parameters.
Sema &SemaRef;
@@ -557,7 +571,6 @@ private:
SourceLocation NameLoc;
SourceRange NameContextRange;
Sema::LookupNameKind LookupKind;
- ResultFilter IsAcceptableFn; // set by configure()
unsigned IDNS; // set by configure()
bool Redecl;
diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp
index 7cd3989..bb0bd9e 100644
--- a/lib/Sema/ParseAST.cpp
+++ b/lib/Sema/ParseAST.cpp
@@ -24,6 +24,26 @@
using namespace clang;
+static void DumpRecordLayouts(ASTContext &C) {
+ for (ASTContext::type_iterator I = C.types_begin(), E = C.types_end();
+ I != E; ++I) {
+ const RecordType *RT = dyn_cast<RecordType>(*I);
+ if (!RT)
+ continue;
+
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD || RD->isImplicit() || RD->isDependentType() ||
+ RD->isInvalidDecl() || !RD->getDefinition())
+ continue;
+
+ // FIXME: Do we really need to hard code this?
+ if (RD->getQualifiedNameAsString() == "__va_list_tag")
+ continue;
+
+ C.DumpRecordLayout(RD, llvm::errs());
+ }
+}
+
//===----------------------------------------------------------------------===//
// Public interface to the file
//===----------------------------------------------------------------------===//
@@ -44,8 +64,7 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit, CompletionConsumer);
Parser P(PP, S);
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
// Initialize the parser.
P.Initialize();
@@ -82,6 +101,10 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
E = S.WeakTopLevelDecls().end(); I != E; ++I)
Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
+ // Dump record layouts, if requested.
+ if (PP.getLangOptions().DumpRecordLayouts)
+ DumpRecordLayouts(Ctx);
+
Consumer->HandleTranslationUnit(Ctx);
if (ExternalSemaSource *ESS =
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index ccfbe1e..755af84 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -158,7 +158,8 @@ Sema::~Sema() {
/// If there is already an implicit cast, merge into the existing one.
/// If isLvalue, the result of the cast is an lvalue.
void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,
- CastExpr::CastKind Kind, bool isLvalue) {
+ CastExpr::CastKind Kind,
+ bool isLvalue, CXXBaseSpecifierArray BasePath) {
QualType ExprTy = Context.getCanonicalType(Expr->getType());
QualType TypeTy = Context.getCanonicalType(Ty);
@@ -177,14 +178,14 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,
CheckImplicitConversion(Expr, Ty);
if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
- if (ImpCast->getCastKind() == Kind) {
+ if (ImpCast->getCastKind() == Kind && BasePath.empty()) {
ImpCast->setType(Ty);
ImpCast->setLvalueCast(isLvalue);
return;
}
}
- Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, isLvalue);
+ Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, BasePath, isLvalue);
}
void Sema::DeleteExpr(ExprTy *E) {
@@ -197,14 +198,7 @@ void Sema::DeleteStmt(StmtTy *S) {
/// ActOnEndOfTranslationUnit - This is called at the very end of the
/// translation unit when EOF is reached and all but the top-level scope is
/// popped.
-void Sema::ActOnEndOfTranslationUnit() {
-
- // Remove functions that turned out to be used.
- UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(),
- UnusedStaticFuncs.end(),
- std::mem_fun(&FunctionDecl::isUsed)),
- UnusedStaticFuncs.end());
-
+void Sema::ActOnEndOfTranslationUnit() {
while (1) {
// C++: Perform implicit template instantiations.
//
@@ -225,6 +219,12 @@ void Sema::ActOnEndOfTranslationUnit() {
break;
}
+ // Remove functions that turned out to be used.
+ UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(),
+ UnusedStaticFuncs.end(),
+ std::mem_fun(&FunctionDecl::isUsed)),
+ UnusedStaticFuncs.end());
+
// Check for #pragma weak identifiers that were never declared
// FIXME: This will cause diagnostics to be emitted in a non-determinstic
// order! Iterating over a densemap like this is bad.
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 0766b1e..f146c85 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -25,6 +25,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/FullExpr.h"
#include "clang/Parse/Action.h"
#include "clang/Sema/SemaDiagnostic.h"
@@ -108,33 +109,33 @@ namespace clang {
class TargetAttributesSema;
class ADLResult;
-/// \brief Retains information about a function, method, or block that is
+/// \brief Retains information about a function, method, or block that is
/// currently being parsed.
struct FunctionScopeInfo {
/// \brief Whether this scope information structure defined information for
/// a block.
bool IsBlockInfo;
-
- /// \brief Set true when a function, method contains a VLA or ObjC try block,
+
+ /// \brief Set true when a function, method contains a VLA or ObjC try block,
/// which introduce scopes that need to be checked for goto conditions. If a
/// function does not contain this, then it need not have the jump checker run on it.
bool NeedsScopeChecking;
-
+
/// \brief The number of errors that had occurred before starting this
/// function or block.
unsigned NumErrorsAtStartOfFunction;
-
+
/// LabelMap - This is a mapping from label identifiers to the LabelStmt for
/// it (which acts like the label decl in some ways). Forward referenced
/// labels have a LabelStmt created for them with a null location & SubStmt.
llvm::DenseMap<IdentifierInfo*, LabelStmt*> LabelMap;
-
+
/// SwitchStack - This is the current set of active switch statements in the
/// block.
- llvm::SmallVector<SwitchStmt*, 8> SwitchStack;
-
- FunctionScopeInfo(unsigned NumErrors)
- : IsBlockInfo(false), NeedsScopeChecking(false),
+ llvm::SmallVector<SwitchStmt*, 8> SwitchStack;
+
+ FunctionScopeInfo(unsigned NumErrors)
+ : IsBlockInfo(false), NeedsScopeChecking(false),
NumErrorsAtStartOfFunction(NumErrors) { }
virtual ~FunctionScopeInfo();
@@ -142,11 +143,11 @@ struct FunctionScopeInfo {
/// \brief Clear out the information in this function scope, making it
/// suitable for reuse.
void Clear(unsigned NumErrors);
-
- static bool classof(const FunctionScopeInfo *FSI) { return true; }
+
+ static bool classof(const FunctionScopeInfo *FSI) { return true; }
};
-
-
+
+
/// \brief Retains information about a block that is currently being parsed.
struct BlockScopeInfo : FunctionScopeInfo {
llvm::SmallVector<ParmVarDecl*, 8> Params;
@@ -164,11 +165,11 @@ struct BlockScopeInfo : FunctionScopeInfo {
/// return types, if any, in the block body.
QualType ReturnType;
- BlockScopeInfo(unsigned NumErrors, Scope *BlockScope, BlockDecl *Block)
- : FunctionScopeInfo(NumErrors), hasPrototype(false), isVariadic(false),
- hasBlockDeclRefExprs(false), TheDecl(Block), TheScope(BlockScope)
+ BlockScopeInfo(unsigned NumErrors, Scope *BlockScope, BlockDecl *Block)
+ : FunctionScopeInfo(NumErrors), hasPrototype(false), isVariadic(false),
+ hasBlockDeclRefExprs(false), TheDecl(Block), TheScope(BlockScope)
{
- IsBlockInfo = true;
+ IsBlockInfo = true;
}
virtual ~BlockScopeInfo();
@@ -233,6 +234,30 @@ public:
/// CurContext - This is the current declaration context of parsing.
DeclContext *CurContext;
+ /// A RAII object to temporarily push a declaration context.
+ class ContextRAII {
+ private:
+ Sema &S;
+ DeclContext *SavedContext;
+
+ public:
+ ContextRAII(Sema &S, DeclContext *ContextToPush)
+ : S(S), SavedContext(S.CurContext) {
+ assert(ContextToPush && "pushing null context");
+ S.CurContext = ContextToPush;
+ }
+
+ void pop() {
+ if (!SavedContext) return;
+ S.CurContext = SavedContext;
+ SavedContext = 0;
+ }
+
+ ~ContextRAII() {
+ pop();
+ }
+ };
+
/// PackContext - Manages the stack for #pragma pack. An alignment
/// of 0 indicates default alignment.
void *PackContext; // Really a "PragmaPackStack*"
@@ -240,14 +265,14 @@ public:
/// \brief Stack containing information about each of the nested function,
/// block, and method scopes that are currently active.
llvm::SmallVector<FunctionScopeInfo *, 4> FunctionScopes;
-
+
/// \brief Cached function scope object used for the top function scope
/// and when there is no function scope (in error cases).
///
- /// This should never be accessed directly; rather, it's address will be
+ /// This should never be accessed directly; rather, it's address will be
/// pushed into \c FunctionScopes when we want to re-use it.
FunctionScopeInfo TopFunctionScope;
-
+
/// ExprTemporaries - This is the stack of temporaries that are created by
/// the current full expression.
llvm::SmallVector<CXXTemporary*, 8> ExprTemporaries;
@@ -312,26 +337,17 @@ public:
bool isMemberAccess() const { return IsMember; }
- AccessedEntity(ASTContext &Context,
- MemberNonce _,
- CXXRecordDecl *NamingClass,
- AccessSpecifier Access,
- NamedDecl *Target)
- : Access(Access), IsMember(true),
- Target(Target), NamingClass(NamingClass),
- Diag(0, Context.getDiagAllocator()) {
- }
-
- AccessedEntity(ASTContext &Context,
+ AccessedEntity(ASTContext &Context,
MemberNonce _,
CXXRecordDecl *NamingClass,
- DeclAccessPair FoundDecl)
- : Access(FoundDecl.getAccess()), IsMember(true),
+ DeclAccessPair FoundDecl,
+ QualType BaseObjectType)
+ : Access(FoundDecl.getAccess()), IsMember(true),
Target(FoundDecl.getDecl()), NamingClass(NamingClass),
- Diag(0, Context.getDiagAllocator()) {
+ BaseObjectType(BaseObjectType), Diag(0, Context.getDiagAllocator()) {
}
- AccessedEntity(ASTContext &Context,
+ AccessedEntity(ASTContext &Context,
BaseNonce _,
CXXRecordDecl *BaseClass,
CXXRecordDecl *DerivedClass,
@@ -353,6 +369,10 @@ public:
CXXRecordDecl *getBaseClass() const { return cast<CXXRecordDecl>(Target); }
CXXRecordDecl *getDerivedClass() const { return NamingClass; }
+ /// Retrieves the base object type, important when accessing
+ /// an instance member.
+ QualType getBaseObjectType() const { return BaseObjectType; }
+
/// Sets a diagnostic to be performed. The diagnostic is given
/// four (additional) arguments:
/// %0 - 0 if the entity was private, 1 if protected
@@ -377,7 +397,8 @@ public:
unsigned Access : 2;
bool IsMember;
NamedDecl *Target;
- CXXRecordDecl *NamingClass;
+ CXXRecordDecl *NamingClass;
+ QualType BaseObjectType;
PartialDiagnostic Diag;
};
@@ -484,14 +505,14 @@ public:
/// \brief The C++ "std::bad_alloc" class, which is defined by the C++
/// standard library.
CXXRecordDecl *StdBadAlloc;
-
+
/// A flag to remember whether the implicit forms of operator new and delete
/// have been declared.
bool GlobalNewDeleteDeclared;
/// \brief The set of declarations that have been referenced within
/// a potentially evaluated expression.
- typedef std::vector<std::pair<SourceLocation, Decl *> >
+ typedef std::vector<std::pair<SourceLocation, Decl *> >
PotentiallyReferencedDecls;
/// \brief A set of diagnostics that may be emitted.
@@ -522,8 +543,8 @@ public:
PotentiallyEmittedDiagnostics *PotentiallyDiagnosed;
ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
- unsigned NumTemporaries)
- : Context(Context), NumTemporaries(NumTemporaries),
+ unsigned NumTemporaries)
+ : Context(Context), NumTemporaries(NumTemporaries),
PotentiallyReferenced(0), PotentiallyDiagnosed(0) { }
void addReferencedDecl(SourceLocation Loc, Decl *Decl) {
@@ -618,11 +639,11 @@ public:
/// \brief Emit a partial diagnostic.
SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD);
- /// \brief Build a partial diagnostic.
+ /// \brief Build a partial diagnostic.
PartialDiagnostic PDiag(unsigned DiagID = 0) {
return PartialDiagnostic(DiagID, Context.getDiagAllocator());
}
-
+
virtual void DeleteExpr(ExprTy *E);
virtual void DeleteStmt(StmtTy *S);
@@ -646,13 +667,13 @@ public:
void PushFunctionScope();
void PushBlockScope(Scope *BlockScope, BlockDecl *Block);
void PopFunctionOrBlockScope();
-
+
/// getLabelMap() - Return the current label map. If we're in a block, we
/// return it.
llvm::DenseMap<IdentifierInfo*, LabelStmt*> &getLabelMap() {
if (FunctionScopes.empty())
return TopFunctionScope.LabelMap;
-
+
return FunctionScopes.back()->LabelMap;
}
@@ -661,24 +682,24 @@ public:
llvm::SmallVector<SwitchStmt*,8> &getSwitchStack() {
if (FunctionScopes.empty())
return TopFunctionScope.SwitchStack;
-
+
return FunctionScopes.back()->SwitchStack;
}
- /// \brief Determine whether the current function or block needs scope
+ /// \brief Determine whether the current function or block needs scope
/// checking.
bool &FunctionNeedsScopeChecking() {
if (FunctionScopes.empty())
return TopFunctionScope.NeedsScopeChecking;
-
+
return FunctionScopes.back()->NeedsScopeChecking;
}
-
+
bool hasAnyErrorsInThisFunction() const;
-
+
/// \brief Retrieve the current block, if any.
BlockScopeInfo *getCurBlock();
-
+
/// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls
llvm::SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
@@ -708,7 +729,8 @@ public:
QualType GetTypeForDeclarator(Declarator &D, Scope *S,
TypeSourceInfo **TInfo = 0,
TagDecl **OwnedDecl = 0);
- TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T);
+ TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
+ TypeSourceInfo *ReturnTypeInfo);
/// \brief Create a LocInfoType to hold the given QualType and TypeSourceInfo.
QualType CreateLocInfoType(QualType T, TypeSourceInfo *TInfo);
DeclarationName GetNameForDeclarator(Declarator &D);
@@ -745,7 +767,7 @@ public:
const PartialDiagnostic &PD);
bool RequireCompleteType(SourceLocation Loc, QualType T,
unsigned DiagID);
-
+
QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T);
QualType BuildTypeofExprType(Expr *E);
@@ -762,16 +784,16 @@ public:
DeclGroupPtrTy ConvertDeclToDeclGroup(DeclPtrTy Ptr);
virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
- Scope *S, const CXXScopeSpec *SS,
+ Scope *S, CXXScopeSpec *SS,
bool isClassName = false,
TypeTy *ObjectType = 0);
virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S);
- virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II,
+ virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II,
SourceLocation IILoc,
Scope *S,
- const CXXScopeSpec *SS,
+ CXXScopeSpec *SS,
TypeTy *&SuggestedType);
-
+
virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) {
return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false);
}
@@ -809,7 +831,12 @@ public:
bool &OverloadableAttrRequired);
void CheckMain(FunctionDecl *FD);
virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D);
- virtual void ActOnObjCCatchParam(DeclPtrTy D);
+ ParmVarDecl *CheckParameter(DeclContext *DC,
+ TypeSourceInfo *TSInfo, QualType T,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ VarDecl::StorageClass StorageClass,
+ VarDecl::StorageClass StorageClassAsWritten);
virtual void ActOnParamDefaultArgument(DeclPtrTy param,
SourceLocation EqualLoc,
ExprArg defarg);
@@ -847,11 +874,21 @@ public:
/// ParmVarDecl pointers.
template<typename InputIterator>
void DiagnoseUnusedParameters(InputIterator Param, InputIterator ParamEnd) {
+ if (Diags.getDiagnosticLevel(diag::warn_unused_parameter) ==
+ Diagnostic::Ignored)
+ return;
+
+ // Don't diagnose unused-parameter errors in template instantiations; we
+ // will already have done so in the template itself.
+ if (!ActiveTemplateInstantiations.empty())
+ return;
+
for (; Param != ParamEnd; ++Param) {
if (!(*Param)->isUsed() && (*Param)->getDeclName() &&
- !(*Param)->template hasAttr<UnusedAttr>())
+ !(*Param)->template hasAttr<UnusedAttr>()) {
Diag((*Param)->getLocation(), diag::warn_unused_parameter)
<< (*Param)->getDeclName();
+ }
}
}
@@ -877,7 +914,7 @@ public:
const IdentifierInfo &Name);
virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
- SourceLocation KWLoc, const CXXScopeSpec &SS,
+ SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
MultiTemplateParamsArg TemplateParameterLists,
@@ -911,12 +948,14 @@ public:
Declarator *D = 0);
enum CXXSpecialMember {
- CXXDefaultConstructor = 0,
+ CXXInvalid = -1,
+ CXXConstructor = 0,
CXXCopyConstructor = 1,
CXXCopyAssignment = 2,
CXXDestructor = 3
};
void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem);
+ CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD);
virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart,
DeclPtrTy IntfDecl,
@@ -1034,7 +1073,7 @@ public:
AA_Sending,
AA_Casting
};
-
+
/// C++ Overloading.
enum OverloadKind {
/// This is a legitimate overload: the existing declarations are
@@ -1058,9 +1097,7 @@ public:
TryImplicitConversion(Expr* From, QualType ToType,
bool SuppressUserConversions,
bool AllowExplicit,
- bool ForceRValue,
- bool InOverloadResolution,
- bool UserCast = false);
+ bool InOverloadResolution);
bool IsStandardConversion(Expr *From, QualType ToType,
bool InOverloadResolution,
StandardConversionSequence& SCS);
@@ -1072,24 +1109,27 @@ public:
QualType& ConvertedType, bool &IncompatibleObjC);
bool isObjCPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType, bool &IncompatibleObjC);
+ bool FunctionArgTypesAreEqual (FunctionProtoType* OldType,
+ FunctionProtoType* NewType);
+
bool CheckPointerConversion(Expr *From, QualType ToType,
CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray& BasePath,
bool IgnoreBaseAccess);
bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType,
bool InOverloadResolution,
QualType &ConvertedType);
bool CheckMemberPointerConversion(Expr *From, QualType ToType,
CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath,
bool IgnoreBaseAccess);
bool IsQualificationConversion(QualType FromType, QualType ToType);
OverloadingResult IsUserDefinedConversion(Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
OverloadCandidateSet& Conversions,
- bool AllowConversionFunctions,
- bool AllowExplicit, bool ForceRValue,
- bool UserCast = false);
+ bool AllowExplicit);
bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
-
+
ImplicitConversionSequence::CompareKind
CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
@@ -1107,18 +1147,13 @@ public:
CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
- ImplicitConversionSequence
- TryCopyInitialization(Expr* From, QualType ToType,
- bool SuppressUserConversions, bool ForceRValue,
- bool InOverloadResolution);
-
OwningExprResult PerformCopyInitialization(const InitializedEntity &Entity,
SourceLocation EqualLoc,
OwningExprResult Init);
ImplicitConversionSequence
TryObjectArgumentInitialization(QualType FromType, CXXMethodDecl *Method,
CXXRecordDecl *ActingContext);
- bool PerformObjectArgumentInitialization(Expr *&From,
+ bool PerformObjectArgumentInitialization(Expr *&From,
NestedNameSpecifier *Qualifier,
NamedDecl *FoundDecl,
CXXMethodDecl *Method);
@@ -1126,7 +1161,7 @@ public:
ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From);
bool PerformContextuallyConvertToBool(Expr *&From);
- bool PerformObjectMemberConversion(Expr *&From,
+ bool PerformObjectMemberConversion(Expr *&From,
NestedNameSpecifier *Qualifier,
NamedDecl *FoundDecl,
NamedDecl *Member);
@@ -1146,7 +1181,6 @@ public:
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
- bool ForceRValue = false,
bool PartialOverloading = false);
void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
Expr **Args, unsigned NumArgs,
@@ -1156,15 +1190,13 @@ public:
QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversion = false,
- bool ForceRValue = false);
+ bool SuppressUserConversion = false);
void AddMethodCandidate(CXXMethodDecl *Method,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions = false,
- bool ForceRValue = false);
+ bool SuppressUserConversions = false);
void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
@@ -1172,15 +1204,13 @@ public:
QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions = false,
- bool ForceRValue = false);
+ bool SuppressUserConversions = false);
void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
DeclAccessPair FoundDecl,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions = false,
- bool ForceRValue = false);
+ bool SuppressUserConversions = false);
void AddConversionCandidate(CXXConversionDecl *Conversion,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
@@ -1197,11 +1227,6 @@ public:
const FunctionProtoType *Proto,
QualType ObjectTy, Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet);
- void AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
- SourceLocation OpLoc,
- Expr **Args, unsigned NumArgs,
- OverloadCandidateSet& CandidateSet,
- SourceRange OpRange = SourceRange());
void AddMemberOperatorCandidates(OverloadedOperatorKind Op,
SourceLocation OpLoc,
Expr **Args, unsigned NumArgs,
@@ -1254,18 +1279,18 @@ public:
FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From);
Expr *FixOverloadedFunctionReference(Expr *E,
- NamedDecl *FoundDecl,
+ DeclAccessPair FoundDecl,
FunctionDecl *Fn);
- OwningExprResult FixOverloadedFunctionReference(OwningExprResult,
- NamedDecl *FoundDecl,
+ OwningExprResult FixOverloadedFunctionReference(OwningExprResult,
+ DeclAccessPair FoundDecl,
FunctionDecl *Fn);
void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading = false);
-
- OwningExprResult BuildOverloadedCallExpr(Expr *Fn,
+
+ OwningExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
@@ -1305,7 +1330,7 @@ public:
/// that best represents the call.
bool CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
CallExpr *CE, FunctionDecl *FD);
-
+
/// Helpers for dealing with blocks and functions.
bool CheckParmsForFunctionDef(FunctionDecl *FD);
void CheckCXXDefaultArguments(FunctionDecl *FD);
@@ -1374,9 +1399,7 @@ public:
/// C99 6.2.2p4-5 and C++ [basic.link]p6.
LookupRedeclarationWithLinkage,
/// Look up the name of an Objective-C protocol.
- LookupObjCProtocolName,
- /// Look up the name of an Objective-C implementation
- LookupObjCImplementationName
+ LookupObjCProtocolName
};
/// \brief Specifies whether (or how) name lookup is being performed for a
@@ -1400,6 +1423,7 @@ public:
/// It is preferable to use the elaborated form and explicitly handle
/// ambiguity and overloaded.
NamedDecl *LookupSingleName(Scope *S, DeclarationName Name,
+ SourceLocation Loc,
LookupNameKind NameKind,
RedeclarationKind Redecl
= NotForRedeclaration);
@@ -1407,15 +1431,15 @@ public:
bool AllowBuiltinCreation = false);
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
bool InUnqualifiedLookup = false);
- bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
+ bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
bool AllowBuiltinCreation = false,
bool EnteringContext = false);
- ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II);
+ ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc);
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
QualType T1, QualType T2,
UnresolvedSetImpl &Functions);
-
+
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
Expr **Args, unsigned NumArgs,
ADLResult &Functions);
@@ -1425,10 +1449,34 @@ public:
void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
VisibleDeclConsumer &Consumer);
- bool CorrectTypo(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
- DeclContext *MemberContext = 0,
- bool EnteringContext = false,
- const ObjCObjectPointerType *OPT = 0);
+ /// \brief The context in which typo-correction occurs.
+ ///
+ /// The typo-correction context affects which keywords (if any) are
+ /// considered when trying to correct for typos.
+ enum CorrectTypoContext {
+ /// \brief An unknown context, where any keyword might be valid.
+ CTC_Unknown,
+ /// \brief A context where no keywords are used (e.g. we expect an actual
+ /// name).
+ CTC_NoKeywords,
+ /// \brief A context where we're correcting a type name.
+ CTC_Type,
+ /// \brief An expression context.
+ CTC_Expression,
+ /// \brief A type cast, or anything else that can be followed by a '<'.
+ CTC_CXXCasts,
+ /// \brief A member lookup context.
+ CTC_MemberLookup,
+ /// \brief The receiver of an Objective-C message send within an
+ /// Objective-C method where 'super' is a valid keyword.
+ CTC_ObjCMessageReceiver
+ };
+
+ DeclarationName CorrectTypo(LookupResult &R, Scope *S, CXXScopeSpec *SS,
+ DeclContext *MemberContext = 0,
+ bool EnteringContext = false,
+ CorrectTypoContext CTC = CTC_Unknown,
+ const ObjCObjectPointerType *OPT = 0);
void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
AssociatedNamespaceSet &AssociatedNamespaces,
@@ -1438,7 +1486,8 @@ public:
//@}
ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id,
- SourceLocation RecoverLoc = SourceLocation());
+ SourceLocation IdLoc,
+ bool TypoCorrection = false);
NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
Scope *S, bool ForRedeclaration,
SourceLocation Loc);
@@ -1482,7 +1531,7 @@ public:
void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
ObjCContainerDecl* IDecl,
bool IncompleteImpl = false);
-
+
/// DiagnoseUnimplementedProperties - This routine warns on those properties
/// which must be implemented by this implementation.
void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
@@ -1494,13 +1543,19 @@ public:
void CollectImmediateProperties(ObjCContainerDecl *CDecl,
llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap);
+ /// ProtocolConformsToSuperClass - Returns true if class has a super class
+ /// and it, or its nested super class conforms to the protocol.
+ bool ProtocolConformsToSuperClass(const ObjCInterfaceDecl *IDecl,
+ const ObjCProtocolDecl *PDecl);
+ /// ProtocolConformsToProtocol - Returns true if 2nd Protocol (PDecl) is
+ /// qualified by the 1st.
+ bool ProtocolConformsToProtocol(const ObjCProtocolDecl *NestedProtocol,
+ const ObjCProtocolDecl *PDecl);
+
/// LookupPropertyDecl - Looks up a property in the current class and all
/// its protocols.
- ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl,
+ ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl,
IdentifierInfo *II);
-
- ObjCIvarDecl *SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl,
- IdentifierInfo *NameII);
/// Called by ActOnProperty to handle @property declarations in
//// class extensions.
@@ -1572,6 +1627,11 @@ public:
/// AddFactoryMethodToGlobalPool - Same as above, but for factory methods.
void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method);
+
+ /// CollectIvarsToConstructOrDestruct - Collect those ivars which require
+ /// initialization.
+ void CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI,
+ llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
//===--------------------------------------------------------------------===//
// Statement Parsing Callbacks: SemaStmt.cpp.
public:
@@ -1601,7 +1661,7 @@ public:
FullExprArg CondVal, DeclPtrTy CondVar,
StmtArg ThenVal,
SourceLocation ElseLoc, StmtArg ElseVal);
- virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond,
+ virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond,
DeclPtrTy CondVar);
virtual void ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch,
StmtArg Body);
@@ -1619,7 +1679,7 @@ public:
SourceLocation LParenLoc,
StmtArg First, FullExprArg Second,
DeclPtrTy SecondVar,
- FullExprArg Third,
+ FullExprArg Third,
SourceLocation RParenLoc,
StmtArg Body);
virtual OwningStmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc,
@@ -1656,18 +1716,27 @@ public:
SourceLocation RParenLoc,
bool MSAsm = false);
+
+ VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ bool Invalid = false);
+
+ virtual DeclPtrTy ActOnObjCExceptionDecl(Scope *S, Declarator &D);
+
virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
SourceLocation RParen,
- DeclPtrTy Parm, StmtArg Body,
- StmtArg CatchList);
+ DeclPtrTy Parm, StmtArg Body);
virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc,
StmtArg Body);
virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
StmtArg Try,
- StmtArg Catch, StmtArg Finally);
+ MultiStmtArg Catch,
+ StmtArg Finally);
+ virtual OwningStmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc,
+ ExprArg Throw);
virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
ExprArg Throw,
Scope *CurScope);
@@ -1717,17 +1786,17 @@ public:
void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
bool DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD);
-
+
// Primary Expressions.
virtual SourceRange getExprRange(ExprTy *E) const;
virtual OwningExprResult ActOnIdExpression(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
bool HasTrailingLParen,
bool IsAddressOfOperand);
- bool DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, LookupResult &R);
+ bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R);
OwningExprResult LookupInObjCMethod(LookupResult &R,
Scope *S,
@@ -1739,7 +1808,7 @@ public:
SourceLocation NameLoc,
bool isAddressOfOperand,
const TemplateArgumentListInfo *TemplateArgs);
-
+
OwningExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty,
SourceLocation Loc,
const CXXScopeSpec *SS = 0);
@@ -1761,7 +1830,7 @@ public:
const LookupResult &R,
bool HasTrailingLParen);
- OwningExprResult BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS,
+ OwningExprResult BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
DeclarationName Name,
SourceLocation NameLoc);
OwningExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
@@ -1831,7 +1900,7 @@ public:
QualType BaseType,
SourceLocation OpLoc,
bool IsArrow,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
DeclarationName Name,
SourceLocation NameLoc,
@@ -1843,11 +1912,12 @@ public:
const CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs);
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool SuppressQualifierCheck = false);
OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base,
bool &IsArrow, SourceLocation OpLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
DeclPtrTy ObjCImpDecl);
bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType,
@@ -1867,11 +1937,11 @@ public:
virtual OwningExprResult ActOnMemberAccessExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Member,
DeclPtrTy ObjCImpDecl,
bool HasTrailingLParen);
-
+
virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl);
bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
FunctionDecl *FDecl,
@@ -1954,6 +2024,11 @@ public:
SourceLocation RPLoc); // "({..})"
/// __builtin_offsetof(type, a.b[123][456].c)
+ OwningExprResult BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
+ TypeSourceInfo *TInfo,
+ OffsetOfComponent *CompPtr,
+ unsigned NumComponents,
+ SourceLocation RParenLoc);
virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S,
SourceLocation BuiltinLoc,
SourceLocation TypeLoc,
@@ -2011,7 +2086,7 @@ public:
virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope,
SourceLocation UsingLoc,
SourceLocation NamespcLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *NamespcName,
AttributeList *AttrList);
@@ -2022,7 +2097,7 @@ public:
SourceLocation NamespaceLoc,
SourceLocation AliasLoc,
IdentifierInfo *Alias,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *Ident);
@@ -2043,7 +2118,7 @@ public:
NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
DeclarationName Name,
AttributeList *AttrList,
@@ -2055,7 +2130,7 @@ public:
AccessSpecifier AS,
bool HasUsingKeyword,
SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
bool IsTypeName,
@@ -2078,28 +2153,21 @@ public:
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
/// including handling of its default argument expressions.
- OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc,
- QualType DeclInitType,
- CXXConstructorDecl *Constructor,
- MultiExprArg Exprs,
- bool RequiresZeroInit = false,
- bool BaseInitialization = false);
+ OwningExprResult
+ BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
+ CXXConstructorDecl *Constructor, MultiExprArg Exprs,
+ bool RequiresZeroInit = false,
+ CXXConstructExpr::ConstructionKind ConstructKind =
+ CXXConstructExpr::CK_Complete);
// FIXME: Can re remove this and have the above BuildCXXConstructExpr check if
// the constructor can be elidable?
- OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc,
- QualType DeclInitType,
- CXXConstructorDecl *Constructor,
- bool Elidable,
- MultiExprArg Exprs,
- bool RequiresZeroInit = false,
- bool BaseInitialization = false);
-
- OwningExprResult BuildCXXCastArgument(SourceLocation CastLoc,
- QualType Ty,
- CastExpr::CastKind Kind,
- CXXMethodDecl *Method,
- ExprArg Arg);
+ OwningExprResult
+ BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
+ CXXConstructorDecl *Constructor, bool Elidable,
+ MultiExprArg Exprs, bool RequiresZeroInit = false,
+ CXXConstructExpr::ConstructionKind ConstructKind =
+ CXXConstructExpr::CK_Complete);
/// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating
/// the default expr if needed.
@@ -2127,36 +2195,23 @@ public:
CXXConstructorDecl *Constructor,
unsigned TypeQuals);
- /// DefineImplicitOverloadedAssign - Checks for feasibility of
- /// defining implicit this overloaded assignment operator.
- void DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
- CXXMethodDecl *MethodDecl);
-
- /// getAssignOperatorMethod - Returns the default copy assignmment operator
- /// for the class.
- CXXMethodDecl *getAssignOperatorMethod(SourceLocation CurrentLocation,
- ParmVarDecl *Decl,
- CXXRecordDecl *ClassDecl);
+ /// \brief Defined and implicitly-declared copy assignment operator.
+ void DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
+ CXXMethodDecl *MethodDecl);
/// MaybeBindToTemporary - If the passed in expression has a record type with
/// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise
/// it simply returns the passed in expression.
OwningExprResult MaybeBindToTemporary(Expr *E);
- CXXConstructorDecl *
- TryInitializationByConstructor(QualType ClassType,
- Expr **Args, unsigned NumArgs,
- SourceLocation Loc,
- InitializationKind Kind);
-
bool CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
- SourceLocation Loc,
+ SourceLocation Loc,
ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs);
-
+
virtual TypeTy *getDestructorName(SourceLocation TildeLoc,
IdentifierInfo &II, SourceLocation NameLoc,
- Scope *S, const CXXScopeSpec &SS,
+ Scope *S, CXXScopeSpec &SS,
TypeTy *ObjectType,
bool EnteringContext);
@@ -2177,6 +2232,15 @@ public:
SourceRange AngleBrackets,
SourceRange Parens);
+ OwningExprResult BuildCXXTypeId(QualType TypeInfoType,
+ SourceLocation TypeidLoc,
+ TypeSourceInfo *Operand,
+ SourceLocation RParenLoc);
+ OwningExprResult BuildCXXTypeId(QualType TypeInfoType,
+ SourceLocation TypeidLoc,
+ ExprArg Operand,
+ SourceLocation RParenLoc);
+
/// ActOnCXXTypeid - Parse typeid( something ).
virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc,
SourceLocation LParenLoc, bool isType,
@@ -2247,7 +2311,7 @@ public:
QualType Argument,
bool addMallocAttr = false);
- bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
+ bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name, FunctionDecl* &Operator);
/// ActOnCXXDelete - Parsed a C++ 'delete' expression
@@ -2258,7 +2322,7 @@ public:
virtual DeclResult ActOnCXXConditionDeclaration(Scope *S,
Declarator &D);
OwningExprResult CheckConditionVariable(VarDecl *ConditionVar);
-
+
/// ActOnUnaryTypeTrait - Parsed one of the unary type trait support
/// pseudo-functions.
virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
@@ -2276,7 +2340,7 @@ public:
OwningExprResult DiagnoseDtorReference(SourceLocation NameLoc,
ExprArg MemExpr);
-
+
OwningExprResult BuildPseudoDestructorExpr(ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
@@ -2286,27 +2350,28 @@ public:
SourceLocation TildeLoc,
PseudoDestructorTypeStorage DestroyedType,
bool HasTrailingLParen);
-
+
virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &FirstTypeName,
SourceLocation CCLoc,
SourceLocation TildeLoc,
UnqualifiedId &SecondTypeName,
bool HasTrailingLParen);
-
+
/// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is
/// non-empty, will create a new CXXExprWithTemporaries expression.
/// Otherwise, just returs the passed in expression.
Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr);
OwningExprResult MaybeCreateCXXExprWithTemporaries(OwningExprResult SubExpr);
FullExpr CreateFullExpr(Expr *SubExpr);
-
+
virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr);
- bool RequireCompleteDeclContext(const CXXScopeSpec &SS);
+ // Marks SS invalid if it represents an incomplete type.
+ bool RequireCompleteDeclContext(CXXScopeSpec &SS, DeclContext *DC);
DeclContext *computeDeclContext(QualType T);
DeclContext *computeDeclContext(const CXXScopeSpec &SS,
@@ -2323,13 +2388,13 @@ public:
bool isAcceptableNestedNameSpecifier(NamedDecl *SD);
NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
- virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
+ virtual bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS,
SourceLocation IdLoc,
IdentifierInfo &II,
TypeTy *ObjectType);
-
+
CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
IdentifierInfo &II,
@@ -2339,7 +2404,7 @@ public:
bool ErrorRecoveryLookup);
virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
IdentifierInfo &II,
@@ -2347,11 +2412,11 @@ public:
bool EnteringContext);
virtual bool IsInvalidUnlessNestedName(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
IdentifierInfo &II,
TypeTy *ObjectType,
bool EnteringContext);
-
+
/// ActOnCXXNestedNameSpecifier - Called during parsing of a
/// nested-name-specifier that involves a template-id, e.g.,
/// "foo::bar<int, float>::", and now we need to build a scope
@@ -2374,7 +2439,7 @@ public:
/// looked up in the declarator-id's scope, until the declarator is parsed and
/// ActOnCXXExitDeclaratorScope is called.
/// The 'SS' should be a non-empty valid CXXScopeSpec.
- virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS);
+ virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS);
/// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
/// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same
@@ -2400,7 +2465,7 @@ public:
unsigned NumStrings);
Expr *BuildObjCEncodeExpression(SourceLocation AtLoc,
- QualType EncodedType,
+ TypeSourceInfo *EncodedTypeInfo,
SourceLocation RParenLoc);
CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp,
NamedDecl *FoundDecl,
@@ -2432,8 +2497,7 @@ public:
virtual DeclPtrTy ActOnStartLinkageSpecification(Scope *S,
SourceLocation ExternLoc,
SourceLocation LangLoc,
- const char *Lang,
- unsigned StrSize,
+ llvm::StringRef Lang,
SourceLocation LBraceLoc);
virtual DeclPtrTy ActOnFinishLinkageSpecification(Scope *S,
DeclPtrTy LinkageSpec,
@@ -2455,7 +2519,7 @@ public:
virtual MemInitResult ActOnMemInitializer(DeclPtrTy ConstructorD,
Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
IdentifierInfo *MemberOrBase,
TypeTy *TemplateTypeTy,
SourceLocation IdLoc,
@@ -2479,6 +2543,9 @@ public:
bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
CXXBaseOrMemberInitializer **Initializers,
unsigned NumInitializers, bool AnyErrors);
+
+ void SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation);
+
/// MarkBaseAndMemberDestructorsReferenced - Given a record decl,
/// mark all the non-trivial destructors of its members and bases as
@@ -2494,28 +2561,28 @@ public:
ClassesWithUnmarkedVirtualMembers;
/// MaybeMarkVirtualMembersReferenced - If the passed in method is the
- /// key function of the record decl, will mark virtual member functions as
+ /// key function of the record decl, will mark virtual member functions as
/// referenced.
void MaybeMarkVirtualMembersReferenced(SourceLocation Loc, CXXMethodDecl *MD);
-
+
/// MarkVirtualMembersReferenced - Will mark all virtual members of the given
/// CXXRecordDecl referenced.
void MarkVirtualMembersReferenced(SourceLocation Loc,
const CXXRecordDecl *RD);
- /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes
+ /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes
/// that might need to have their virtual members marked as referenced.
/// Returns false if no work was done.
bool ProcessPendingClassesWithUnmarkedVirtualMembers();
-
- void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
+
+ void AddImplicitlyDeclaredMembersToClass(Scope *S, CXXRecordDecl *ClassDecl);
virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
MemInitTy **MemInits, unsigned NumMemInits,
bool AnyErrors);
- void CheckCompletedCXXClass(CXXRecordDecl *Record);
+ void CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record);
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclPtrTy TagDecl,
SourceLocation LBrac,
@@ -2537,6 +2604,8 @@ public:
ExprArg AssertExpr,
ExprArg AssertMessageExpr);
+ FriendDecl *CheckFriendTypeDecl(SourceLocation FriendLoc,
+ TypeSourceInfo *TSInfo);
DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
MultiTemplateParamsArg TemplateParams);
DeclPtrTy ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
@@ -2551,7 +2620,7 @@ public:
void CheckConversionDeclarator(Declarator &D, QualType &R,
FunctionDecl::StorageClass& SC);
DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion);
-
+
//===--------------------------------------------------------------------===//
// C++ Derived Classes
//
@@ -2562,14 +2631,14 @@ public:
bool Virtual, AccessSpecifier Access,
QualType BaseType,
SourceLocation BaseLoc);
-
- /// SetClassDeclAttributesFromBase - Copies class decl traits
- /// (such as whether the class has a trivial constructor,
+
+ /// SetClassDeclAttributesFromBase - Copies class decl traits
+ /// (such as whether the class has a trivial constructor,
/// trivial destructor etc) from the given base class.
void SetClassDeclAttributesFromBase(CXXRecordDecl *Class,
const CXXRecordDecl *BaseClass,
bool BaseIsVirtual);
-
+
virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl,
SourceRange SpecifierRange,
bool Virtual, AccessSpecifier Access,
@@ -2583,15 +2652,21 @@ public:
bool IsDerivedFrom(QualType Derived, QualType Base);
bool IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths);
-
+
+ // FIXME: I don't like this name.
+ void BuildBasePathArray(const CXXBasePaths &Paths,
+ CXXBaseSpecifierArray &BasePath);
+
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
SourceLocation Loc, SourceRange Range,
+ CXXBaseSpecifierArray *BasePath = 0,
bool IgnoreAccess = false);
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
unsigned InaccessibleBaseID,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
- DeclarationName Name);
+ DeclarationName Name,
+ CXXBaseSpecifierArray *BasePath);
std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths);
@@ -2636,6 +2711,7 @@ public:
DeclAccessPair FoundDecl);
AccessResult CheckConstructorAccess(SourceLocation Loc,
CXXConstructorDecl *D,
+ const InitializedEntity &Entity,
AccessSpecifier Access);
AccessResult CheckDestructorAccess(SourceLocation Loc,
CXXDestructorDecl *Dtor,
@@ -2691,23 +2767,23 @@ public:
//===--------------------------------------------------------------------===//
// C++ Templates [C++ 14]
//
- void LookupTemplateName(LookupResult &R, Scope *S, const CXXScopeSpec &SS,
+ void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
QualType ObjectType, bool EnteringContext);
virtual TemplateNameKind isTemplateName(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext,
TemplateTy &Template);
-
- virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
+
+ 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);
@@ -2765,10 +2841,11 @@ public:
const CXXScopeSpec &SS,
TemplateParameterList **ParamLists,
unsigned NumParamLists,
+ bool IsFriend,
bool &IsExplicitSpecialization);
DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
- SourceLocation KWLoc, const CXXScopeSpec &SS,
+ SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
TemplateParameterList *TemplateParams,
@@ -2776,7 +2853,7 @@ public:
void translateTemplateArguments(const ASTTemplateArgsPtr &In,
TemplateArgumentListInfo &Out);
-
+
QualType CheckTemplateIdType(TemplateName Template,
SourceLocation TemplateLoc,
const TemplateArgumentListInfo &TemplateArgs);
@@ -2796,13 +2873,13 @@ public:
LookupResult &R,
bool RequiresADL,
const TemplateArgumentListInfo &TemplateArgs);
- OwningExprResult BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS,
+ OwningExprResult BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
DeclarationName Name,
SourceLocation NameLoc,
const TemplateArgumentListInfo &TemplateArgs);
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext);
@@ -2815,7 +2892,7 @@ public:
virtual DeclResult
ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
TemplateTy Template,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
@@ -2839,12 +2916,16 @@ public:
TemplateSpecializationKind PrevTSK,
SourceLocation PrevPointOfInstantiation,
bool &SuppressNew);
-
+
+ bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
+ const TemplateArgumentListInfo &ExplicitTemplateArgs,
+ LookupResult &Previous);
+
bool CheckFunctionTemplateSpecialization(FunctionDecl *FD,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous);
bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous);
-
+
virtual DeclResult
ActOnExplicitInstantiation(Scope *S,
SourceLocation ExternLoc,
@@ -2865,7 +2946,7 @@ public:
SourceLocation TemplateLoc,
unsigned TagSpec,
SourceLocation KWLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
IdentifierInfo *Name,
SourceLocation NameLoc,
AttributeList *Attr);
@@ -2874,8 +2955,8 @@ public:
SourceLocation ExternLoc,
SourceLocation TemplateLoc,
Declarator &D);
-
- TemplateArgumentLoc
+
+ TemplateArgumentLoc
SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
@@ -2905,7 +2986,7 @@ public:
SourceLocation RAngleLoc,
TemplateArgumentListBuilder &Converted,
CheckTemplateArgumentKind CTAK = CTAK_Specified);
-
+
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
const TemplateArgumentListInfo &TemplateArgs,
@@ -2918,23 +2999,23 @@ public:
bool CheckTemplateArgument(TemplateTypeParmDecl *Param,
TypeSourceInfo *Arg);
- bool CheckTemplateArgumentPointerToMember(Expr *Arg,
+ bool CheckTemplateArgumentPointerToMember(Expr *Arg,
TemplateArgument &Converted);
bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType InstantiatedParamType, Expr *&Arg,
TemplateArgument &Converted,
CheckTemplateArgumentKind CTAK = CTAK_Specified);
- bool CheckTemplateArgument(TemplateTemplateParmDecl *Param,
+ bool CheckTemplateArgument(TemplateTemplateParmDecl *Param,
const TemplateArgumentLoc &Arg);
- OwningExprResult
+ OwningExprResult
BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
QualType ParamType,
SourceLocation Loc);
- OwningExprResult
+ OwningExprResult
BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
SourceLocation Loc);
-
+
/// \brief Enumeration describing how template parameter lists are compared
/// for equality.
enum TemplateParameterListEqualKind {
@@ -2946,7 +3027,7 @@ public:
/// template<typename T> struct X;
/// \endcode
TPL_TemplateMatch,
-
+
/// \brief We are matching the template parameter lists of two template
/// template parameters as part of matching the template parameter lists
/// of two templates that might be redeclarations.
@@ -2956,7 +3037,7 @@ public:
/// template<template<int Value> class Other> struct X;
/// \endcode
TPL_TemplateTemplateParmMatch,
-
+
/// \brief We are matching the template parameter lists of a template
/// template argument against the template parameter lists of a template
/// template parameter.
@@ -2968,7 +3049,7 @@ public:
/// \endcode
TPL_TemplateTemplateArgumentMatch
};
-
+
bool TemplateParameterListsAreEqual(TemplateParameterList *New,
TemplateParameterList *Old,
bool Complain,
@@ -3001,12 +3082,15 @@ public:
ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
SourceLocation TemplateLoc, TypeTy *Ty);
- QualType CheckTypenameType(NestedNameSpecifier *NNS,
+ QualType CheckTypenameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
const IdentifierInfo &II,
SourceRange Range);
- QualType RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc,
- DeclarationName Name);
+ TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
+ SourceLocation Loc,
+ DeclarationName Name);
+ bool RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS);
std::string
getTemplateArgumentBindingsText(const TemplateParameterList *Params,
@@ -3016,7 +3100,7 @@ public:
getTemplateArgumentBindingsText(const TemplateParameterList *Params,
const TemplateArgument *Args,
unsigned NumArgs);
-
+
/// \brief Describes the result of template argument deduction.
///
/// The TemplateDeductionResult enumeration describes the result of
@@ -3205,27 +3289,28 @@ public:
const PartialDiagnostic &NoneDiag,
const PartialDiagnostic &AmbigDiag,
const PartialDiagnostic &CandidateDiag);
-
+
ClassTemplatePartialSpecializationDecl *
getMoreSpecializedPartialSpecialization(
ClassTemplatePartialSpecializationDecl *PS1,
ClassTemplatePartialSpecializationDecl *PS2,
SourceLocation Loc);
-
+
void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
bool OnlyDeduced,
unsigned Depth,
llvm::SmallVectorImpl<bool> &Used);
void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
llvm::SmallVectorImpl<bool> &Deduced);
-
+
//===--------------------------------------------------------------------===//
// C++ Template Instantiation
//
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D,
const TemplateArgumentList *Innermost = 0,
- bool RelativeToPrimary = false);
+ bool RelativeToPrimary = false,
+ const FunctionDecl *Pattern = 0);
/// \brief A template instantiation that is currently in progress.
struct ActiveTemplateInstantiation {
@@ -3257,12 +3342,12 @@ public:
/// Entity is either a ClassTemplatePartialSpecializationDecl or
/// a FunctionTemplateDecl.
DeducedTemplateArgumentSubstitution,
-
+
/// We are substituting prior template arguments into a new
/// template parameter. The template parameter itself is either a
/// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl.
PriorTemplateArgumentSubstitution,
-
+
/// We are checking the validity of a default template argument that
/// has been used when naming a template-id.
DefaultTemplateArgumentChecking
@@ -3274,7 +3359,7 @@ public:
/// \brief The template in which we are performing the instantiation,
/// for substitutions of prior template arguments.
TemplateDecl *Template;
-
+
/// \brief The entity that is being instantiated.
uintptr_t Entity;
@@ -3291,13 +3376,13 @@ public:
SourceRange InstantiationRange;
ActiveTemplateInstantiation()
- : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0),
+ : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0),
NumTemplateArgs(0) {}
/// \brief Determines whether this template is an actual instantiation
/// that should be counted toward the maximum instantiation depth.
bool isInstantiationRecord() const;
-
+
friend bool operator==(const ActiveTemplateInstantiation &X,
const ActiveTemplateInstantiation &Y) {
if (X.Kind != Y.Kind)
@@ -3314,9 +3399,9 @@ public:
case DefaultTemplateArgumentChecking:
if (X.Template != Y.Template)
return false;
-
+
// Fall through
-
+
case DefaultTemplateArgumentInstantiation:
case ExplicitTemplateArgumentSubstitution:
case DeducedTemplateArgumentSubstitution:
@@ -3347,7 +3432,7 @@ public:
/// \c ActiveTemplateInstantiations that are not actual instantiations and,
/// therefore, should not be counted as part of the instantiation depth.
unsigned NonInstantiationEntries;
-
+
/// \brief The last template from which a template instantiation
/// error or warning was produced.
///
@@ -3422,7 +3507,7 @@ public:
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceRange InstantiationRange);
-
+
/// \brief Note that we are checking the default template argument
/// against the template parameter for a given template-id.
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -3431,8 +3516,8 @@ public:
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceRange InstantiationRange);
-
-
+
+
/// \brief Note that we have finished instantiating this template.
void Clear();
@@ -3510,7 +3595,7 @@ public:
/// instantiated ParmVarDecl for 'x'.
llvm::DenseMap<const Decl *, Decl *> LocalDecls;
- /// \brief The outer scope, in which contains local variable
+ /// \brief The outer scope, which contains local variable
/// definitions from some other instantiation (that may not be
/// relevant to this particular scope).
LocalInstantiationScope *Outer;
@@ -3518,54 +3603,36 @@ public:
/// \brief Whether we have already exited this scope.
bool Exited;
- /// \brief Whether this scope is temporary, meaning that we should
- /// remove any additions we make once we exit this
- /// scope. Temporary scopes are always combined with their outer
- /// scopes.
- bool Temporary;
-
- /// \brief List of the declarations that we have added into this
- /// temporary scope. They will be removed when we exit the
- /// temporary scope.
- llvm::SmallVector<const Decl *, 4> AddedTemporaryDecls;
-
+ /// \brief Whether to combine this scope with the outer scope, such that
+ /// lookup will search our outer scope.
+ bool CombineWithOuterScope;
+
// This class is non-copyable
LocalInstantiationScope(const LocalInstantiationScope &);
LocalInstantiationScope &operator=(const LocalInstantiationScope &);
public:
- LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false,
- bool Temporary = false)
- : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
- Exited(false), Temporary(Temporary) {
- if (!CombineWithOuterScope && !Temporary)
- SemaRef.CurrentInstantiationScope = this;
- else
- assert(SemaRef.CurrentInstantiationScope &&
- "No outer instantiation scope?");
+ LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false)
+ : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
+ Exited(false), CombineWithOuterScope(CombineWithOuterScope)
+ {
+ SemaRef.CurrentInstantiationScope = this;
}
~LocalInstantiationScope() {
- if (!Exited) {
- SemaRef.CurrentInstantiationScope = Outer;
- for (unsigned I = 0, N = AddedTemporaryDecls.size(); I != N; ++I)
- LocalDecls.erase(AddedTemporaryDecls[I]);
- }
+ Exit();
}
/// \brief Exit this local instantiation scope early.
void Exit() {
+ if (Exited)
+ return;
+
SemaRef.CurrentInstantiationScope = Outer;
- LocalDecls.clear();
Exited = true;
}
- Decl *getInstantiationOf(const Decl *D) {
- Decl *Result = LocalDecls[D];
- assert((Result || D->isInvalidDecl()) &&
- "declaration was not instantiated in this scope!");
- return Result;
- }
+ Decl *getInstantiationOf(const Decl *D);
VarDecl *getInstantiationOf(const VarDecl *Var) {
return cast<VarDecl>(getInstantiationOf(cast<Decl>(Var)));
@@ -3579,16 +3646,8 @@ public:
const NonTypeTemplateParmDecl *Var) {
return cast<NonTypeTemplateParmDecl>(getInstantiationOf(cast<Decl>(Var)));
}
-
- void InstantiatedLocal(const Decl *D, Decl *Inst) {
- Decl *&Stored = LocalDecls[D];
- assert((!Stored || Stored == Inst) && "Already instantiated this local");
- if (Temporary && !Stored)
- AddedTemporaryDecls.push_back(D);
-
- Stored = Inst;
- }
+ void InstantiatedLocal(const Decl *D, Decl *Inst);
};
/// \brief The current instantiation scope used to store local
@@ -3634,6 +3693,12 @@ public:
const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc, DeclarationName Entity);
+ TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ SourceLocation Loc,
+ DeclarationName Entity);
+ ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
OwningExprResult SubstExpr(Expr *E,
const MultiLevelTemplateArgumentList &TemplateArgs);
@@ -3701,8 +3766,6 @@ public:
DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC,
const MultiLevelTemplateArgumentList &TemplateArgs);
- bool CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl *> &Params);
-
// Objective-C declarations.
virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName,
@@ -3823,7 +3886,7 @@ public:
// optional arguments. The number of types/arguments is obtained
// from the Sel.getNumArgs().
ObjCArgInfo *ArgInfo,
- llvm::SmallVectorImpl<Declarator> &Cdecls,
+ DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args
AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind,
bool isVariadic = false);
@@ -3836,28 +3899,66 @@ public:
ObjCMethodDecl *LookupPrivateInstanceMethod(Selector Sel,
ObjCInterfaceDecl *ClassDecl);
- virtual OwningExprResult ActOnClassPropertyRefExpr(
- IdentifierInfo &receiverName,
- IdentifierInfo &propertyName,
- SourceLocation &receiverNameLoc,
- SourceLocation &propertyNameLoc);
-
- // ActOnClassMessage - used for both unary and keyword messages.
- // ArgExprs is optional - if it is present, the number of expressions
- // is obtained from NumArgs.
- virtual ExprResult ActOnClassMessage(
- Scope *S,
- IdentifierInfo *receivingClassName, Selector Sel, SourceLocation lbrac,
- SourceLocation receiverLoc, SourceLocation selectorLoc,SourceLocation rbrac,
- ExprTy **ArgExprs, unsigned NumArgs);
-
- // ActOnInstanceMessage - used for both unary and keyword messages.
- // ArgExprs is optional - if it is present, the number of expressions
- // is obtained from NumArgs.
- virtual ExprResult ActOnInstanceMessage(
- ExprTy *receiver, Selector Sel,
- SourceLocation lbrac, SourceLocation receiverLoc, SourceLocation rbrac,
- ExprTy **ArgExprs, unsigned NumArgs);
+ OwningExprResult
+ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
+ Expr *BaseExpr,
+ DeclarationName MemberName,
+ SourceLocation MemberLoc);
+
+ virtual OwningExprResult
+ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
+ IdentifierInfo &propertyName,
+ SourceLocation receiverNameLoc,
+ SourceLocation propertyNameLoc);
+
+ virtual ObjCMessageKind getObjCMessageKind(Scope *S,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ bool IsSuper,
+ bool HasTrailingDot,
+ TypeTy *&ReceiverType);
+
+ virtual OwningExprResult ActOnSuperMessage(Scope *S, SourceLocation SuperLoc,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args);
+
+ OwningExprResult BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
+ QualType ReceiverType,
+ SourceLocation SuperLoc,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ SourceLocation LBracLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args);
+
+ virtual OwningExprResult ActOnClassMessage(Scope *S,
+ TypeTy *Receiver,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args);
+
+ OwningExprResult BuildInstanceMessage(ExprArg Receiver,
+ QualType ReceiverType,
+ SourceLocation SuperLoc,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ SourceLocation LBracLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args);
+
+ virtual OwningExprResult ActOnInstanceMessage(Scope *S,
+ ExprArg Receiver,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args);
+
/// ActOnPragmaPack - Called on well formed #pragma pack(...).
virtual void ActOnPragmaPack(PragmaPackKind Kind,
@@ -3900,7 +4001,9 @@ public:
/// cast. If there is already an implicit cast, merge into the existing one.
/// If isLvalue, the result of the cast is an lvalue.
void ImpCastExprToType(Expr *&Expr, QualType Type, CastExpr::CastKind Kind,
- bool isLvalue = false);
+ bool isLvalue = false,
+ CXXBaseSpecifierArray BasePath =
+ CXXBaseSpecifierArray());
// UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts
// functions and arrays to their respective pointers (C99 6.3.2.1).
@@ -3985,11 +4088,11 @@ public:
/// CompatiblePointerDiscardsQualifiers - The assignment discards
/// c/v/r qualifiers, which we accept as an extension.
CompatiblePointerDiscardsQualifiers,
-
+
/// IncompatibleNestedPointerQualifiers - The assignment is between two
/// nested pointer types, and the qualifiers other than the first two
- /// levels differ e.g. char ** -> const char **, but we accept them as an
- /// extension.
+ /// levels differ e.g. char ** -> const char **, but we accept them as an
+ /// extension.
IncompatibleNestedPointerQualifiers,
/// IncompatibleVectors - The assignment is between two vector types that
@@ -4013,14 +4116,15 @@ public:
/// represent it in the AST.
Incompatible
};
-
+
/// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the
/// assignment conversion type specified by ConvTy. This returns true if the
/// conversion was invalid or false if the conversion was accepted.
bool DiagnoseAssignmentResult(AssignConvertType ConvTy,
SourceLocation Loc,
QualType DstType, QualType SrcType,
- Expr *SrcExpr, AssignmentAction Action);
+ Expr *SrcExpr, AssignmentAction Action,
+ bool *Complained = 0);
/// CheckAssignmentConstraints - Perform type checking for assignment,
/// argument passing, variable initialization, and function return values.
@@ -4056,12 +4160,10 @@ public:
bool PerformImplicitConversion(Expr *&From, QualType ToType,
AssignmentAction Action,
- bool AllowExplicit = false,
- bool Elidable = false);
+ bool AllowExplicit = false);
bool PerformImplicitConversion(Expr *&From, QualType ToType,
AssignmentAction Action,
bool AllowExplicit,
- bool Elidable,
ImplicitConversionSequence& ICS);
bool PerformImplicitConversion(Expr *&From, QualType ToType,
const ImplicitConversionSequence& ICS,
@@ -4106,12 +4208,12 @@ public:
Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
QualType CXXCheckConditionalOperands( // C++ 5.16
Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
- QualType FindCompositePointerType(Expr *&E1, Expr *&E2,
+ QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2,
bool *NonStandardCompositeType = 0);
QualType FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
SourceLocation questionLoc);
-
+
/// type checking for vector binary operators.
inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex);
inline QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx,
@@ -4120,7 +4222,7 @@ public:
/// type checking unary operators (subroutines of ActOnUnaryOp).
/// C99 6.5.3.1, 6.5.3.2, 6.5.3.4
QualType CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc,
- bool isInc);
+ bool isInc, bool isPrefix);
QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc);
QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc);
QualType CheckRealImagOperand(Expr *&Op, SourceLocation OpLoc, bool isReal);
@@ -4162,19 +4264,10 @@ public:
QualType T1, QualType T2,
bool& DerivedToBase);
- bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType declType,
- SourceLocation DeclLoc,
- bool SuppressUserConversions,
- bool AllowExplicit,
- bool ForceRValue,
- ImplicitConversionSequence *ICS = 0,
- bool IgnoreBaseAccess = false);
-
/// CheckCastTypes - Check type constraints for casting between types under
/// C semantics, or forward to CXXCheckCStyleCast in C++.
bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr,
- CastExpr::CastKind &Kind,
- CXXMethodDecl *& ConversionDecl,
+ CastExpr::CastKind &Kind, CXXBaseSpecifierArray &BasePath,
bool FunctionalStyle = false);
// CheckVectorCast - check type constraints for vectors.
@@ -4195,8 +4288,9 @@ public:
/// CXXCheckCStyleCast - Check constraints of a C-style or function-style
/// cast under C++ semantics.
bool CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
- CastExpr::CastKind &Kind, bool FunctionalStyle,
- CXXMethodDecl *&ConversionDecl);
+ CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath,
+ bool FunctionalStyle);
/// CheckMessageArgumentTypes - Check types in an Obj-C message send.
/// \param Method - May be null.
@@ -4253,7 +4347,7 @@ 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,
@@ -4262,14 +4356,14 @@ public:
virtual void CodeCompleteCase(Scope *S);
virtual void CodeCompleteCall(Scope *S, ExprTy *Fn,
ExprTy **Args, unsigned NumArgs);
- virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
+ virtual void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
bool EnteringContext);
virtual void CodeCompleteUsing(Scope *S);
virtual void CodeCompleteUsingDirective(Scope *S);
virtual void CodeCompleteNamespaceDecl(Scope *S);
virtual void CodeCompleteNamespaceAliasDecl(Scope *S);
virtual void CodeCompleteOperatorName(Scope *S);
-
+
virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl,
bool InInterface);
virtual void CodeCompleteObjCAtVisibility(Scope *S);
@@ -4283,9 +4377,11 @@ public:
DeclPtrTy *Methods,
unsigned NumMethods);
- virtual void CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName,
- SourceLocation FNameLoc,
- IdentifierInfo **SelIdents,
+ virtual void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
+ IdentifierInfo **SelIdents,
+ unsigned NumSelIdents);
+ virtual void CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver,
+ IdentifierInfo **SelIdents,
unsigned NumSelIdents);
virtual void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
IdentifierInfo **SelIdents,
@@ -4294,20 +4390,27 @@ public:
unsigned NumProtocols);
virtual void CodeCompleteObjCProtocolDecl(Scope *S);
virtual void CodeCompleteObjCInterfaceDecl(Scope *S);
- virtual void CodeCompleteObjCSuperclass(Scope *S,
- IdentifierInfo *ClassName);
+ virtual void CodeCompleteObjCSuperclass(Scope *S,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassNameLoc);
virtual void CodeCompleteObjCImplementationDecl(Scope *S);
- virtual void CodeCompleteObjCInterfaceCategory(Scope *S,
- IdentifierInfo *ClassName);
- virtual void CodeCompleteObjCImplementationCategory(Scope *S,
- IdentifierInfo *ClassName);
- virtual void CodeCompleteObjCPropertyDefinition(Scope *S,
+ virtual void CodeCompleteObjCInterfaceCategory(Scope *S,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassNameLoc);
+ virtual void CodeCompleteObjCImplementationCategory(Scope *S,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassNameLoc);
+ virtual void CodeCompleteObjCPropertyDefinition(Scope *S,
DeclPtrTy ObjCImpDecl);
- virtual void CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
+ virtual void CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
IdentifierInfo *PropertyName,
DeclPtrTy ObjCImpDecl);
+ virtual void CodeCompleteObjCMethodDecl(Scope *S,
+ bool IsInstanceMethod,
+ TypeTy *ReturnType,
+ DeclPtrTy IDecl);
//@}
-
+
//===--------------------------------------------------------------------===//
// Extra semantic analysis beyond the C type system
@@ -4327,7 +4430,6 @@ private:
bool SemaBuiltinVAStart(CallExpr *TheCall);
bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs);
- bool SemaBuiltinStackAddress(CallExpr *TheCall);
public:
// Used by C++ template instantiation.
@@ -4338,7 +4440,8 @@ private:
bool SemaBuiltinObjectSize(CallExpr *TheCall);
bool SemaBuiltinLongjmp(CallExpr *TheCall);
bool SemaBuiltinAtomicOverloaded(CallExpr *TheCall);
- bool SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall);
+ bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
+ llvm::APSInt &Result);
bool SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg);
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index f628884..444ee79 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "SemaInit.h"
#include "Lookup.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
@@ -22,6 +23,13 @@
using namespace clang;
+/// A copy of Sema's enum without AR_delayed.
+enum AccessResult {
+ AR_accessible,
+ AR_inaccessible,
+ AR_dependent
+};
+
/// SetMemberAccessSpecifier - Set the access specifier of a member.
/// Returns true on error (when the previous member decl access specifier
/// is different from the new member decl access specifier).
@@ -51,6 +59,20 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
return false;
}
+static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
+ DeclContext *DC = D->getDeclContext();
+
+ // This can only happen at top: enum decls only "publish" their
+ // immediate members.
+ if (isa<EnumDecl>(DC))
+ DC = cast<EnumDecl>(DC)->getDeclContext();
+
+ CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);
+ while (DeclaringClass->isAnonymousStructOrUnion())
+ DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
+ return DeclaringClass;
+}
+
namespace {
struct EffectiveContext {
EffectiveContext() : Inner(0), Dependent(false) {}
@@ -109,22 +131,168 @@ struct EffectiveContext {
llvm::SmallVector<CXXRecordDecl*, 4> Records;
bool Dependent;
};
+
+/// Like Sema's AccessedEntity, but kindly lets us scribble all over
+/// it.
+struct AccessTarget : public Sema::AccessedEntity {
+ AccessTarget(const Sema::AccessedEntity &Entity)
+ : AccessedEntity(Entity) {
+ initialize();
+ }
+
+ AccessTarget(ASTContext &Context,
+ MemberNonce _,
+ CXXRecordDecl *NamingClass,
+ DeclAccessPair FoundDecl,
+ QualType BaseObjectType)
+ : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) {
+ initialize();
+ }
+
+ AccessTarget(ASTContext &Context,
+ BaseNonce _,
+ CXXRecordDecl *BaseClass,
+ CXXRecordDecl *DerivedClass,
+ AccessSpecifier Access)
+ : AccessedEntity(Context, Base, BaseClass, DerivedClass, Access) {
+ initialize();
+ }
+
+ bool hasInstanceContext() const {
+ return HasInstanceContext;
+ }
+
+ class SavedInstanceContext {
+ public:
+ ~SavedInstanceContext() {
+ Target.HasInstanceContext = Has;
+ }
+
+ private:
+ friend struct AccessTarget;
+ explicit SavedInstanceContext(AccessTarget &Target)
+ : Target(Target), Has(Target.HasInstanceContext) {}
+ AccessTarget &Target;
+ bool Has;
+ };
+
+ SavedInstanceContext saveInstanceContext() {
+ return SavedInstanceContext(*this);
+ }
+
+ void suppressInstanceContext() {
+ HasInstanceContext = false;
+ }
+
+ const CXXRecordDecl *resolveInstanceContext(Sema &S) const {
+ assert(HasInstanceContext);
+ if (CalculatedInstanceContext)
+ return InstanceContext;
+
+ CalculatedInstanceContext = true;
+ DeclContext *IC = S.computeDeclContext(getBaseObjectType());
+ InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl() : 0);
+ return InstanceContext;
+ }
+
+ const CXXRecordDecl *getDeclaringClass() const {
+ return DeclaringClass;
+ }
+
+private:
+ void initialize() {
+ HasInstanceContext = (isMemberAccess() &&
+ !getBaseObjectType().isNull() &&
+ getTargetDecl()->isCXXInstanceMember());
+ CalculatedInstanceContext = false;
+ InstanceContext = 0;
+
+ if (isMemberAccess())
+ DeclaringClass = FindDeclaringClass(getTargetDecl());
+ else
+ DeclaringClass = getBaseClass();
+ DeclaringClass = DeclaringClass->getCanonicalDecl();
+ }
+
+ bool HasInstanceContext : 1;
+ mutable bool CalculatedInstanceContext : 1;
+ mutable const CXXRecordDecl *InstanceContext;
+ const CXXRecordDecl *DeclaringClass;
+};
+
}
-static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
- DeclContext *DC = D->getDeclContext();
+/// Checks whether one class might instantiate to the other.
+static bool MightInstantiateTo(const CXXRecordDecl *From,
+ const CXXRecordDecl *To) {
+ // Declaration names are always preserved by instantiation.
+ if (From->getDeclName() != To->getDeclName())
+ return false;
- // This can only happen at top: enum decls only "publish" their
- // immediate members.
- if (isa<EnumDecl>(DC))
- DC = cast<EnumDecl>(DC)->getDeclContext();
+ const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext();
+ const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext();
+ if (FromDC == ToDC) return true;
+ if (FromDC->isFileContext() || ToDC->isFileContext()) return false;
- CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);
- while (DeclaringClass->isAnonymousStructOrUnion())
- DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
- return DeclaringClass;
+ // Be conservative.
+ return true;
}
+/// Checks whether one class is derived from another, inclusively.
+/// Properly indicates when it couldn't be determined due to
+/// dependence.
+///
+/// This should probably be donated to AST or at least Sema.
+static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
+ const CXXRecordDecl *Target) {
+ assert(Derived->getCanonicalDecl() == Derived);
+ assert(Target->getCanonicalDecl() == Target);
+
+ if (Derived == Target) return AR_accessible;
+
+ bool CheckDependent = Derived->isDependentContext();
+ if (CheckDependent && MightInstantiateTo(Derived, Target))
+ return AR_dependent;
+
+ AccessResult OnFailure = AR_inaccessible;
+ llvm::SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack
+
+ while (true) {
+ for (CXXRecordDecl::base_class_const_iterator
+ I = Derived->bases_begin(), E = Derived->bases_end(); I != E; ++I) {
+
+ const CXXRecordDecl *RD;
+
+ QualType T = I->getType();
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ RD = cast<CXXRecordDecl>(RT->getDecl());
+ } else if (const InjectedClassNameType *IT
+ = T->getAs<InjectedClassNameType>()) {
+ RD = IT->getDecl();
+ } else {
+ assert(T->isDependentType() && "non-dependent base wasn't a record?");
+ OnFailure = AR_dependent;
+ continue;
+ }
+
+ RD = RD->getCanonicalDecl();
+ if (RD == Target) return AR_accessible;
+ if (CheckDependent && MightInstantiateTo(RD, Target))
+ OnFailure = AR_dependent;
+
+ Queue.push_back(RD);
+ }
+
+ if (Queue.empty()) break;
+
+ Derived = Queue.back();
+ Queue.pop_back();
+ }
+
+ return OnFailure;
+}
+
+
static bool MightInstantiateTo(Sema &S, DeclContext *Context,
DeclContext *Friend) {
if (Friend == Context)
@@ -204,11 +372,11 @@ static bool MightInstantiateTo(Sema &S,
Friend->getTemplatedDecl());
}
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- const CXXRecordDecl *Friend) {
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *Friend) {
if (EC.includesClass(Friend))
- return Sema::AR_accessible;
+ return AR_accessible;
if (EC.isDependent()) {
CanQualType FriendTy
@@ -219,32 +387,32 @@ static Sema::AccessResult MatchesFriend(Sema &S,
CanQualType ContextTy
= S.Context.getCanonicalType(S.Context.getTypeDeclType(*I));
if (MightInstantiateTo(S, ContextTy, FriendTy))
- return Sema::AR_dependent;
+ return AR_dependent;
}
}
- return Sema::AR_inaccessible;
+ return AR_inaccessible;
}
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- CanQualType Friend) {
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ CanQualType Friend) {
if (const RecordType *RT = Friend->getAs<RecordType>())
return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
// TODO: we can do better than this
if (Friend->isDependentType())
- return Sema::AR_dependent;
+ return AR_dependent;
- return Sema::AR_inaccessible;
+ return AR_inaccessible;
}
/// Determines whether the given friend class template matches
/// anything in the effective context.
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- ClassTemplateDecl *Friend) {
- Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ ClassTemplateDecl *Friend) {
+ AccessResult OnFailure = AR_inaccessible;
// Check whether the friend is the template of a class in the
// context chain.
@@ -268,7 +436,7 @@ static Sema::AccessResult MatchesFriend(Sema &S,
// It's a match.
if (Friend == CTD->getCanonicalDecl())
- return Sema::AR_accessible;
+ return AR_accessible;
// If the context isn't dependent, it can't be a dependent match.
if (!EC.isDependent())
@@ -286,7 +454,7 @@ static Sema::AccessResult MatchesFriend(Sema &S,
continue;
// Otherwise, it's a dependent match.
- OnFailure = Sema::AR_dependent;
+ OnFailure = AR_dependent;
}
return OnFailure;
@@ -294,18 +462,18 @@ static Sema::AccessResult MatchesFriend(Sema &S,
/// Determines whether the given friend function matches anything in
/// the effective context.
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- FunctionDecl *Friend) {
- Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FunctionDecl *Friend) {
+ AccessResult OnFailure = AR_inaccessible;
for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
if (Friend == *I)
- return Sema::AR_accessible;
+ return AR_accessible;
if (EC.isDependent() && MightInstantiateTo(S, *I, Friend))
- OnFailure = Sema::AR_dependent;
+ OnFailure = AR_dependent;
}
return OnFailure;
@@ -313,12 +481,12 @@ static Sema::AccessResult MatchesFriend(Sema &S,
/// Determines whether the given friend function template matches
/// anything in the effective context.
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- FunctionTemplateDecl *Friend) {
- if (EC.Functions.empty()) return Sema::AR_inaccessible;
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FunctionTemplateDecl *Friend) {
+ if (EC.Functions.empty()) return AR_inaccessible;
- Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+ AccessResult OnFailure = AR_inaccessible;
for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
@@ -332,10 +500,10 @@ static Sema::AccessResult MatchesFriend(Sema &S,
FTD = FTD->getCanonicalDecl();
if (Friend == FTD)
- return Sema::AR_accessible;
+ return AR_accessible;
if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend))
- OnFailure = Sema::AR_dependent;
+ OnFailure = AR_dependent;
}
return OnFailure;
@@ -343,9 +511,9 @@ static Sema::AccessResult MatchesFriend(Sema &S,
/// Determines whether the given friend declaration matches anything
/// in the effective context.
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- FriendDecl *FriendD) {
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FriendDecl *FriendD) {
if (TypeSourceInfo *T = FriendD->getFriendType())
return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());
@@ -367,10 +535,10 @@ static Sema::AccessResult MatchesFriend(Sema &S,
return MatchesFriend(S, EC, cast<FunctionDecl>(Friend));
}
-static Sema::AccessResult GetFriendKind(Sema &S,
- const EffectiveContext &EC,
- const CXXRecordDecl *Class) {
- Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+static AccessResult GetFriendKind(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *Class) {
+ AccessResult OnFailure = AR_inaccessible;
// Okay, check friends.
for (CXXRecordDecl::friend_iterator I = Class->friend_begin(),
@@ -378,18 +546,15 @@ static Sema::AccessResult GetFriendKind(Sema &S,
FriendDecl *Friend = *I;
switch (MatchesFriend(S, EC, Friend)) {
- case Sema::AR_accessible:
- return Sema::AR_accessible;
+ case AR_accessible:
+ return AR_accessible;
- case Sema::AR_inaccessible:
- break;
+ case AR_inaccessible:
+ continue;
- case Sema::AR_dependent:
- OnFailure = Sema::AR_dependent;
+ case AR_dependent:
+ OnFailure = AR_dependent;
break;
-
- case Sema::AR_delayed:
- llvm_unreachable("cannot get delayed answer from MatchesFriend");
}
}
@@ -397,16 +562,19 @@ static Sema::AccessResult GetFriendKind(Sema &S,
return OnFailure;
}
-static Sema::AccessResult HasAccess(Sema &S,
- const EffectiveContext &EC,
- const CXXRecordDecl *NamingClass,
- AccessSpecifier Access) {
+static AccessResult HasAccess(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ const AccessTarget &Target) {
assert(NamingClass->getCanonicalDecl() == NamingClass &&
"declaration should be canonicalized before being passed here");
- if (Access == AS_public) return Sema::AR_accessible;
+ if (Access == AS_public) return AR_accessible;
assert(Access == AS_private || Access == AS_protected);
+ AccessResult OnFailure = AR_inaccessible;
+
for (EffectiveContext::record_iterator
I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
// All the declarations in EC have been canonicalized, so pointer
@@ -414,16 +582,78 @@ static Sema::AccessResult HasAccess(Sema &S,
const CXXRecordDecl *ECRecord = *I;
// [B2] and [M2]
- if (ECRecord == NamingClass)
- return Sema::AR_accessible;
+ if (Access == AS_private) {
+ if (ECRecord == NamingClass)
+ return AR_accessible;
+
+ if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass))
+ OnFailure = AR_dependent;
// [B3] and [M3]
- if (Access == AS_protected &&
- ECRecord->isDerivedFrom(const_cast<CXXRecordDecl*>(NamingClass)))
- return Sema::AR_accessible;
+ } else {
+ assert(Access == AS_protected);
+ switch (IsDerivedFromInclusive(ECRecord, NamingClass)) {
+ case AR_accessible: break;
+ case AR_inaccessible: continue;
+ case AR_dependent: OnFailure = AR_dependent; continue;
+ }
+
+ if (!Target.hasInstanceContext())
+ return AR_accessible;
+
+ const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
+ if (!InstanceContext) {
+ OnFailure = AR_dependent;
+ continue;
+ }
+
+ // C++ [class.protected]p1:
+ // An additional access check beyond those described earlier in
+ // [class.access] is applied when a non-static data member or
+ // non-static member function is a protected member of its naming
+ // class. As described earlier, access to a protected member is
+ // granted because the reference occurs in a friend or member of
+ // some class C. If the access is to form a pointer to member,
+ // the nested-name-specifier shall name C or a class derived from
+ // C. All other accesses involve a (possibly implicit) object
+ // expression. In this case, the class of the object expression
+ // shall be C or a class derived from C.
+ //
+ // We interpret this as a restriction on [M3]. Most of the
+ // conditions are encoded by not having any instance context.
+ switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) {
+ case AR_accessible: return AR_accessible;
+ case AR_inaccessible: continue;
+ case AR_dependent: OnFailure = AR_dependent; continue;
+ }
+ }
}
- return GetFriendKind(S, EC, NamingClass);
+ if (!NamingClass->hasFriends())
+ return OnFailure;
+
+ // Don't consider friends if we're under the [class.protected]
+ // restriction, above.
+ if (Access == AS_protected && Target.hasInstanceContext()) {
+ const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
+ if (!InstanceContext) return AR_dependent;
+
+ switch (IsDerivedFromInclusive(InstanceContext, NamingClass)) {
+ case AR_accessible: break;
+ case AR_inaccessible: return OnFailure;
+ case AR_dependent: return AR_dependent;
+ }
+ }
+
+ switch (GetFriendKind(S, EC, NamingClass)) {
+ case AR_accessible: return AR_accessible;
+ case AR_inaccessible: return OnFailure;
+ case AR_dependent: return AR_dependent;
+ }
+
+ // Silence bogus warnings
+ llvm_unreachable("impossible friendship kind");
+ return OnFailure;
}
/// Finds the best path from the naming class to the declaring class,
@@ -479,17 +709,21 @@ static Sema::AccessResult HasAccess(Sema &S,
///
/// B is an accessible base of N at R iff ACAB(1) = public.
///
-/// \param FinalAccess the access of the "final step", or AS_none if
+/// \param FinalAccess the access of the "final step", or AS_public if
/// there is no final step.
/// \return null if friendship is dependent
static CXXBasePath *FindBestPath(Sema &S,
const EffectiveContext &EC,
- CXXRecordDecl *Derived,
- CXXRecordDecl *Base,
+ AccessTarget &Target,
AccessSpecifier FinalAccess,
CXXBasePaths &Paths) {
// Derive the paths to the desired base.
- bool isDerived = Derived->isDerivedFrom(Base, Paths);
+ const CXXRecordDecl *Derived = Target.getNamingClass();
+ const CXXRecordDecl *Base = Target.getDeclaringClass();
+
+ // FIXME: fail correctly when there are dependent paths.
+ bool isDerived = Derived->isDerivedFrom(const_cast<CXXRecordDecl*>(Base),
+ Paths);
assert(isDerived && "derived class not actually derived from base");
(void) isDerived;
@@ -502,6 +736,7 @@ static CXXBasePath *FindBestPath(Sema &S,
// Derive the friend-modified access along each path.
for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
PI != PE; ++PI) {
+ AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext();
// Walk through the path backwards.
AccessSpecifier PathAccess = FinalAccess;
@@ -519,16 +754,23 @@ static CXXBasePath *FindBestPath(Sema &S,
break;
}
+ const CXXRecordDecl *NC = I->Class->getCanonicalDecl();
+
AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
PathAccess = std::max(PathAccess, BaseAccess);
- switch (HasAccess(S, EC, I->Class, PathAccess)) {
- case Sema::AR_inaccessible: break;
- case Sema::AR_accessible: PathAccess = AS_public; break;
- case Sema::AR_dependent:
+
+ switch (HasAccess(S, EC, NC, PathAccess, Target)) {
+ case AR_inaccessible: break;
+ case AR_accessible:
+ PathAccess = AS_public;
+
+ // Future tests are not against members and so do not have
+ // instance context.
+ Target.suppressInstanceContext();
+ break;
+ case AR_dependent:
AnyDependent = true;
goto Next;
- case Sema::AR_delayed:
- llvm_unreachable("friend resolution is never delayed"); break;
}
}
@@ -561,46 +803,36 @@ static CXXBasePath *FindBestPath(Sema &S,
/// to become inaccessible.
static void DiagnoseAccessPath(Sema &S,
const EffectiveContext &EC,
- const Sema::AccessedEntity &Entity) {
+ AccessTarget &Entity) {
AccessSpecifier Access = Entity.getAccess();
- CXXRecordDecl *NamingClass = Entity.getNamingClass();
+ const CXXRecordDecl *NamingClass = Entity.getNamingClass();
NamingClass = NamingClass->getCanonicalDecl();
- NamedDecl *D;
- CXXRecordDecl *DeclaringClass;
- if (Entity.isMemberAccess()) {
- D = Entity.getTargetDecl();
- DeclaringClass = FindDeclaringClass(D);
- } else {
- D = 0;
- DeclaringClass = Entity.getBaseClass();
- }
- DeclaringClass = DeclaringClass->getCanonicalDecl();
+ NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0);
+ const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
// Easy case: the decl's natural access determined its path access.
// We have to check against AS_private here in case Access is AS_none,
// indicating a non-public member of a private base class.
if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
- switch (HasAccess(S, EC, DeclaringClass, D->getAccess())) {
- case Sema::AR_inaccessible: {
+ switch (HasAccess(S, EC, DeclaringClass, D->getAccess(), Entity)) {
+ case AR_inaccessible: {
S.Diag(D->getLocation(), diag::note_access_natural)
<< (unsigned) (Access == AS_protected)
<< /*FIXME: not implicitly*/ 0;
return;
}
- case Sema::AR_accessible: break;
+ case AR_accessible: break;
- case Sema::AR_dependent:
- case Sema::AR_delayed:
- llvm_unreachable("dependent/delayed not allowed");
+ case AR_dependent:
+ llvm_unreachable("can't diagnose dependent access failures");
return;
}
}
CXXBasePaths Paths;
- CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass,
- AS_public, Paths);
+ CXXBasePath &Path = *FindBestPath(S, EC, Entity, AS_public, Paths);
CXXBasePath::iterator I = Path.end(), E = Path.begin();
while (I != E) {
@@ -615,12 +847,10 @@ static void DiagnoseAccessPath(Sema &S,
continue;
switch (GetFriendKind(S, EC, I->Class)) {
- case Sema::AR_accessible: continue;
- case Sema::AR_inaccessible: break;
-
- case Sema::AR_dependent:
- case Sema::AR_delayed:
- llvm_unreachable("dependent friendship, should not be diagnosing");
+ case AR_accessible: continue;
+ case AR_inaccessible: break;
+ case AR_dependent:
+ llvm_unreachable("can't diagnose dependent access failures");
}
// Check whether this base specifier is the tighest point
@@ -649,17 +879,10 @@ static void DiagnoseAccessPath(Sema &S,
static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
const EffectiveContext &EC,
- const Sema::AccessedEntity &Entity) {
+ AccessTarget &Entity) {
const CXXRecordDecl *NamingClass = Entity.getNamingClass();
- NamedDecl *D;
- const CXXRecordDecl *DeclaringClass;
- if (Entity.isMemberAccess()) {
- D = Entity.getTargetDecl();
- DeclaringClass = FindDeclaringClass(D);
- } else {
- D = 0;
- DeclaringClass = Entity.getBaseClass();
- }
+ const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
+ NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0);
S.Diag(Loc, Entity.getDiag())
<< (Entity.getAccess() == AS_protected)
@@ -671,9 +894,9 @@ static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
/// Determines whether the accessed entity is accessible. Public members
/// have been weeded out by this point.
-static Sema::AccessResult IsAccessible(Sema &S,
- const EffectiveContext &EC,
- const Sema::AccessedEntity &Entity) {
+static AccessResult IsAccessible(Sema &S,
+ const EffectiveContext &EC,
+ AccessTarget &Entity) {
// Determine the actual naming class.
CXXRecordDecl *NamingClass = Entity.getNamingClass();
while (NamingClass->isAnonymousStructOrUnion())
@@ -686,10 +909,10 @@ static Sema::AccessResult IsAccessible(Sema &S,
// Before we try to recalculate access paths, try to white-list
// accesses which just trade in on the final step, i.e. accesses
// which don't require [M4] or [B4]. These are by far the most
- // common forms of access.
+ // common forms of privileged access.
if (UnprivilegedAccess != AS_none) {
- switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess)) {
- case Sema::AR_dependent:
+ switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) {
+ case AR_dependent:
// This is actually an interesting policy decision. We don't
// *have* to delay immediately here: we can do the full access
// calculation in the hope that friendship on some intermediate
@@ -697,23 +920,14 @@ static Sema::AccessResult IsAccessible(Sema &S,
// But that's not cheap, and odds are very good (note: assertion
// made without data) that the friend declaration will determine
// access.
- return Sema::AR_dependent;
+ return AR_dependent;
- case Sema::AR_accessible: return Sema::AR_accessible;
- case Sema::AR_inaccessible: break;
- case Sema::AR_delayed:
- llvm_unreachable("friendship never subject to contextual delay");
+ case AR_accessible: return AR_accessible;
+ case AR_inaccessible: break;
}
}
- // Determine the declaring class.
- CXXRecordDecl *DeclaringClass;
- if (Entity.isMemberAccess()) {
- DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
- } else {
- DeclaringClass = Entity.getBaseClass();
- }
- DeclaringClass = DeclaringClass->getCanonicalDecl();
+ AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext();
// We lower member accesses to base accesses by pretending that the
// member is a base class of its declaring class.
@@ -723,43 +937,44 @@ static Sema::AccessResult IsAccessible(Sema &S,
// Determine if the declaration is accessible from EC when named
// in its declaring class.
NamedDecl *Target = Entity.getTargetDecl();
+ const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
FinalAccess = Target->getAccess();
- switch (HasAccess(S, EC, DeclaringClass, FinalAccess)) {
- case Sema::AR_accessible: FinalAccess = AS_public; break;
- case Sema::AR_inaccessible: break;
- case Sema::AR_dependent: return Sema::AR_dependent; // see above
- case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
+ switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) {
+ case AR_accessible:
+ FinalAccess = AS_public;
+ break;
+ case AR_inaccessible: break;
+ case AR_dependent: return AR_dependent; // see above
}
if (DeclaringClass == NamingClass)
- return (FinalAccess == AS_public
- ? Sema::AR_accessible
- : Sema::AR_inaccessible);
+ return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible);
+
+ Entity.suppressInstanceContext();
} else {
FinalAccess = AS_public;
}
- assert(DeclaringClass != NamingClass);
+ assert(Entity.getDeclaringClass() != NamingClass);
// Append the declaration's access if applicable.
CXXBasePaths Paths;
- CXXBasePath *Path = FindBestPath(S, EC, NamingClass, DeclaringClass,
- FinalAccess, Paths);
+ CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths);
if (!Path)
- return Sema::AR_dependent;
+ return AR_dependent;
assert(Path->Access <= UnprivilegedAccess &&
"access along best path worse than direct?");
if (Path->Access == AS_public)
- return Sema::AR_accessible;
- return Sema::AR_inaccessible;
+ return AR_accessible;
+ return AR_inaccessible;
}
-static void DelayAccess(Sema &S,
- const EffectiveContext &EC,
- SourceLocation Loc,
- const Sema::AccessedEntity &Entity) {
+static void DelayDependentAccess(Sema &S,
+ const EffectiveContext &EC,
+ SourceLocation Loc,
+ const AccessTarget &Entity) {
assert(EC.isDependent() && "delaying non-dependent access");
DeclContext *DC = EC.getInnerContext();
assert(DC->isDependentContext() && "delaying non-dependent access");
@@ -769,48 +984,38 @@ static void DelayAccess(Sema &S,
Entity.getAccess(),
Entity.getTargetDecl(),
Entity.getNamingClass(),
+ Entity.getBaseObjectType(),
Entity.getDiag());
}
/// Checks access to an entity from the given effective context.
-static Sema::AccessResult CheckEffectiveAccess(Sema &S,
- const EffectiveContext &EC,
- SourceLocation Loc,
- const Sema::AccessedEntity &Entity) {
+static AccessResult CheckEffectiveAccess(Sema &S,
+ const EffectiveContext &EC,
+ SourceLocation Loc,
+ AccessTarget &Entity) {
assert(Entity.getAccess() != AS_public && "called for public access!");
switch (IsAccessible(S, EC, Entity)) {
- case Sema::AR_dependent:
- DelayAccess(S, EC, Loc, Entity);
- return Sema::AR_dependent;
-
- case Sema::AR_delayed:
- llvm_unreachable("IsAccessible cannot contextually delay");
+ case AR_dependent:
+ DelayDependentAccess(S, EC, Loc, Entity);
+ return AR_dependent;
- case Sema::AR_inaccessible:
+ case AR_inaccessible:
if (!Entity.isQuiet())
DiagnoseBadAccess(S, Loc, EC, Entity);
- return Sema::AR_inaccessible;
-
- case Sema::AR_accessible:
- break;
- }
+ return AR_inaccessible;
- // We only consider the natural access of the declaration when
- // deciding whether to do the protected check.
- if (Entity.isMemberAccess() && Entity.getAccess() == AS_protected) {
- NamedDecl *D = Entity.getTargetDecl();
- if (isa<FieldDecl>(D) ||
- (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())) {
- // FIXME: implement [class.protected]
- }
+ case AR_accessible:
+ return AR_accessible;
}
- return Sema::AR_accessible;
+ // silence unnecessary warning
+ llvm_unreachable("invalid access result");
+ return AR_accessible;
}
static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
- const Sema::AccessedEntity &Entity) {
+ AccessTarget &Entity) {
// If the access path is public, it's accessible everywhere.
if (Entity.getAccess() == AS_public)
return Sema::AR_accessible;
@@ -825,16 +1030,31 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
return Sema::AR_delayed;
}
- return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
- Loc, Entity);
+ EffectiveContext EC(S.CurContext);
+ switch (CheckEffectiveAccess(S, EC, Loc, Entity)) {
+ case AR_accessible: return Sema::AR_accessible;
+ case AR_inaccessible: return Sema::AR_inaccessible;
+ case AR_dependent: return Sema::AR_dependent;
+ }
+ llvm_unreachable("falling off end");
+ return Sema::AR_accessible;
}
void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
// Pretend we did this from the context of the newly-parsed
- // declaration.
- EffectiveContext EC(Ctx->getDeclContext());
-
- if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData()))
+ // declaration. If that declaration itself forms a declaration context,
+ // include it in the effective context so that parameters and return types of
+ // befriended functions have that function's access priveledges.
+ DeclContext *DC = Ctx->getDeclContext();
+ if (isa<FunctionDecl>(Ctx))
+ DC = cast<DeclContext>(Ctx);
+ else if (FunctionTemplateDecl *FnTpl = dyn_cast<FunctionTemplateDecl>(Ctx))
+ DC = cast<DeclContext>(FnTpl->getTemplatedDecl());
+ EffectiveContext EC(DC);
+
+ AccessTarget Target(DD.getAccessData());
+
+ if (CheckEffectiveAccess(*this, EC, DD.Loc, Target) == ::AR_inaccessible)
DD.Triggered = true;
}
@@ -851,19 +1071,28 @@ void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
if (!TargetD) return;
if (DD.isAccessToMember()) {
- AccessedEntity Entity(Context,
- AccessedEntity::Member,
- cast<CXXRecordDecl>(NamingD),
- Access,
- cast<NamedDecl>(TargetD));
+ CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(NamingD);
+ NamedDecl *TargetDecl = cast<NamedDecl>(TargetD);
+ QualType BaseObjectType = DD.getAccessBaseObjectType();
+ if (!BaseObjectType.isNull()) {
+ BaseObjectType = SubstType(BaseObjectType, TemplateArgs, Loc,
+ DeclarationName());
+ if (BaseObjectType.isNull()) return;
+ }
+
+ AccessTarget Entity(Context,
+ AccessTarget::Member,
+ NamingClass,
+ DeclAccessPair::make(TargetDecl, Access),
+ BaseObjectType);
Entity.setDiag(DD.getDiagnostic());
CheckAccess(*this, Loc, Entity);
} else {
- AccessedEntity Entity(Context,
- AccessedEntity::Base,
- cast<CXXRecordDecl>(TargetD),
- cast<CXXRecordDecl>(NamingD),
- Access);
+ AccessTarget Entity(Context,
+ AccessTarget::Base,
+ cast<CXXRecordDecl>(TargetD),
+ cast<CXXRecordDecl>(NamingD),
+ Access);
Entity.setDiag(DD.getDiagnostic());
CheckAccess(*this, Loc, Entity);
}
@@ -876,8 +1105,8 @@ Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
Found.getAccess() == AS_public)
return AR_accessible;
- AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(),
- Found);
+ AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
+ Found, QualType());
Entity.setDiag(diag::err_access) << E->getSourceRange();
return CheckAccess(*this, E->getNameLoc(), Entity);
@@ -891,8 +1120,12 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
Found.getAccess() == AS_public)
return AR_accessible;
- AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(),
- Found);
+ QualType BaseType = E->getBaseType();
+ if (E->isArrow())
+ BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+
+ AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
+ Found, BaseType);
Entity.setDiag(diag::err_access) << E->getSourceRange();
return CheckAccess(*this, E->getMemberLoc(), Entity);
@@ -910,8 +1143,9 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
return AR_accessible;
CXXRecordDecl *NamingClass = Dtor->getParent();
- AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
- DeclAccessPair::make(Dtor, Access));
+ AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
+ DeclAccessPair::make(Dtor, Access),
+ QualType());
Entity.setDiag(PDiag); // TODO: avoid copy
return CheckAccess(*this, Loc, Entity);
@@ -920,17 +1154,39 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
/// Checks access to a constructor.
Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
CXXConstructorDecl *Constructor,
+ const InitializedEntity &Entity,
AccessSpecifier Access) {
if (!getLangOptions().AccessControl ||
Access == AS_public)
return AR_accessible;
CXXRecordDecl *NamingClass = Constructor->getParent();
- AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
- DeclAccessPair::make(Constructor, Access));
- Entity.setDiag(diag::err_access_ctor);
+ AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass,
+ DeclAccessPair::make(Constructor, Access),
+ QualType());
+ switch (Entity.getKind()) {
+ default:
+ AccessEntity.setDiag(diag::err_access_ctor);
+ break;
- return CheckAccess(*this, UseLoc, Entity);
+ case InitializedEntity::EK_Base:
+ AccessEntity.setDiag(PDiag(diag::err_access_base)
+ << Entity.isInheritedVirtualBase()
+ << Entity.getBaseSpecifier()->getType()
+ << getSpecialMember(Constructor));
+ break;
+
+ case InitializedEntity::EK_Member: {
+ const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl());
+ AccessEntity.setDiag(PDiag(diag::err_access_field)
+ << Field->getType()
+ << getSpecialMember(Constructor));
+ break;
+ }
+
+ }
+
+ return CheckAccess(*this, UseLoc, AccessEntity);
}
/// Checks direct (i.e. non-inherited) access to an arbitrary class
@@ -944,8 +1200,9 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
return AR_accessible;
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext());
- AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
- DeclAccessPair::make(Target, Access));
+ AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
+ DeclAccessPair::make(Target, Access),
+ QualType());
Entity.setDiag(Diag);
return CheckAccess(*this, UseLoc, Entity);
}
@@ -961,7 +1218,8 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
Found.getAccess() == AS_public)
return AR_accessible;
- AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
+ AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
+ QualType());
Entity.setDiag(diag::err_access)
<< PlacementRange;
@@ -982,7 +1240,8 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
assert(RT && "found member operator but object expr not of record type");
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
- AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
+ AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
+ ObjectExpr->getType());
Entity.setDiag(diag::err_access)
<< ObjectExpr->getSourceRange()
<< (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
@@ -998,24 +1257,16 @@ Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
return AR_accessible;
OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).getPointer();
- NestedNameSpecifier *Qualifier = Ovl->getQualifier();
- assert(Qualifier && "address of overloaded member without qualifier");
+ CXXRecordDecl *NamingClass = Ovl->getNamingClass();
- CXXScopeSpec SS;
- SS.setScopeRep(Qualifier);
- SS.setRange(Ovl->getQualifierRange());
- DeclContext *DC = computeDeclContext(SS);
- assert(DC && DC->isRecord() && "scope did not resolve to record");
- CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(DC);
-
- AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
+ AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
+ Context.getTypeDeclType(NamingClass));
Entity.setDiag(diag::err_access)
<< Ovl->getSourceRange();
return CheckAccess(*this, Ovl->getNameLoc(), Entity);
}
-
/// Checks access for a hierarchy conversion.
///
/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
@@ -1042,13 +1293,20 @@ Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
- AccessedEntity Entity(Context, AccessedEntity::Base, BaseD, DerivedD,
- Path.Access);
+ AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD,
+ Path.Access);
if (DiagID)
Entity.setDiag(DiagID) << Derived << Base;
- if (ForceUnprivileged)
- return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity);
+ if (ForceUnprivileged) {
+ switch (CheckEffectiveAccess(*this, EffectiveContext(),
+ AccessLoc, Entity)) {
+ case ::AR_accessible: return Sema::AR_accessible;
+ case ::AR_inaccessible: return Sema::AR_inaccessible;
+ case ::AR_dependent: return Sema::AR_dependent;
+ }
+ llvm_unreachable("unexpected result from CheckEffectiveAccess");
+ }
return CheckAccess(*this, AccessLoc, Entity);
}
@@ -1060,9 +1318,9 @@ void Sema::CheckLookupAccess(const LookupResult &R) {
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
if (I.getAccess() != AS_public) {
- AccessedEntity Entity(Context, AccessedEntity::Member,
- R.getNamingClass(),
- I.getPair());
+ AccessTarget Entity(Context, AccessedEntity::Member,
+ R.getNamingClass(), I.getPair(),
+ R.getBaseObjectType());
Entity.setDiag(diag::err_access);
CheckAccess(*this, R.getNameLoc(), Entity);
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 11c8e6d..ba7e1ff 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -47,11 +47,12 @@ static void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange,
CastExpr::CastKind &Kind,
- CXXMethodDecl *&ConversionDecl);
+ CXXBaseSpecifierArray &BasePath);
static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange,
const SourceRange &DestRange,
- CastExpr::CastKind &Kind);
+ CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath);
static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType);
@@ -69,39 +70,43 @@ static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType);
static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
QualType DestType, unsigned &msg);
static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr,
- QualType DestType, bool CStyle,
- const SourceRange &OpRange,
- unsigned &msg,
- CastExpr::CastKind &Kind);
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg,
+ CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath);
static TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
- CastExpr::CastKind &Kind);
+ CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath);
static TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType,
CanQualType DestType, bool CStyle,
const SourceRange &OpRange,
QualType OrigSrcType,
QualType OrigDestType, unsigned &msg,
- CastExpr::CastKind &Kind);
+ CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath);
static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr,
- QualType SrcType,
- QualType DestType,bool CStyle,
- const SourceRange &OpRange,
- unsigned &msg,
- CastExpr::CastKind &Kind);
+ QualType SrcType,
+ QualType DestType,bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg,
+ CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath);
+
static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
- CastExpr::CastKind &Kind,
- CXXMethodDecl *&ConversionDecl);
+ CastExpr::CastKind &Kind);
static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
CastExpr::CastKind &Kind,
- CXXMethodDecl *&ConversionDecl);
+ CXXBaseSpecifierArray &BasePath);
static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
bool CStyle, unsigned &msg);
static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
@@ -153,10 +158,12 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
case tok::kw_dynamic_cast: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ CXXBaseSpecifierArray BasePath;
if (!TypeDependent)
- CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind);
+ CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind, BasePath);
return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(),
- Kind, Ex, DestTInfo, OpLoc));
+ Kind, Ex, BasePath, DestTInfo,
+ OpLoc));
}
case tok::kw_reinterpret_cast: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
@@ -164,28 +171,18 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind);
return Owned(new (Context) CXXReinterpretCastExpr(
DestType.getNonReferenceType(),
- Kind, Ex, DestTInfo, OpLoc));
+ Kind, Ex, CXXBaseSpecifierArray(),
+ DestTInfo, OpLoc));
}
case tok::kw_static_cast: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
- if (!TypeDependent) {
- CXXMethodDecl *Method = 0;
-
- CheckStaticCast(*this, Ex, DestType, OpRange, Kind, Method);
-
- if (Method) {
- OwningExprResult CastArg
- = BuildCXXCastArgument(OpLoc, DestType.getNonReferenceType(),
- Kind, Method, Owned(Ex));
- if (CastArg.isInvalid())
- return ExprError();
-
- Ex = CastArg.takeAs<Expr>();
- }
- }
+ CXXBaseSpecifierArray BasePath;
+ if (!TypeDependent)
+ CheckStaticCast(*this, Ex, DestType, OpRange, Kind, BasePath);
return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(),
- Kind, Ex, DestTInfo, OpLoc));
+ Kind, Ex, BasePath,
+ DestTInfo, OpLoc));
}
}
@@ -290,7 +287,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
static void
CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange,
- const SourceRange &DestRange, CastExpr::CastKind &Kind) {
+ const SourceRange &DestRange, CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath) {
QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType();
DestType = Self.Context.getCanonicalType(DestType);
@@ -384,10 +382,12 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
// C++ 5.2.7p5
// Upcasts are resolved statically.
if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) {
- Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee,
- OpRange.getBegin(), OpRange);
+ if (Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee,
+ OpRange.getBegin(), OpRange,
+ &BasePath))
+ return;
+
Kind = CastExpr::CK_DerivedToBase;
- // Diagnostic already emitted on error.
return;
}
@@ -448,7 +448,7 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
void
CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange, CastExpr::CastKind &Kind,
- CXXMethodDecl *&ConversionDecl) {
+ CXXBaseSpecifierArray &BasePath) {
// This test is outside everything else because it's the only case where
// a non-lvalue-reference target type does not lead to decay.
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
@@ -462,8 +462,7 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
- Kind, ConversionDecl)
- != TC_Success && msg != 0)
+ Kind, BasePath) != TC_Success && msg != 0)
Self.Diag(OpRange.getBegin(), msg) << CT_Static
<< SrcExpr->getType() << DestType << OpRange;
}
@@ -475,7 +474,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange, unsigned &msg,
CastExpr::CastKind &Kind,
- CXXMethodDecl *&ConversionDecl) {
+ CXXBaseSpecifierArray &BasePath) {
// The order the tests is not entirely arbitrary. There is one conversion
// that can be handled in two different ways. Given:
// struct A {};
@@ -497,7 +496,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
// See the function for details.
// DR 427 specifies that this is to be applied before paragraph 2.
tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle, OpRange,
- msg, Kind);
+ msg, Kind, BasePath);
if (tcr != TC_NotApplicable)
return tcr;
@@ -512,7 +511,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
// C++ 5.2.9p2: An expression e can be explicitly converted to a type T
// [...] if the declaration "T t(e);" is well-formed, [...].
tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CStyle, OpRange, msg,
- Kind, ConversionDecl);
+ Kind);
if (tcr != TC_NotApplicable)
return tcr;
@@ -548,7 +547,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
// Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast.
// C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance.
tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg,
- Kind);
+ Kind, BasePath);
if (tcr != TC_NotApplicable)
return tcr;
@@ -556,7 +555,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
// conversion. C++ 5.2.9p9 has additional information.
// DR54's access restrictions apply here also.
tcr = TryStaticMemberPointerUpcast(Self, SrcExpr, SrcType, DestType, CStyle,
- OpRange, msg, Kind);
+ OpRange, msg, Kind, BasePath);
if (tcr != TC_NotApplicable)
return tcr;
@@ -630,7 +629,8 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
TryCastResult
TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
bool CStyle, const SourceRange &OpRange,
- unsigned &msg, CastExpr::CastKind &Kind) {
+ unsigned &msg, CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath) {
// C++ 5.2.9p5: An lvalue of type "cv1 B", where B is a class type, can be
// cast to type "reference to cv2 D", where D is a class derived from B,
// if a valid standard conversion from "pointer to D" to "pointer to B"
@@ -656,14 +656,16 @@ TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
return TryStaticDowncast(Self,
Self.Context.getCanonicalType(SrcExpr->getType()),
Self.Context.getCanonicalType(DestPointee), CStyle,
- OpRange, SrcExpr->getType(), DestType, msg, Kind);
+ OpRange, SrcExpr->getType(), DestType, msg, Kind,
+ BasePath);
}
/// Tests whether a conversion according to C++ 5.2.9p8 is valid.
TryCastResult
TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType,
bool CStyle, const SourceRange &OpRange,
- unsigned &msg, CastExpr::CastKind &Kind) {
+ unsigned &msg, CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath) {
// C++ 5.2.9p8: An rvalue of type "pointer to cv1 B", where B is a class
// type, can be converted to an rvalue of type "pointer to cv2 D", where D
// is a class derived from B, if a valid standard conversion from "pointer
@@ -686,7 +688,8 @@ TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType,
return TryStaticDowncast(Self,
Self.Context.getCanonicalType(SrcPointer->getPointeeType()),
Self.Context.getCanonicalType(DestPointer->getPointeeType()),
- CStyle, OpRange, SrcType, DestType, msg, Kind);
+ CStyle, OpRange, SrcType, DestType, msg, Kind,
+ BasePath);
}
/// TryStaticDowncast - Common functionality of TryStaticReferenceDowncast and
@@ -696,7 +699,7 @@ TryCastResult
TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
bool CStyle, const SourceRange &OpRange, QualType OrigSrcType,
QualType OrigDestType, unsigned &msg,
- CastExpr::CastKind &Kind) {
+ CastExpr::CastKind &Kind, CXXBaseSpecifierArray &BasePath) {
// We can only work with complete types. But don't complain if it doesn't work
if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, Self.PDiag(0)) ||
Self.RequireCompleteType(OpRange.getBegin(), DestType, Self.PDiag(0)))
@@ -707,7 +710,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
return TC_NotApplicable;
}
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/!CStyle,
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
if (!Self.IsDerivedFrom(DestType, SrcType, Paths)) {
return TC_NotApplicable;
@@ -787,6 +790,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
return TC_Failed;
}
+ Self.BuildBasePathArray(Paths, BasePath);
Kind = CastExpr::CK_BaseToDerived;
return TC_Success;
}
@@ -802,22 +806,25 @@ TryCastResult
TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
- unsigned &msg, CastExpr::CastKind &Kind) {
+ unsigned &msg, CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath) {
const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>();
if (!DestMemPtr)
return TC_NotApplicable;
bool WasOverloadedFunction = false;
DeclAccessPair FoundOverload;
- if (FunctionDecl *Fn
- = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false,
- FoundOverload)) {
- CXXMethodDecl *M = cast<CXXMethodDecl>(Fn);
- SrcType = Self.Context.getMemberPointerType(Fn->getType(),
- Self.Context.getTypeDeclType(M->getParent()).getTypePtr());
- WasOverloadedFunction = true;
+ if (SrcExpr->getType() == Self.Context.OverloadTy) {
+ if (FunctionDecl *Fn
+ = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false,
+ FoundOverload)) {
+ CXXMethodDecl *M = cast<CXXMethodDecl>(Fn);
+ SrcType = Self.Context.getMemberPointerType(Fn->getType(),
+ Self.Context.getTypeDeclType(M->getParent()).getTypePtr());
+ WasOverloadedFunction = true;
+ }
}
-
+
const MemberPointerType *SrcMemPtr = SrcType->getAs<MemberPointerType>();
if (!SrcMemPtr) {
msg = diag::err_bad_static_cast_member_pointer_nonmp;
@@ -832,7 +839,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
// B base of D
QualType SrcClass(SrcMemPtr->getClass(), 0);
QualType DestClass(DestMemPtr->getClass(), 0);
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/!CStyle,
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
if (!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) {
return TC_NotApplicable;
@@ -886,6 +893,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
}
}
+ Self.BuildBasePathArray(Paths, BasePath);
Kind = CastExpr::CK_DerivedToBaseMemberPointer;
return TC_Success;
}
@@ -898,8 +906,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
TryCastResult
TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
bool CStyle, const SourceRange &OpRange, unsigned &msg,
- CastExpr::CastKind &Kind,
- CXXMethodDecl *&ConversionDecl) {
+ CastExpr::CastKind &Kind) {
if (DestType->isRecordType()) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
diag::err_bad_dynamic_cast_incomplete)) {
@@ -907,71 +914,35 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
return TC_Failed;
}
}
-
- if (DestType->isReferenceType()) {
- // All reference bindings insert implicit casts above that do the actual
- // casting.
- Kind = CastExpr::CK_NoOp;
-
- // At this point of CheckStaticCast, if the destination is a reference,
- // this has to work. There is no other way that works.
- // On the other hand, if we're checking a C-style cast, we've still got
- // the reinterpret_cast way.
- InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
- InitializationKind InitKind = InitializationKind::CreateCast(OpRange,
- CStyle);
- InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1);
- if (InitSeq.getKind() == InitializationSequence::FailedSequence && CStyle)
- return TC_NotApplicable;
-
- Sema::OwningExprResult Result
- = InitSeq.Perform(Self, Entity, InitKind,
- Action::MultiExprArg(Self, (void**)&SrcExpr, 1));
- if (Result.isInvalid()) {
- msg = 0;
- return TC_Failed;
- }
-
- SrcExpr = Result.takeAs<Expr>();
- return TC_Success;
- }
-
- if (DestType->isRecordType()) {
- if (CXXConstructorDecl *Constructor
- = Self.TryInitializationByConstructor(DestType, &SrcExpr, 1,
- OpRange.getBegin(),
- InitializationKind::CreateDirect(OpRange.getBegin(),
- OpRange.getBegin(),
- OpRange.getEnd()))) {
- ConversionDecl = Constructor;
- Kind = CastExpr::CK_ConstructorConversion;
- return TC_Success;
- }
-
+
+ // At this point of CheckStaticCast, if the destination is a reference,
+ // this has to work. There is no other way that works.
+ // On the other hand, if we're checking a C-style cast, we've still got
+ // the reinterpret_cast way.
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
+ InitializationKind InitKind
+ = InitializationKind::CreateCast(/*FIXME:*/OpRange,
+ CStyle);
+ InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1);
+ if (InitSeq.getKind() == InitializationSequence::FailedSequence &&
+ (CStyle || !DestType->isReferenceType()))
return TC_NotApplicable;
+
+ Sema::OwningExprResult Result
+ = InitSeq.Perform(Self, Entity, InitKind,
+ Action::MultiExprArg(Self, (void**)&SrcExpr, 1));
+ if (Result.isInvalid()) {
+ msg = 0;
+ return TC_Failed;
}
-
- // FIXME: To get a proper error from invalid conversions here, we need to
- // reimplement more of this.
- // FIXME: This does not actually perform the conversion, and thus does not
- // check for ambiguity or access.
- ImplicitConversionSequence ICS =
- Self.TryImplicitConversion(SrcExpr, DestType,
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/true,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false,
- /*one of user provided casts*/true);
-
- if (ICS.isBad())
- return TC_NotApplicable;
-
- // The conversion is possible, so commit to it.
- Kind = CastExpr::CK_NoOp;
- msg = 0;
- return Self.PerformImplicitConversion(SrcExpr, DestType, ICS, Sema::AA_Casting,
- /*IgnoreBaseAccess*/CStyle) ?
- TC_Failed : TC_Success;
+
+ if (InitSeq.isConstructorInitialization())
+ Kind = CastExpr::CK_ConstructorConversion;
+ else
+ Kind = CastExpr::CK_NoOp;
+
+ SrcExpr = Result.takeAs<Expr>();
+ return TC_Success;
}
/// TryConstCast - See if a const_cast from source to destination is allowed,
@@ -1234,9 +1205,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
return TC_Success;
}
-bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
- CastExpr::CastKind &Kind, bool FunctionalStyle,
- CXXMethodDecl *&ConversionDecl) {
+bool
+Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
+ CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath,
+ bool FunctionalStyle) {
// This test is outside everything else because it's the only case where
// a non-lvalue-reference target type does not lead to decay.
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
@@ -1271,8 +1244,8 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
if (tcr == TC_NotApplicable) {
// ... or if that is not possible, a static_cast, ignoring const, ...
- tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg,
- Kind, ConversionDecl);
+ tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, Kind,
+ BasePath);
if (tcr == TC_NotApplicable) {
// ... and finally a reinterpret_cast, ignoring const.
tcr = TryReinterpretCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg,
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index c90f75e..c0ec9e9 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -24,61 +24,17 @@
using namespace clang;
/// \brief Find the current instantiation that associated with the given type.
-static CXXRecordDecl *
-getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext,
- QualType T) {
+static CXXRecordDecl *getCurrentInstantiationOf(QualType T) {
if (T.isNull())
return 0;
-
- T = Context.getCanonicalType(T).getUnqualifiedType();
-
- for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) {
- // If we've hit a namespace or the global scope, then the
- // nested-name-specifier can't refer to the current instantiation.
- if (Ctx->isFileContext())
- return 0;
-
- // Skip non-class contexts.
- CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx);
- if (!Record)
- continue;
-
- // If this record type is not dependent,
- if (!Record->isDependentType())
- return 0;
-
- // C++ [temp.dep.type]p1:
- //
- // In the definition of a class template, a nested class of a
- // class template, a member of a class template, or a member of a
- // nested class of a class template, a name refers to the current
- // instantiation if it is
- // -- the injected-class-name (9) of the class template or
- // nested class,
- // -- in the definition of a primary class template, the name
- // of the class template followed by the template argument
- // list of the primary template (as described below)
- // enclosed in <>,
- // -- in the definition of a nested class of a class template,
- // the name of the nested class referenced as a member of
- // the current instantiation, or
- // -- in the definition of a partial specialization, the name
- // of the class template followed by the template argument
- // list of the partial specialization enclosed in <>. If
- // the nth template parameter is a parameter pack, the nth
- // template argument is a pack expansion (14.6.3) whose
- // pattern is the name of the parameter pack.
- // (FIXME: parameter packs)
- //
- // All of these options come down to having the
- // nested-name-specifier type that is equivalent to the
- // injected-class-name of one of the types that is currently in
- // our context.
- if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T)
- return Record;
- }
-
- return 0;
+
+ const Type *Ty = T->getCanonicalTypeInternal().getTypePtr();
+ if (isa<RecordType>(Ty))
+ return cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
+ else if (isa<InjectedClassNameType>(Ty))
+ return cast<InjectedClassNameType>(Ty)->getDecl();
+ else
+ return 0;
}
/// \brief Compute the DeclContext that is associated with the given type.
@@ -92,7 +48,7 @@ DeclContext *Sema::computeDeclContext(QualType T) {
if (const TagType *Tag = T->getAs<TagType>())
return Tag->getDecl();
- return ::getCurrentInstantiationOf(Context, CurContext, T);
+ return ::getCurrentInstantiationOf(T);
}
/// \brief Compute the DeclContext that is associated with the given
@@ -218,7 +174,7 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
return 0;
QualType T = QualType(NNS->getAsType(), 0);
- return ::getCurrentInstantiationOf(Context, CurContext, T);
+ return ::getCurrentInstantiationOf(T);
}
/// \brief Require that the context specified by SS be complete.
@@ -230,11 +186,10 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
/// that is currently being defined. Or, if we have a type that names
/// a class template specialization that is not a complete type, we
/// will attempt to instantiate that class template.
-bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
- if (!SS.isSet() || SS.isInvalid())
- return false;
+bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
+ DeclContext *DC) {
+ assert(DC != 0 && "given null context");
- DeclContext *DC = computeDeclContext(SS, true);
if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
// If this is a dependent type, then we consider it complete.
if (Tag->isDependentContext())
@@ -247,10 +202,13 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
return false;
// The type must be complete.
- return RequireCompleteType(SS.getRange().getBegin(),
- Context.getTypeDeclType(Tag),
- PDiag(diag::err_incomplete_nested_name_spec)
- << SS.getRange());
+ if (RequireCompleteType(SS.getRange().getBegin(),
+ Context.getTypeDeclType(Tag),
+ PDiag(diag::err_incomplete_nested_name_spec)
+ << SS.getRange())) {
+ SS.setScopeRep(0); // Mark the ScopeSpec invalid.
+ return true;
+ }
}
return false;
@@ -322,7 +280,7 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
return 0;
}
-bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
+bool Sema::isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS,
SourceLocation IdLoc,
IdentifierInfo &II,
TypeTy *ObjectTypePtr) {
@@ -353,7 +311,8 @@ bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
// nested-name-specifier.
// The declaration context must be complete.
- if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
+ if (!LookupCtx->isDependentContext() &&
+ RequireCompleteDeclContext(SS, LookupCtx))
return false;
LookupQualifiedName(Found, LookupCtx);
@@ -384,7 +343,7 @@ bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
/// scope if it *knows* that the result is correct. It should not return in a
/// dependent context, for example.
Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
IdentifierInfo &II,
@@ -423,7 +382,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
// nested-name-specifier.
// The declaration context must be complete.
- if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
+ if (!LookupCtx->isDependentContext() &&
+ RequireCompleteDeclContext(SS, LookupCtx))
return 0;
LookupQualifiedName(Found, LookupCtx);
@@ -480,7 +440,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
// We haven't found anything, and we're not recovering from a
// different kind of error, so look for typos.
DeclarationName Name = Found.getLookupName();
- if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext) &&
+ if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext,
+ CTC_NoKeywords) &&
Found.isSingleResult() &&
isAcceptableNestedNameSpecifier(Found.getAsSingle<NamedDecl>())) {
if (LookupCtx)
@@ -593,7 +554,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
/// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
/// Returns a CXXScopeTy* object representing the C++ scope.
Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
IdentifierInfo &II,
@@ -611,7 +572,7 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
/// conservatively correct to always return false from this method.
///
/// The arguments are the same as those passed to ActOnCXXNestedNameSpecifier.
-bool Sema::IsInvalidUnlessNestedName(Scope *S, const CXXScopeSpec &SS,
+bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS,
IdentifierInfo &II, TypeTy *ObjectType,
bool EnteringContext) {
return BuildCXXNestedNameSpecifier(S, SS, SourceLocation(), SourceLocation(),
@@ -676,7 +637,7 @@ bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
/// looked up in the declarator-id's scope, until the declarator is parsed and
/// ActOnCXXExitDeclaratorScope is called.
/// The 'SS' should be a non-empty valid CXXScopeSpec.
-bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
+bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
if (SS.isInvalid()) return true;
@@ -686,10 +647,15 @@ bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
// Before we enter a declarator's context, we need to make sure that
// it is a complete declaration context.
- if (!DC->isDependentContext() && RequireCompleteDeclContext(SS))
+ if (!DC->isDependentContext() && RequireCompleteDeclContext(SS, DC))
return true;
EnterDeclaratorContext(S, DC);
+
+ // Rebuild the nested name specifier for the new scope.
+ if (DC->isDependentContext())
+ RebuildNestedNameSpecifierInCurrentInstantiation(SS);
+
return false;
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index f2520fc..7029711 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -26,6 +26,7 @@
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
+#include "clang/Basic/TargetBuiltins.h"
#include <limits>
using namespace clang;
@@ -155,14 +156,18 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return ExprError();
break;
case Builtin::BI__builtin_return_address:
- case Builtin::BI__builtin_frame_address:
- if (SemaBuiltinStackAddress(TheCall))
+ case Builtin::BI__builtin_frame_address: {
+ llvm::APSInt Result;
+ if (SemaBuiltinConstantArg(TheCall, 0, Result))
return ExprError();
break;
- case Builtin::BI__builtin_eh_return_data_regno:
- if (SemaBuiltinEHReturnDataRegNo(TheCall))
+ }
+ case Builtin::BI__builtin_eh_return_data_regno: {
+ llvm::APSInt Result;
+ if (SemaBuiltinConstantArg(TheCall, 0, Result))
return ExprError();
break;
+ }
case Builtin::BI__builtin_shufflevector:
return SemaBuiltinShuffleVector(TheCall);
// TheCall will be freed by the smart pointer here, but that's fine, since
@@ -196,6 +201,15 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (SemaBuiltinAtomicOverloaded(TheCall))
return ExprError();
break;
+
+ // Target specific builtins start here.
+ case X86::BI__builtin_ia32_palignr128:
+ case X86::BI__builtin_ia32_palignr: {
+ llvm::APSInt Result;
+ if (SemaBuiltinConstantArg(TheCall, 2, Result))
+ return ExprError();
+ break;
+ }
}
return move(TheCallResult);
@@ -270,8 +284,10 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
// Ensure that we have at least one argument to do type inference from.
if (TheCall->getNumArgs() < 1)
- return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
- << 0 << TheCall->getCallee()->getSourceRange();
+ return Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_few_args_at_least)
+ << 0 << 1 << TheCall->getNumArgs()
+ << TheCall->getCallee()->getSourceRange();
// Inspect the first argument of the atomic builtin. This should always be
// a pointer type, whose element is an integral scalar or pointer type.
@@ -367,8 +383,10 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
// Now that we know how many fixed arguments we expect, first check that we
// have at least that many.
if (TheCall->getNumArgs() < 1+NumFixed)
- return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
- << 0 << TheCall->getCallee()->getSourceRange();
+ return Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_few_args_at_least)
+ << 0 << 1+NumFixed << TheCall->getNumArgs()
+ << TheCall->getCallee()->getSourceRange();
// Get the decl for the concrete builtin from this, we can tell what the
@@ -405,9 +423,8 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
// GCC does an implicit conversion to the pointer or integer ValType. This
// can fail in some cases (1i -> int**), check for this error case now.
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
- CXXMethodDecl *ConversionDecl = 0;
- if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind,
- ConversionDecl))
+ CXXBaseSpecifierArray BasePath;
+ if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind, BasePath))
return true;
// Okay, we have something that *can* be converted to the right type. Check
@@ -416,7 +433,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
// pass in 42. The 42 gets converted to char. This is even more strange
// for things like 45.123 -> char, etc.
// FIXME: Do this check.
- ImpCastExprToType(Arg, ValType, Kind, /*isLvalue=*/false);
+ ImpCastExprToType(Arg, ValType, Kind);
TheCall->setArg(i+1, Arg);
}
@@ -476,15 +493,17 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
if (TheCall->getNumArgs() > 2) {
Diag(TheCall->getArg(2)->getLocStart(),
diag::err_typecheck_call_too_many_args)
- << 0 /*function call*/ << Fn->getSourceRange()
+ << 0 /*function call*/ << 2 << TheCall->getNumArgs()
+ << Fn->getSourceRange()
<< SourceRange(TheCall->getArg(2)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
return true;
}
if (TheCall->getNumArgs() < 2) {
- return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
- << 0 /*function call*/;
+ return Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_few_args_at_least)
+ << 0 /*function call*/ << 2 << TheCall->getNumArgs();
}
// Determine whether the current function is variadic or not.
@@ -492,15 +511,10 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
bool isVariadic;
if (CurBlock)
isVariadic = CurBlock->isVariadic;
- else if (getCurFunctionDecl()) {
- if (FunctionProtoType* FTP =
- dyn_cast<FunctionProtoType>(getCurFunctionDecl()->getType()))
- isVariadic = FTP->isVariadic();
- else
- isVariadic = false;
- } else {
+ else if (FunctionDecl *FD = getCurFunctionDecl())
+ isVariadic = FD->isVariadic();
+ else
isVariadic = getCurMethodDecl()->isVariadic();
- }
if (!isVariadic) {
Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function);
@@ -538,11 +552,11 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
if (TheCall->getNumArgs() < 2)
return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
- << 0 /*function call*/;
+ << 0 << 2 << TheCall->getNumArgs()/*function call*/;
if (TheCall->getNumArgs() > 2)
return Diag(TheCall->getArg(2)->getLocStart(),
diag::err_typecheck_call_too_many_args)
- << 0 /*function call*/
+ << 0 /*function call*/ << 2 << TheCall->getNumArgs()
<< SourceRange(TheCall->getArg(2)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
@@ -580,11 +594,11 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
if (TheCall->getNumArgs() < NumArgs)
return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
- << 0 /*function call*/;
+ << 0 << NumArgs << TheCall->getNumArgs()/*function call*/;
if (TheCall->getNumArgs() > NumArgs)
return Diag(TheCall->getArg(NumArgs)->getLocStart(),
diag::err_typecheck_call_too_many_args)
- << 0 /*function call*/
+ << 0 /*function call*/ << NumArgs << TheCall->getNumArgs()
<< SourceRange(TheCall->getArg(NumArgs)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
@@ -602,25 +616,14 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
return false;
}
-bool Sema::SemaBuiltinStackAddress(CallExpr *TheCall) {
- // The signature for these builtins is exact; the only thing we need
- // to check is that the argument is a constant.
- SourceLocation Loc;
- if (!TheCall->getArg(0)->isTypeDependent() &&
- !TheCall->getArg(0)->isValueDependent() &&
- !TheCall->getArg(0)->isIntegerConstantExpr(Context, &Loc))
- return Diag(Loc, diag::err_stack_const_level) << TheCall->getSourceRange();
-
- return false;
-}
-
/// SemaBuiltinShuffleVector - Handle __builtin_shufflevector.
// This is declared to take (...), so we have to check everything.
Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
if (TheCall->getNumArgs() < 3)
return ExprError(Diag(TheCall->getLocEnd(),
- diag::err_typecheck_call_too_few_args)
- << 0 /*function call*/ << TheCall->getSourceRange());
+ diag::err_typecheck_call_too_few_args_at_least)
+ << 0 /*function call*/ << 3 << TheCall->getNumArgs()
+ << TheCall->getSourceRange());
unsigned numElements = std::numeric_limits<unsigned>::max();
if (!TheCall->getArg(0)->isTypeDependent() &&
@@ -647,10 +650,14 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
if (TheCall->getNumArgs() < numElements+2)
return ExprError(Diag(TheCall->getLocEnd(),
diag::err_typecheck_call_too_few_args)
- << 0 /*function call*/ << TheCall->getSourceRange());
+ << 0 /*function call*/
+ << numElements+2 << TheCall->getNumArgs()
+ << TheCall->getSourceRange());
return ExprError(Diag(TheCall->getLocEnd(),
diag::err_typecheck_call_too_many_args)
- << 0 /*function call*/ << TheCall->getSourceRange());
+ << 0 /*function call*/
+ << numElements+2 << TheCall->getNumArgs()
+ << TheCall->getSourceRange());
}
}
@@ -659,11 +666,9 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
TheCall->getArg(i)->isValueDependent())
continue;
- llvm::APSInt Result(32);
- if (!TheCall->getArg(i)->isIntegerConstantExpr(Result, Context))
- return ExprError(Diag(TheCall->getLocStart(),
- diag::err_shufflevector_nonconstant_argument)
- << TheCall->getArg(i)->getSourceRange());
+ llvm::APSInt Result;
+ if (SemaBuiltinConstantArg(TheCall, i, Result))
+ return ExprError();
if (Result.getActiveBits() > 64 || Result.getZExtValue() >= numElements*2)
return ExprError(Diag(TheCall->getLocStart(),
@@ -691,30 +696,19 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
unsigned NumArgs = TheCall->getNumArgs();
if (NumArgs > 3)
- return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_many_args)
- << 0 /*function call*/ << TheCall->getSourceRange();
+ return Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_many_args_at_most)
+ << 0 /*function call*/ << 3 << NumArgs
+ << TheCall->getSourceRange();
// Argument 0 is checked for us and the remaining arguments must be
// constant integers.
for (unsigned i = 1; i != NumArgs; ++i) {
Expr *Arg = TheCall->getArg(i);
- if (Arg->isTypeDependent())
- continue;
-
- if (!Arg->getType()->isIntegralType())
- return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_arg_type)
- << Arg->getSourceRange();
-
- ImpCastExprToType(Arg, Context.IntTy, CastExpr::CK_IntegralCast);
- TheCall->setArg(i, Arg);
-
- if (Arg->isValueDependent())
- continue;
-
+
llvm::APSInt Result;
- if (!Arg->isIntegerConstantExpr(Result, Context))
- return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_arg_ice)
- << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
+ if (SemaBuiltinConstantArg(TheCall, i, Result))
+ return true;
// FIXME: gcc issues a warning and rewrites these to 0. These
// seems especially odd for the third argument since the default
@@ -733,42 +727,35 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
return false;
}
-/// SemaBuiltinEHReturnDataRegNo - Handle __builtin_eh_return_data_regno, the
-/// operand must be an integer constant.
-bool Sema::SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall) {
- llvm::APSInt Result;
- if (!TheCall->getArg(0)->isIntegerConstantExpr(Result, Context))
- return Diag(TheCall->getLocStart(), diag::err_expr_not_ice)
- << TheCall->getArg(0)->getSourceRange();
-
+/// SemaBuiltinConstantArg - Handle a check if argument ArgNum of CallExpr
+/// TheCall is a constant expression.
+bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
+ llvm::APSInt &Result) {
+ Expr *Arg = TheCall->getArg(ArgNum);
+ DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+ FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl());
+
+ if (Arg->isTypeDependent() || Arg->isValueDependent()) return false;
+
+ if (!Arg->isIntegerConstantExpr(Result, Context))
+ return Diag(TheCall->getLocStart(), diag::err_constant_integer_arg_type)
+ << FDecl->getDeclName() << Arg->getSourceRange();
+
return false;
}
-
/// SemaBuiltinObjectSize - Handle __builtin_object_size(void *ptr,
/// int type). This simply type checks that type is one of the defined
/// constants (0-3).
// For compatability check 0-3, llvm only handles 0 and 2.
bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
- Expr *Arg = TheCall->getArg(1);
- if (Arg->isTypeDependent())
- return false;
-
- QualType ArgType = Arg->getType();
- const BuiltinType *BT = ArgType->getAs<BuiltinType>();
- llvm::APSInt Result(32);
- if (!BT || BT->getKind() != BuiltinType::Int)
- return Diag(TheCall->getLocStart(), diag::err_object_size_invalid_argument)
- << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
-
- if (Arg->isValueDependent())
- return false;
-
- if (!Arg->isIntegerConstantExpr(Result, Context)) {
- return Diag(TheCall->getLocStart(), diag::err_object_size_invalid_argument)
- << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
- }
+ llvm::APSInt Result;
+
+ // Check constant-ness first.
+ if (SemaBuiltinConstantArg(TheCall, 1, Result))
+ return true;
+ Expr *Arg = TheCall->getArg(1);
if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3) {
return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
<< "0" << "3" << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
@@ -781,11 +768,13 @@ bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
/// This checks that val is a constant 1.
bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
Expr *Arg = TheCall->getArg(1);
- if (Arg->isTypeDependent() || Arg->isValueDependent())
- return false;
+ llvm::APSInt Result;
- llvm::APSInt Result(32);
- if (!Arg->isIntegerConstantExpr(Result, Context) || Result != 1)
+ // TODO: This is less than ideal. Overload this to take a value.
+ if (SemaBuiltinConstantArg(TheCall, 1, Result))
+ return true;
+
+ if (Result != 1)
return Diag(TheCall->getLocStart(), diag::err_builtin_longjmp_invalid_val)
<< SourceRange(Arg->getLocStart(), Arg->getLocEnd());
@@ -1885,6 +1874,17 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
// Left shift gets black-listed based on a judgement call.
case BinaryOperator::Shl:
+ // ...except that we want to treat '1 << (blah)' as logically
+ // positive. It's an important idiom.
+ if (IntegerLiteral *I
+ = dyn_cast<IntegerLiteral>(BO->getLHS()->IgnoreParenCasts())) {
+ if (I->getValue() == 1) {
+ IntRange R = IntRange::forType(C, E->getType());
+ return IntRange(R.Width, /*NonNegative*/ true);
+ }
+ }
+ // fallthrough
+
case BinaryOperator::ShlAssign:
return IntRange::forType(C, E->getType());
@@ -1945,6 +1945,10 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
return GetExprRange(C, UO->getSubExpr(), MaxWidth);
}
}
+
+ if (dyn_cast<OffsetOfExpr>(E)) {
+ IntRange::forType(C, E->getType());
+ }
FieldDecl *BitField = E->getBitField();
if (BitField) {
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index df14aa7..c075d16 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -13,12 +13,14 @@
#include "Sema.h"
#include "Lookup.h"
#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Sema/ExternalSemaSource.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
#include <list>
#include <map>
#include <vector>
@@ -413,6 +415,9 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND,
return false;
}
+
+ if (Filter == &ResultBuilder::IsNestedNameSpecifier)
+ AsNestedNameSpecifier = true;
// ... then it must be interesting!
return true;
@@ -502,7 +507,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
}
for (; I != IEnd; ++I) {
// A tag declaration does not hide a non-tag declaration.
- if (I->first->getIdentifierNamespace() == Decl::IDNS_Tag &&
+ if (I->first->hasTagIdentifierNamespace() &&
(IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
Decl::IDNS_ObjCProtocol)))
continue;
@@ -627,7 +632,7 @@ void ResultBuilder::ExitScope() {
bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
unsigned IDNS = Decl::IDNS_Ordinary;
if (SemaRef.getLangOptions().CPlusPlus)
- IDNS |= Decl::IDNS_Tag;
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace;
else if (SemaRef.getLangOptions().ObjC1 && isa<ObjCIvarDecl>(ND))
return true;
@@ -639,7 +644,7 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const {
unsigned IDNS = Decl::IDNS_Ordinary;
if (SemaRef.getLangOptions().CPlusPlus)
- IDNS |= Decl::IDNS_Tag;
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace;
return (ND->getIdentifierNamespace() & IDNS) &&
!isa<ValueDecl>(ND) && !isa<FunctionTemplateDecl>(ND);
@@ -882,7 +887,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddPlaceholderChunk("identifier");
Pattern->AddChunk(CodeCompletionString::CK_Equal);
Pattern->AddPlaceholderChunk("identifier");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
// Using directives
@@ -892,7 +896,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddTextChunk("namespace");
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("identifier");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
// asm(string-literal)
@@ -901,7 +904,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
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
@@ -909,7 +911,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddTypedTextChunk("template");
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("declaration");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
}
@@ -926,7 +927,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
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)
@@ -937,7 +937,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddTextChunk("typename");
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("qualified-id");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
}
@@ -1090,7 +1089,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
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 }
@@ -1116,7 +1114,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
// continue ;
Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("continue");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
}
@@ -1124,7 +1121,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
// break ;
Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("break");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
}
@@ -1145,7 +1141,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("expression");
}
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
// goto identifier ;
@@ -1153,7 +1148,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddTypedTextChunk("goto");
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("identifier");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
// Using directives
@@ -1163,7 +1157,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddTextChunk("namespace");
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("identifier");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
}
@@ -2075,10 +2068,6 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
Results.ExitScope();
- // Add macros
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
-
// Hand off the results found for code completion.
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2108,13 +2097,17 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
return;
}
- ResultBuilder Results(*this, Filter);
- Results.allowNestedNameSpecifiers();
+ ResultBuilder Results(*this);
CodeCompletionDeclConsumer Consumer(Results, CurContext);
+
+ // First pass: look for tags.
+ Results.setFilter(Filter);
LookupVisibleDecls(S, LookupTagName, Consumer);
+
+ // Second pass: look for nested name specifiers.
+ Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
+ LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer);
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2192,7 +2185,7 @@ void Sema::CodeCompleteCase(Scope *S) {
CurContext, 0, false);
}
Results.ExitScope();
-
+
if (CodeCompleter->includeMacros())
AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
@@ -2258,7 +2251,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
// FIXME: access?
AddOverloadCandidate(FDecl, DeclAccessPair::make(FDecl, AS_none),
Args, NumArgs, CandidateSet,
- false, false, /*PartialOverloading*/ true);
+ false, /*PartialOverloading*/true);
}
}
@@ -2276,14 +2269,13 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
}
}
- if (Results.empty())
- CodeCompleteOrdinaryName(S, CCC_Expression);
- else
+ CodeCompleteOrdinaryName(S, CCC_Expression);
+ if (!Results.empty())
CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(),
Results.size());
}
-void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
+void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
bool EnteringContext) {
if (!SS.getScopeRep() || !CodeCompleter)
return;
@@ -2294,7 +2286,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
// Try to instantiate any non-dependent declaration contexts before
// we look in them.
- if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS))
+ if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS, Ctx))
return;
ResultBuilder Results(*this);
@@ -2307,8 +2299,6 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
if (!Results.empty() && NNS->isDependent())
Results.AddResult("template");
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2329,8 +2319,6 @@ void Sema::CodeCompleteUsing(Scope *S) {
LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
Results.ExitScope();
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2345,8 +2333,6 @@ void Sema::CodeCompleteUsingDirective(Scope *S) {
CodeCompletionDeclConsumer Consumer(Results, CurContext);
LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
Results.ExitScope();
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2381,8 +2367,6 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) {
Results.ExitScope();
}
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2394,8 +2378,6 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) {
ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias);
CodeCompletionDeclConsumer Consumer(Results, CurContext);
LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2422,8 +2404,6 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
AddTypeSpecifierResults(getLangOptions(), Results);
Results.ExitScope();
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2484,7 +2464,6 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
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
@@ -2593,7 +2572,6 @@ static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) {
Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,throw));
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
// @synchronized ( expression ) { statements }
@@ -2908,70 +2886,198 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S, DeclPtrTy ObjCImplDecl,
HandleCodeCompleteResults(this, CodeCompleter,Results.data(),Results.size());
}
-void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName,
- SourceLocation FNameLoc,
+/// \brief When we have an expression with type "id", we may assume
+/// that it has some more-specific class type based on knowledge of
+/// common uses of Objective-C. This routine returns that class type,
+/// or NULL if no better result could be determined.
+static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
+ ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E);
+ if (!Msg)
+ return 0;
+
+ Selector Sel = Msg->getSelector();
+ if (Sel.isNull())
+ return 0;
+
+ IdentifierInfo *Id = Sel.getIdentifierInfoForSlot(0);
+ if (!Id)
+ return 0;
+
+ ObjCMethodDecl *Method = Msg->getMethodDecl();
+ if (!Method)
+ return 0;
+
+ // Determine the class that we're sending the message to.
+ ObjCInterfaceDecl *IFace = 0;
+ switch (Msg->getReceiverKind()) {
+ case ObjCMessageExpr::Class:
+ if (const ObjCInterfaceType *IFaceType
+ = Msg->getClassReceiver()->getAs<ObjCInterfaceType>())
+ IFace = IFaceType->getDecl();
+ break;
+
+ case ObjCMessageExpr::Instance: {
+ QualType T = Msg->getInstanceReceiver()->getType();
+ if (const ObjCObjectPointerType *Ptr = T->getAs<ObjCObjectPointerType>())
+ IFace = Ptr->getInterfaceDecl();
+ break;
+ }
+
+ case ObjCMessageExpr::SuperInstance:
+ case ObjCMessageExpr::SuperClass:
+ break;
+ }
+
+ if (!IFace)
+ return 0;
+
+ ObjCInterfaceDecl *Super = IFace->getSuperClass();
+ if (Method->isInstanceMethod())
+ return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName())
+ .Case("retain", IFace)
+ .Case("autorelease", IFace)
+ .Case("copy", IFace)
+ .Case("copyWithZone", IFace)
+ .Case("mutableCopy", IFace)
+ .Case("mutableCopyWithZone", IFace)
+ .Case("awakeFromCoder", IFace)
+ .Case("replacementObjectFromCoder", IFace)
+ .Case("class", IFace)
+ .Case("classForCoder", IFace)
+ .Case("superclass", Super)
+ .Default(0);
+
+ return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName())
+ .Case("new", IFace)
+ .Case("alloc", IFace)
+ .Case("allocWithZone", IFace)
+ .Case("class", IFace)
+ .Case("superclass", Super)
+ .Default(0);
+}
+
+void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
IdentifierInfo **SelIdents,
unsigned NumSelIdents) {
- typedef CodeCompleteConsumer::Result Result;
ObjCInterfaceDecl *CDecl = 0;
+ if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) {
+ // Figure out which interface we're in.
+ CDecl = CurMethod->getClassInterface();
+ if (!CDecl)
+ return;
+
+ // Find the superclass of this class.
+ CDecl = CDecl->getSuperClass();
+ if (!CDecl)
+ return;
- if (FName->isStr("super")) {
- // We're sending a message to "super".
- if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) {
- // Figure out which interface we're in.
- CDecl = CurMethod->getClassInterface();
- if (!CDecl)
- return;
-
- // Find the superclass of this class.
- CDecl = CDecl->getSuperClass();
- if (!CDecl)
- return;
+ if (CurMethod->isInstanceMethod()) {
+ // We are inside an instance method, which means that the message
+ // send [super ...] is actually calling an instance method on the
+ // current object. Build the super expression and handle this like
+ // an instance method.
+ QualType SuperTy = Context.getObjCInterfaceType(CDecl);
+ SuperTy = Context.getObjCObjectPointerType(SuperTy);
+ OwningExprResult Super
+ = Owned(new (Context) ObjCSuperExpr(SuperLoc, SuperTy));
+ return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(),
+ SelIdents, NumSelIdents);
+ }
- if (CurMethod->isInstanceMethod()) {
- // We are inside an instance method, which means that the message
- // send [super ...] is actually calling an instance method on the
- // current object. Build the super expression and handle this like
- // an instance method.
- QualType SuperTy = Context.getObjCInterfaceType(CDecl);
- SuperTy = Context.getObjCObjectPointerType(SuperTy);
- OwningExprResult Super
- = Owned(new (Context) ObjCSuperExpr(FNameLoc, SuperTy));
- return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(),
- SelIdents, NumSelIdents);
- }
+ // Fall through to send to the superclass in CDecl.
+ } else {
+ // "super" may be the name of a type or variable. Figure out which
+ // it is.
+ IdentifierInfo *Super = &Context.Idents.get("super");
+ NamedDecl *ND = LookupSingleName(S, Super, SuperLoc,
+ LookupOrdinaryName);
+ if ((CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(ND))) {
+ // "super" names an interface. Use it.
+ } else if (TypeDecl *TD = dyn_cast_or_null<TypeDecl>(ND)) {
+ if (const ObjCInterfaceType *Iface
+ = Context.getTypeDeclType(TD)->getAs<ObjCInterfaceType>())
+ CDecl = Iface->getDecl();
+ } else if (ND && isa<UnresolvedUsingTypenameDecl>(ND)) {
+ // "super" names an unresolved type; we can't be more specific.
+ } else {
+ // Assume that "super" names some kind of value and parse that way.
+ CXXScopeSpec SS;
+ UnqualifiedId id;
+ id.setIdentifier(Super, SuperLoc);
+ OwningExprResult SuperExpr = ActOnIdExpression(S, SS, id, false, false);
+ return CodeCompleteObjCInstanceMessage(S, (Expr *)SuperExpr.get(),
+ SelIdents, NumSelIdents);
+ }
- // Okay, we're calling a factory method in our superclass.
- }
+ // Fall through
}
+ TypeTy *Receiver = 0;
+ if (CDecl)
+ Receiver = Context.getObjCInterfaceType(CDecl).getAsOpaquePtr();
+ return CodeCompleteObjCClassMessage(S, Receiver, SelIdents,
+ NumSelIdents);
+}
+
+void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver,
+ IdentifierInfo **SelIdents,
+ unsigned NumSelIdents) {
+ typedef CodeCompleteConsumer::Result Result;
+ ObjCInterfaceDecl *CDecl = 0;
+
// If the given name refers to an interface type, retrieve the
// corresponding declaration.
- if (!CDecl)
- if (TypeTy *Ty = getTypeName(*FName, FNameLoc, S, 0, false)) {
- QualType T = GetTypeFromParser(Ty, 0);
- if (!T.isNull())
- if (const ObjCInterfaceType *Interface = T->getAs<ObjCInterfaceType>())
- CDecl = Interface->getDecl();
- }
-
- if (!CDecl && FName->isStr("super")) {
- // "super" may be the name of a variable, in which case we are
- // probably calling an instance method.
- CXXScopeSpec SS;
- UnqualifiedId id;
- id.setIdentifier(FName, FNameLoc);
- OwningExprResult Super = ActOnIdExpression(S, SS, id, false, false);
- return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(),
- SelIdents, NumSelIdents);
+ if (Receiver) {
+ QualType T = GetTypeFromParser(Receiver, 0);
+ if (!T.isNull())
+ if (const ObjCInterfaceType *Interface = T->getAs<ObjCInterfaceType>())
+ CDecl = Interface->getDecl();
}
// Add all of the factory methods in this Objective-C class, its protocols,
// superclasses, categories, implementation, etc.
ResultBuilder Results(*this);
Results.EnterNewScope();
- AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext,
- Results);
+
+ if (CDecl)
+ AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext,
+ Results);
+ else {
+ // We're messaging "id" as a type; provide all class/factory methods.
+
+ // If we have an external source, load the entire class method
+ // pool from the PCH file.
+ if (ExternalSource) {
+ for (uint32_t I = 0, N = ExternalSource->GetNumKnownSelectors(); I != N;
+ ++I) {
+ Selector Sel = ExternalSource->GetSelector(I);
+ if (Sel.isNull() || FactoryMethodPool.count(Sel) ||
+ InstanceMethodPool.count(Sel))
+ continue;
+
+ ReadMethodPool(Sel, /*isInstance=*/false);
+ }
+ }
+
+ for (llvm::DenseMap<Selector, ObjCMethodList>::iterator
+ M = FactoryMethodPool.begin(),
+ MEnd = FactoryMethodPool.end();
+ M != MEnd;
+ ++M) {
+ for (ObjCMethodList *MethList = &M->second; MethList && MethList->Method;
+ MethList = MethList->Next) {
+ if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents,
+ NumSelIdents))
+ continue;
+
+ Result R(MethList->Method, 0);
+ R.StartParameter = NumSelIdents;
+ R.AllParametersAreInformative = false;
+ Results.MaybeAddResult(R, CurContext);
+ }
+ }
+ }
+
Results.ExitScope();
// This also suppresses remaining diagnostics.
@@ -2990,15 +3096,17 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
DefaultFunctionArrayLvalueConversion(RecExpr);
QualType ReceiverType = RecExpr->getType();
- if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType()) {
- // FIXME: We're messaging 'id'. Do we actually want to look up every method
- // in the universe?
- return;
- }
-
// Build the set of methods we can see.
ResultBuilder Results(*this);
Results.EnterNewScope();
+
+ // If we're messaging an expression with type "id" or "Class", check
+ // whether we know something special about the receiver that allows
+ // us to assume a more-specific receiver type.
+ if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType())
+ if (ObjCInterfaceDecl *IFace = GetAssumedMessageSendExprType(RecExpr))
+ ReceiverType = Context.getObjCObjectPointerType(
+ Context.getObjCInterfaceType(IFace));
// Handle messages to Class. This really isn't a message to an instance
// method, so we treat it the same way we would treat a message send to a
@@ -3035,7 +3143,44 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
AddObjCMethods(*I, true, MK_Any, SelIdents, NumSelIdents, CurContext,
Results);
}
-
+ // Handle messages to "id".
+ else if (ReceiverType->isObjCIdType()) {
+ // We're messaging "id", so provide all instance methods we know
+ // about as code-completion results.
+
+ // If we have an external source, load the entire class method
+ // pool from the PCH file.
+ if (ExternalSource) {
+ for (uint32_t I = 0, N = ExternalSource->GetNumKnownSelectors(); I != N;
+ ++I) {
+ Selector Sel = ExternalSource->GetSelector(I);
+ if (Sel.isNull() || InstanceMethodPool.count(Sel) ||
+ FactoryMethodPool.count(Sel))
+ continue;
+
+ ReadMethodPool(Sel, /*isInstance=*/true);
+ }
+ }
+
+ for (llvm::DenseMap<Selector, ObjCMethodList>::iterator
+ M = InstanceMethodPool.begin(),
+ MEnd = InstanceMethodPool.end();
+ M != MEnd;
+ ++M) {
+ for (ObjCMethodList *MethList = &M->second; MethList && MethList->Method;
+ MethList = MethList->Next) {
+ if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents,
+ NumSelIdents))
+ continue;
+
+ Result R(MethList->Method, 0);
+ R.StartParameter = NumSelIdents;
+ R.AllParametersAreInformative = false;
+ Results.MaybeAddResult(R, CurContext);
+ }
+ }
+ }
+
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -3076,7 +3221,8 @@ void Sema::CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols,
// Tell the result set to ignore all of the protocols we have
// already seen.
for (unsigned I = 0; I != NumProtocols; ++I)
- if (ObjCProtocolDecl *Protocol = LookupProtocol(Protocols[I].first))
+ if (ObjCProtocolDecl *Protocol = LookupProtocol(Protocols[I].first,
+ Protocols[I].second))
Results.Ignore(Protocol);
// Add all protocols.
@@ -3140,13 +3286,14 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) {
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
-void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName) {
+void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName,
+ SourceLocation ClassNameLoc) {
ResultBuilder Results(*this);
Results.EnterNewScope();
// Make sure that we ignore the class we're currently defining.
NamedDecl *CurClass
- = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
+ = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName);
if (CurClass && isa<ObjCInterfaceDecl>(CurClass))
Results.Ignore(CurClass);
@@ -3171,7 +3318,8 @@ void Sema::CodeCompleteObjCImplementationDecl(Scope *S) {
}
void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
- IdentifierInfo *ClassName) {
+ IdentifierInfo *ClassName,
+ SourceLocation ClassNameLoc) {
typedef CodeCompleteConsumer::Result Result;
ResultBuilder Results(*this);
@@ -3180,7 +3328,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
// interface.
llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames;
NamedDecl *CurClass
- = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
+ = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName);
if (ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass))
for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category;
Category = Category->getNextClassCategory())
@@ -3201,17 +3349,18 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
}
void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
- IdentifierInfo *ClassName) {
+ IdentifierInfo *ClassName,
+ SourceLocation ClassNameLoc) {
typedef CodeCompleteConsumer::Result Result;
// Find the corresponding interface. If we couldn't find the interface, the
// program itself is ill-formed. However, we'll try to be helpful still by
// providing the list of all of the categories we know about.
NamedDecl *CurClass
- = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
+ = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName);
ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass);
if (!Class)
- return CodeCompleteObjCInterfaceCategory(S, ClassName);
+ return CodeCompleteObjCInterfaceCategory(S, ClassName, ClassNameLoc);
ResultBuilder Results(*this);
@@ -3306,3 +3455,224 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
+
+typedef llvm::DenseMap<Selector, ObjCMethodDecl *> KnownMethodsMap;
+
+/// \brief Find all of the methods that reside in the given container
+/// (and its superclasses, protocols, etc.) that meet the given
+/// criteria. Insert those methods into the map of known methods,
+/// indexed by selector so they can be easily found.
+static void FindImplementableMethods(ASTContext &Context,
+ ObjCContainerDecl *Container,
+ bool WantInstanceMethods,
+ QualType ReturnType,
+ bool IsInImplementation,
+ KnownMethodsMap &KnownMethods) {
+ if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)) {
+ // Recurse into protocols.
+ const ObjCList<ObjCProtocolDecl> &Protocols
+ = IFace->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end();
+ I != E; ++I)
+ FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType,
+ IsInImplementation, KnownMethods);
+
+ // If we're not in the implementation of a class, also visit the
+ // superclass.
+ if (!IsInImplementation && IFace->getSuperClass())
+ FindImplementableMethods(Context, IFace->getSuperClass(),
+ WantInstanceMethods, ReturnType,
+ IsInImplementation, KnownMethods);
+
+ // Add methods from any class extensions (but not from categories;
+ // those should go into category implementations).
+ for (ObjCCategoryDecl *Cat = IFace->getCategoryList(); Cat;
+ Cat = Cat->getNextClassCategory()) {
+ if (!Cat->IsClassExtension())
+ continue;
+
+ FindImplementableMethods(Context, Cat, WantInstanceMethods, ReturnType,
+ IsInImplementation, KnownMethods);
+ }
+ }
+
+ if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
+ // Recurse into protocols.
+ const ObjCList<ObjCProtocolDecl> &Protocols
+ = Category->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end();
+ I != E; ++I)
+ FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType,
+ IsInImplementation, KnownMethods);
+ }
+
+ if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
+ // Recurse into protocols.
+ const ObjCList<ObjCProtocolDecl> &Protocols
+ = Protocol->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end();
+ I != E; ++I)
+ FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType,
+ IsInImplementation, KnownMethods);
+ }
+
+ // Add methods in this container. This operation occurs last because
+ // we want the methods from this container to override any methods
+ // we've previously seen with the same selector.
+ for (ObjCContainerDecl::method_iterator M = Container->meth_begin(),
+ MEnd = Container->meth_end();
+ M != MEnd; ++M) {
+ if ((*M)->isInstanceMethod() == WantInstanceMethods) {
+ if (!ReturnType.isNull() &&
+ !Context.hasSameUnqualifiedType(ReturnType, (*M)->getResultType()))
+ continue;
+
+ KnownMethods[(*M)->getSelector()] = *M;
+ }
+ }
+}
+
+void Sema::CodeCompleteObjCMethodDecl(Scope *S,
+ bool IsInstanceMethod,
+ TypeTy *ReturnTy,
+ DeclPtrTy IDecl) {
+ // Determine the return type of the method we're declaring, if
+ // provided.
+ QualType ReturnType = GetTypeFromParser(ReturnTy);
+
+ // Determine where we should start searching for methods, and where we
+ ObjCContainerDecl *SearchDecl = 0, *CurrentDecl = 0;
+ bool IsInImplementation = false;
+ if (Decl *D = IDecl.getAs<Decl>()) {
+ if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(D)) {
+ SearchDecl = Impl->getClassInterface();
+ CurrentDecl = Impl;
+ IsInImplementation = true;
+ } else if (ObjCCategoryImplDecl *CatImpl
+ = dyn_cast<ObjCCategoryImplDecl>(D)) {
+ SearchDecl = CatImpl->getCategoryDecl();
+ CurrentDecl = CatImpl;
+ IsInImplementation = true;
+ } else {
+ SearchDecl = dyn_cast<ObjCContainerDecl>(D);
+ CurrentDecl = SearchDecl;
+ }
+ }
+
+ if (!SearchDecl && S) {
+ if (DeclContext *DC = static_cast<DeclContext *>(S->getEntity())) {
+ SearchDecl = dyn_cast<ObjCContainerDecl>(DC);
+ CurrentDecl = SearchDecl;
+ }
+ }
+
+ if (!SearchDecl || !CurrentDecl) {
+ HandleCodeCompleteResults(this, CodeCompleter, 0, 0);
+ return;
+ }
+
+ // Find all of the methods that we could declare/implement here.
+ KnownMethodsMap KnownMethods;
+ FindImplementableMethods(Context, SearchDecl, IsInstanceMethod,
+ ReturnType, IsInImplementation, KnownMethods);
+
+ // Erase any methods that have already been declared or
+ // implemented here.
+ for (ObjCContainerDecl::method_iterator M = CurrentDecl->meth_begin(),
+ MEnd = CurrentDecl->meth_end();
+ M != MEnd; ++M) {
+ if ((*M)->isInstanceMethod() != IsInstanceMethod)
+ continue;
+
+ KnownMethodsMap::iterator Pos = KnownMethods.find((*M)->getSelector());
+ if (Pos != KnownMethods.end())
+ KnownMethods.erase(Pos);
+ }
+
+ // Add declarations or definitions for each of the known methods.
+ typedef CodeCompleteConsumer::Result Result;
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ PrintingPolicy Policy(Context.PrintingPolicy);
+ Policy.AnonymousTagLocations = false;
+ for (KnownMethodsMap::iterator M = KnownMethods.begin(),
+ MEnd = KnownMethods.end();
+ M != MEnd; ++M) {
+ ObjCMethodDecl *Method = M->second;
+ CodeCompletionString *Pattern = new CodeCompletionString;
+
+ // If the result type was not already provided, add it to the
+ // pattern as (type).
+ if (ReturnType.isNull()) {
+ std::string TypeStr;
+ Method->getResultType().getAsStringInternal(TypeStr, Policy);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddTextChunk(TypeStr);
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ }
+
+ Selector Sel = Method->getSelector();
+
+ // Add the first part of the selector to the pattern.
+ Pattern->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName());
+
+ // Add parameters to the pattern.
+ unsigned I = 0;
+ for (ObjCMethodDecl::param_iterator P = Method->param_begin(),
+ PEnd = Method->param_end();
+ P != PEnd; (void)++P, ++I) {
+ // Add the part of the selector name.
+ if (I == 0)
+ Pattern->AddChunk(CodeCompletionString::CK_Colon);
+ else if (I < Sel.getNumArgs()) {
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk(Sel.getIdentifierInfoForSlot(1)->getName());
+ Pattern->AddChunk(CodeCompletionString::CK_Colon);
+ } else
+ break;
+
+ // Add the parameter type.
+ std::string TypeStr;
+ (*P)->getOriginalType().getAsStringInternal(TypeStr, Policy);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddTextChunk(TypeStr);
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+
+ if (IdentifierInfo *Id = (*P)->getIdentifier())
+ Pattern->AddTextChunk(Id->getName());
+ }
+
+ if (Method->isVariadic()) {
+ if (Method->param_size() > 0)
+ Pattern->AddChunk(CodeCompletionString::CK_Comma);
+ Pattern->AddTextChunk("...");
+ }
+
+ if (IsInImplementation) {
+ // We will be defining the method here, so add a compound statement.
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ if (!Method->getResultType()->isVoidType()) {
+ // If the result type is not void, add a return clause.
+ Pattern->AddTextChunk("return");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ } else
+ Pattern->AddPlaceholderChunk("statements");
+
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ }
+
+ Results.AddResult(Result(Pattern));
+ }
+
+ Results.ExitScope();
+
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 541c271..0e839a9 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -61,7 +61,7 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(DeclPtrTy Ptr) {
/// If name lookup results in an ambiguity, this routine will complain
/// and then return NULL.
Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
- Scope *S, const CXXScopeSpec *SS,
+ Scope *S, CXXScopeSpec *SS,
bool isClassName,
TypeTy *ObjectTypePtr) {
// Determine where we will perform name lookup.
@@ -70,7 +70,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
if (ObjectType->isRecordType())
LookupCtx = computeDeclContext(ObjectType);
- } else if (SS && SS->isSet()) {
+ } else if (SS && SS->isNotEmpty()) {
LookupCtx = computeDeclContext(*SS, false);
if (!LookupCtx) {
@@ -89,16 +89,16 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
// We know from the grammar that this name refers to a type, so build a
// DependentNameType node to describe the type.
- // FIXME: Record somewhere that this DependentNameType node has no "typename"
- // keyword associated with it.
- return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(),
+ return CheckTypenameType(ETK_None,
+ (NestedNameSpecifier *)SS->getScopeRep(),
II, SS->getRange()).getAsOpaquePtr();
}
return 0;
}
- if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS))
+ if (!LookupCtx->isDependentContext() &&
+ RequireCompleteDeclContext(*SS, LookupCtx))
return 0;
}
@@ -236,7 +236,7 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
SourceLocation IILoc,
Scope *S,
- const CXXScopeSpec *SS,
+ CXXScopeSpec *SS,
TypeTy *&SuggestedType) {
// We don't have anything to suggest (yet).
SuggestedType = 0;
@@ -246,31 +246,53 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
LookupResult Lookup(*this, &II, IILoc, LookupOrdinaryName,
NotForRedeclaration);
- // FIXME: It would be nice if we could correct for typos in built-in
- // names, such as "itn" for "int".
-
- if (CorrectTypo(Lookup, S, SS) && Lookup.isSingleResult()) {
- NamedDecl *Result = Lookup.getAsSingle<NamedDecl>();
- if ((isa<TypeDecl>(Result) || isa<ObjCInterfaceDecl>(Result)) &&
- !Result->isInvalidDecl()) {
- // We found a similarly-named type or interface; suggest that.
- if (!SS || !SS->isSet())
- Diag(IILoc, diag::err_unknown_typename_suggest)
- << &II << Lookup.getLookupName()
- << FixItHint::CreateReplacement(SourceRange(IILoc),
- Result->getNameAsString());
- else if (DeclContext *DC = computeDeclContext(*SS, false))
- Diag(IILoc, diag::err_unknown_nested_typename_suggest)
- << &II << DC << Lookup.getLookupName() << SS->getRange()
- << FixItHint::CreateReplacement(SourceRange(IILoc),
- Result->getNameAsString());
- else
- llvm_unreachable("could not have corrected a typo here");
+ if (DeclarationName Corrected = CorrectTypo(Lookup, S, SS, 0, 0, CTC_Type)) {
+ if (NamedDecl *Result = Lookup.getAsSingle<NamedDecl>()) {
+ if ((isa<TypeDecl>(Result) || isa<ObjCInterfaceDecl>(Result)) &&
+ !Result->isInvalidDecl()) {
+ // We found a similarly-named type or interface; suggest that.
+ if (!SS || !SS->isSet())
+ Diag(IILoc, diag::err_unknown_typename_suggest)
+ << &II << Lookup.getLookupName()
+ << FixItHint::CreateReplacement(SourceRange(IILoc),
+ Result->getNameAsString());
+ else if (DeclContext *DC = computeDeclContext(*SS, false))
+ Diag(IILoc, diag::err_unknown_nested_typename_suggest)
+ << &II << DC << Lookup.getLookupName() << SS->getRange()
+ << FixItHint::CreateReplacement(SourceRange(IILoc),
+ Result->getNameAsString());
+ 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);
+ Diag(Result->getLocation(), diag::note_previous_decl)
+ << Result->getDeclName();
+
+ SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS);
+ return true;
+ }
+ } else if (Lookup.empty()) {
+ // We corrected to a keyword.
+ // FIXME: Actually recover with the keyword we suggest, and emit a fix-it.
+ Diag(IILoc, diag::err_unknown_typename_suggest)
+ << &II << Corrected;
+ return true;
+ }
+ }
+
+ if (getLangOptions().CPlusPlus) {
+ // See if II is a class template that the user forgot to pass arguments to.
+ UnqualifiedId Name;
+ Name.setIdentifier(&II, IILoc);
+ CXXScopeSpec EmptySS;
+ TemplateTy TemplateResult;
+ if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult)
+ == TNK_Type_template) {
+ TemplateName TplName = TemplateResult.getAsVal<TemplateName>();
+ Diag(IILoc, diag::err_template_missing_args) << TplName;
+ if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) {
+ Diag(TplDecl->getLocation(), diag::note_template_decl_here)
+ << TplDecl->getTemplateParameters()->getSourceRange();
+ }
return true;
}
}
@@ -522,6 +544,11 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false;
}
+ // If we failed to complete the type for some reason, don't
+ // diagnose the variable.
+ if (Ty->isIncompleteType())
+ return false;
+
if (const TagType *TT = Ty->getAs<TagType>()) {
const TagDecl *Tag = TT->getDecl();
if (Tag->hasAttr<UnusedAttr>())
@@ -558,40 +585,48 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
// Diagnose unused variables in this scope.
if (ShouldDiagnoseUnusedDecl(D) &&
- S->getNumErrorsAtStart() == getDiagnostics().getNumErrors())
- Diag(D->getLocation(), diag::warn_unused_variable) << D->getDeclName();
-
+ S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) {
+ if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable())
+ Diag(D->getLocation(), diag::warn_unused_exception_param)
+ << D->getDeclName();
+ else
+ Diag(D->getLocation(), diag::warn_unused_variable)
+ << D->getDeclName();
+ }
// Remove this name from our lexical scope.
IdResolver.RemoveDecl(D);
}
}
-/// getObjCInterfaceDecl - Look up a for a class declaration in the scope.
-/// return 0 if one not found.
+/// \brief Look for an Objective-C class in the translation unit.
///
-/// \param Id the name of the Objective-C class we're looking for. If
+/// \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.
+/// \param IdLoc The location of the name in the translation unit.
+///
+/// \param TypoCorrection If true, this routine will attempt typo correction
+/// if there is no class with the given name.
+///
+/// \returns The declaration of the named Objective-C class, or NULL if the
+/// class could not be found.
ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
- SourceLocation RecoverLoc) {
+ SourceLocation IdLoc,
+ bool TypoCorrection) {
// The third "scope" argument is 0 since we aren't enabling lazy built-in
// creation from this context.
- NamedDecl *IDecl = LookupSingleName(TUScope, Id, LookupOrdinaryName);
+ NamedDecl *IDecl = LookupSingleName(TUScope, Id, IdLoc, LookupOrdinaryName);
- if (!IDecl && !RecoverLoc.isInvalid()) {
+ if (!IDecl && TypoCorrection) {
// 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) &&
+ LookupResult R(*this, Id, IdLoc, LookupOrdinaryName);
+ if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
(IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
- Diag(RecoverLoc, diag::err_undef_interface_suggest)
+ Diag(IdLoc, diag::err_undef_interface_suggest)
<< Id << IDecl->getDeclName()
- << FixItHint::CreateReplacement(RecoverLoc, IDecl->getNameAsString());
+ << FixItHint::CreateReplacement(IdLoc, IDecl->getNameAsString());
Diag(IDecl->getLocation(), diag::note_previous_decl)
<< IDecl->getDeclName();
@@ -639,7 +674,8 @@ void Sema::InitBuiltinVaListType() {
return;
IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list");
- NamedDecl *VaDecl = LookupSingleName(TUScope, VaIdent, LookupOrdinaryName);
+ NamedDecl *VaDecl = LookupSingleName(TUScope, VaIdent, SourceLocation(),
+ LookupOrdinaryName, ForRedeclaration);
TypedefDecl *VaTypedef = cast<TypedefDecl>(VaDecl);
Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef));
}
@@ -691,7 +727,8 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
FunctionDecl *New = FunctionDecl::Create(Context,
Context.getTranslationUnitDecl(),
Loc, II, R, /*TInfo=*/0,
- FunctionDecl::Extern, false,
+ FunctionDecl::Extern,
+ FunctionDecl::None, false,
/*hasPrototype=*/true);
New->setImplicit();
@@ -702,7 +739,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i)
Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0,
FT->getArgType(i), /*TInfo=*/0,
- VarDecl::None, 0));
+ VarDecl::None, VarDecl::None, 0));
New->setParams(Params.data(), Params.size());
}
@@ -897,13 +934,12 @@ struct GNUCompatibleParamWarning {
/// getSpecialMember - get the special member enum for a method.
-static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx,
- const CXXMethodDecl *MD) {
+Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
- if (Ctor->isDefaultConstructor())
- return Sema::CXXDefaultConstructor;
if (Ctor->isCopyConstructor())
return Sema::CXXCopyConstructor;
+
+ return Sema::CXXConstructor;
}
if (isa<CXXDestructorDecl>(MD))
@@ -1040,10 +1076,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
}
const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
- const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
+ CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
if (OldMethod && NewMethod) {
- if (!NewMethod->getFriendObjectKind() &&
- NewMethod->getLexicalDeclContext()->isRecord()) {
+ // Preserve triviality.
+ NewMethod->setTrivial(OldMethod->isTrivial());
+
+ bool isFriend = NewMethod->getFriendObjectKind();
+
+ if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord()) {
// -- Member function declarations with the same name and the
// same parameter types cannot be overloaded if any of them
// is a static member function declaration.
@@ -1069,14 +1109,19 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
Diag(New->getLocation(), NewDiag);
Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
- } else {
- if (OldMethod->isImplicit()) {
+
+ // Complain if this is an explicit declaration of a special
+ // member that was initially declared implicitly.
+ //
+ // As an exception, it's okay to befriend such methods in order
+ // to permit the implicit constructor/destructor/operator calls.
+ } else if (OldMethod->isImplicit()) {
+ if (isFriend) {
+ NewMethod->setImplicit();
+ } else {
Diag(NewMethod->getLocation(),
diag::err_definition_of_implicitly_declared_member)
- << New << getSpecialMember(Context, OldMethod);
-
- Diag(OldMethod->getLocation(),
- diag::note_previous_implicit_declaration);
+ << New << getSpecialMember(OldMethod);
return true;
}
}
@@ -1125,7 +1170,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
ParmVarDecl *Param = ParmVarDecl::Create(Context, New,
SourceLocation(), 0,
*ParamType, /*TInfo=*/0,
- VarDecl::None, 0);
+ VarDecl::None, VarDecl::None,
+ 0);
Param->setImplicit();
Params.push_back(Param);
}
@@ -1441,7 +1487,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
Record->getDeclContext()->isRecord())
return BuildAnonymousStructOrUnion(S, DS, Record);
- Diag(DS.getSourceRange().getBegin(), diag::err_no_declarators)
+ Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators)
<< DS.getSourceRange();
}
@@ -1463,9 +1509,8 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
return DeclPtrTy::make(Tag);
}
- Diag(DS.getSourceRange().getBegin(), diag::err_no_declarators)
+ Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators)
<< DS.getSourceRange();
- return DeclPtrTy();
}
return DeclPtrTy::make(Tag);
@@ -1558,6 +1603,64 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
return Invalid;
}
+/// StorageClassSpecToVarDeclStorageClass - Maps a DeclSpec::SCS to
+/// a VarDecl::StorageClass. Any error reporting is up to the caller:
+/// illegal input values are mapped to VarDecl::None.
+/// If the input declaration context is a linkage specification
+/// with no braces, then Extern is mapped to None.
+static VarDecl::StorageClass
+StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec,
+ DeclContext *DC) {
+ switch (StorageClassSpec) {
+ case DeclSpec::SCS_unspecified: return VarDecl::None;
+ case DeclSpec::SCS_extern:
+ // If the current context is a C++ linkage specification
+ // having no braces, then the keyword "extern" is properly part
+ // of the linkage specification itself, rather than being
+ // the written storage class specifier.
+ return (DC && isa<LinkageSpecDecl>(DC) &&
+ !cast<LinkageSpecDecl>(DC)->hasBraces())
+ ? VarDecl::None : VarDecl::Extern;
+ case DeclSpec::SCS_static: return VarDecl::Static;
+ case DeclSpec::SCS_auto: return VarDecl::Auto;
+ case DeclSpec::SCS_register: return VarDecl::Register;
+ case DeclSpec::SCS_private_extern: return VarDecl::PrivateExtern;
+ // Illegal SCSs map to None: error reporting is up to the caller.
+ case DeclSpec::SCS_mutable: // Fall through.
+ case DeclSpec::SCS_typedef: return VarDecl::None;
+ }
+ llvm_unreachable("unknown storage class specifier");
+}
+
+/// StorageClassSpecToFunctionDeclStorageClass - Maps a DeclSpec::SCS to
+/// a FunctionDecl::StorageClass. Any error reporting is up to the caller:
+/// illegal input values are mapped to FunctionDecl::None.
+/// If the input declaration context is a linkage specification
+/// with no braces, then Extern is mapped to None.
+static FunctionDecl::StorageClass
+StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec,
+ DeclContext *DC) {
+ switch (StorageClassSpec) {
+ case DeclSpec::SCS_unspecified: return FunctionDecl::None;
+ case DeclSpec::SCS_extern:
+ // If the current context is a C++ linkage specification
+ // having no braces, then the keyword "extern" is properly part
+ // of the linkage specification itself, rather than being
+ // the written storage class specifier.
+ return (DC && isa<LinkageSpecDecl>(DC) &&
+ !cast<LinkageSpecDecl>(DC)->hasBraces())
+ ? FunctionDecl::None : FunctionDecl::Extern;
+ case DeclSpec::SCS_static: return FunctionDecl::Static;
+ case DeclSpec::SCS_private_extern: return FunctionDecl::PrivateExtern;
+ // Illegal SCSs map to None: error reporting is up to the caller.
+ case DeclSpec::SCS_auto: // Fall through.
+ case DeclSpec::SCS_mutable: // Fall through.
+ case DeclSpec::SCS_register: // Fall through.
+ case DeclSpec::SCS_typedef: return FunctionDecl::None;
+ }
+ llvm_unreachable("unknown storage class specifier");
+}
+
/// ActOnAnonymousStructOrUnion - Handle the declaration of an
/// anonymous structure or union. Anonymous unions are a C++ feature
/// (C++ [class.union]) and a GNU C extension; anonymous structures
@@ -1675,32 +1778,31 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
TInfo,
/*BitWidth=*/0, /*Mutable=*/false);
Anon->setAccess(AS_public);
- if (getLangOptions().CPlusPlus)
+ if (getLangOptions().CPlusPlus) {
FieldCollector->Add(cast<FieldDecl>(Anon));
+ if (!cast<CXXRecordDecl>(Record)->isEmpty())
+ cast<CXXRecordDecl>(OwningClass)->setEmpty(false);
+ }
} else {
- VarDecl::StorageClass SC;
- switch (DS.getStorageClassSpec()) {
- default: assert(0 && "Unknown storage class!");
- case DeclSpec::SCS_unspecified: SC = VarDecl::None; break;
- case DeclSpec::SCS_extern: SC = VarDecl::Extern; break;
- case DeclSpec::SCS_static: SC = VarDecl::Static; break;
- case DeclSpec::SCS_auto: SC = VarDecl::Auto; break;
- case DeclSpec::SCS_register: SC = VarDecl::Register; break;
- case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break;
- case DeclSpec::SCS_mutable:
+ DeclSpec::SCS SCSpec = DS.getStorageClassSpec();
+ assert(SCSpec != DeclSpec::SCS_typedef &&
+ "Parser allowed 'typedef' as storage class VarDecl.");
+ VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec, 0);
+ if (SCSpec == DeclSpec::SCS_mutable) {
// mutable can only appear on non-static class members, so it's always
// an error here
Diag(Record->getLocation(), diag::err_mutable_nonmember);
Invalid = true;
SC = VarDecl::None;
- break;
}
+ SCSpec = DS.getStorageClassSpecAsWritten();
+ VarDecl::StorageClass SCAsWritten
+ = StorageClassSpecToVarDeclStorageClass(SCSpec, 0);
Anon = VarDecl::Create(Context, Owner, Record->getLocation(),
/*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
- TInfo,
- SC);
+ TInfo, SC, SCAsWritten);
}
Anon->setImplicit();
@@ -1708,7 +1810,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// context. We'll be referencing this object when we refer to one of
// its members.
Owner->addDecl(Anon);
-
+
// Inject the members of the anonymous struct/union into the owning
// context and into the identifier resolver chain for name lookup
// purposes.
@@ -1829,6 +1931,71 @@ static bool isNearlyMatchingFunction(ASTContext &Context,
return true;
}
+/// NeedsRebuildingInCurrentInstantiation - Checks whether the given
+/// declarator needs to be rebuilt in the current instantiation.
+/// Any bits of declarator which appear before the name are valid for
+/// consideration here. That's specifically the type in the decl spec
+/// and the base type in any member-pointer chunks.
+static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
+ DeclarationName Name) {
+ // The types we specifically need to rebuild are:
+ // - typenames, typeofs, and decltypes
+ // - types which will become injected class names
+ // Of course, we also need to rebuild any type referencing such a
+ // type. It's safest to just say "dependent", but we call out a
+ // few cases here.
+
+ DeclSpec &DS = D.getMutableDeclSpec();
+ switch (DS.getTypeSpecType()) {
+ case DeclSpec::TST_typename:
+ case DeclSpec::TST_typeofType:
+ case DeclSpec::TST_typeofExpr:
+ case DeclSpec::TST_decltype: {
+ // Grab the type from the parser.
+ TypeSourceInfo *TSI = 0;
+ QualType T = S.GetTypeFromParser(DS.getTypeRep(), &TSI);
+ if (T.isNull() || !T->isDependentType()) break;
+
+ // Make sure there's a type source info. This isn't really much
+ // of a waste; most dependent types should have type source info
+ // attached already.
+ if (!TSI)
+ TSI = S.Context.getTrivialTypeSourceInfo(T, DS.getTypeSpecTypeLoc());
+
+ // Rebuild the type in the current instantiation.
+ TSI = S.RebuildTypeInCurrentInstantiation(TSI, D.getIdentifierLoc(), Name);
+ if (!TSI) return true;
+
+ // Store the new type back in the decl spec.
+ QualType LocType = S.CreateLocInfoType(TSI->getType(), TSI);
+ DS.UpdateTypeRep(LocType.getAsOpaquePtr());
+ break;
+ }
+
+ default:
+ // Nothing to do for these decl specs.
+ break;
+ }
+
+ // It doesn't matter what order we do this in.
+ for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) {
+ DeclaratorChunk &Chunk = D.getTypeObject(I);
+
+ // The only type information in the declarator which can come
+ // before the declaration name is the base type of a member
+ // pointer.
+ if (Chunk.Kind != DeclaratorChunk::MemberPointer)
+ continue;
+
+ // Rebuild the scope specifier in-place.
+ CXXScopeSpec &SS = Chunk.Mem.Scope();
+ if (S.RebuildNestedNameSpecifierInCurrentInstantiation(SS))
+ return true;
+ }
+
+ return false;
+}
+
Sema::DeclPtrTy
Sema::HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParamLists,
@@ -1851,35 +2018,47 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
(S->getFlags() & Scope::TemplateParamScope) != 0)
S = S->getParent();
- // If this is an out-of-line definition of a member of a class template
- // or class template partial specialization, we may need to rebuild the
- // type specifier in the declarator. See RebuildTypeInCurrentInstantiation()
- // for more information.
- // FIXME: cope with decltype(expr) and typeof(expr) once the rebuilder can
- // handle expressions properly.
- DeclSpec &DS = const_cast<DeclSpec&>(D.getDeclSpec());
- if (D.getCXXScopeSpec().isSet() && !D.getCXXScopeSpec().isInvalid() &&
- isDependentScopeSpecifier(D.getCXXScopeSpec()) &&
- (DS.getTypeSpecType() == DeclSpec::TST_typename ||
- DS.getTypeSpecType() == DeclSpec::TST_typeofType ||
- DS.getTypeSpecType() == DeclSpec::TST_typeofExpr ||
- DS.getTypeSpecType() == DeclSpec::TST_decltype)) {
- if (DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(), true)) {
- // FIXME: Preserve type source info.
- QualType T = GetTypeFromParser(DS.getTypeRep());
-
- DeclContext *SavedContext = CurContext;
- CurContext = DC;
- T = RebuildTypeInCurrentInstantiation(T, D.getIdentifierLoc(), Name);
- CurContext = SavedContext;
-
- if (T.isNull())
- return DeclPtrTy();
- DS.UpdateTypeRep(T.getAsOpaquePtr());
+ DeclContext *DC = CurContext;
+ if (D.getCXXScopeSpec().isInvalid())
+ D.setInvalidType();
+ else if (D.getCXXScopeSpec().isSet()) {
+ bool EnteringContext = !D.getDeclSpec().isFriendSpecified();
+ DC = computeDeclContext(D.getCXXScopeSpec(), EnteringContext);
+ if (!DC) {
+ // If we could not compute the declaration context, it's because the
+ // declaration context is dependent but does not refer to a class,
+ // class template, or class template partial specialization. Complain
+ // and return early, to avoid the coming semantic disaster.
+ Diag(D.getIdentifierLoc(),
+ diag::err_template_qualified_declarator_no_match)
+ << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep()
+ << D.getCXXScopeSpec().getRange();
+ return DeclPtrTy();
+ }
+
+ bool IsDependentContext = DC->isDependentContext();
+
+ if (!IsDependentContext &&
+ RequireCompleteDeclContext(D.getCXXScopeSpec(), DC))
+ return DeclPtrTy();
+
+ if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_member_def_undefined_record)
+ << Name << DC << D.getCXXScopeSpec().getRange();
+ D.setInvalidType();
+ }
+
+ // Check whether we need to rebuild the type of the given
+ // declaration in the current instantiation.
+ if (EnteringContext && IsDependentContext &&
+ TemplateParamLists.size() != 0) {
+ ContextRAII SavedContext(*this, DC);
+ if (RebuildDeclaratorInCurrentInstantiation(*this, D, Name))
+ D.setInvalidType();
}
}
- DeclContext *DC;
NamedDecl *New;
TypeSourceInfo *TInfo = 0;
@@ -1889,10 +2068,7 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
ForRedeclaration);
// See if this is a redefinition of a variable in the same scope.
- if (D.getCXXScopeSpec().isInvalid()) {
- DC = CurContext;
- D.setInvalidType();
- } else if (!D.getCXXScopeSpec().isSet()) {
+ if (!D.getCXXScopeSpec().isSet()) {
bool IsLinkageLookup = false;
// If the declaration we're planning to build will be a function
@@ -1913,34 +2089,8 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
if (IsLinkageLookup)
Previous.clear(LookupRedeclarationWithLinkage);
- DC = CurContext;
LookupName(Previous, S, /* CreateBuiltins = */ IsLinkageLookup);
} else { // Something like "int foo::x;"
- DC = computeDeclContext(D.getCXXScopeSpec(), true);
-
- if (!DC) {
- // If we could not compute the declaration context, it's because the
- // declaration context is dependent but does not refer to a class,
- // class template, or class template partial specialization. Complain
- // and return early, to avoid the coming semantic disaster.
- Diag(D.getIdentifierLoc(),
- diag::err_template_qualified_declarator_no_match)
- << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep()
- << D.getCXXScopeSpec().getRange();
- return DeclPtrTy();
- }
-
- if (!DC->isDependentContext() &&
- RequireCompleteDeclContext(D.getCXXScopeSpec()))
- return DeclPtrTy();
-
- if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) {
- Diag(D.getIdentifierLoc(),
- diag::err_member_def_undefined_record)
- << Name << DC << D.getCXXScopeSpec().getRange();
- D.setInvalidType();
- }
-
LookupQualifiedName(Previous, DC);
// Don't consider using declarations as previous declarations for
@@ -2298,24 +2448,20 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (getLangOptions().CPlusPlus)
CheckExtraCXXDefaultArguments(D);
- VarDecl *NewVD;
- VarDecl::StorageClass SC;
- switch (D.getDeclSpec().getStorageClassSpec()) {
- default: assert(0 && "Unknown storage class!");
- case DeclSpec::SCS_unspecified: SC = VarDecl::None; break;
- case DeclSpec::SCS_extern: SC = VarDecl::Extern; break;
- case DeclSpec::SCS_static: SC = VarDecl::Static; break;
- case DeclSpec::SCS_auto: SC = VarDecl::Auto; break;
- case DeclSpec::SCS_register: SC = VarDecl::Register; break;
- case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break;
- case DeclSpec::SCS_mutable:
+ DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
+ assert(SCSpec != DeclSpec::SCS_typedef &&
+ "Parser allowed 'typedef' as storage class VarDecl.");
+ VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec, 0);
+ if (SCSpec == DeclSpec::SCS_mutable) {
// mutable can only appear on non-static class members, so it's always
// an error here
Diag(D.getIdentifierLoc(), diag::err_mutable_nonmember);
D.setInvalidType();
SC = VarDecl::None;
- break;
}
+ SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
+ VarDecl::StorageClass SCAsWritten
+ = StorageClassSpecToVarDeclStorageClass(SCSpec, DC);
IdentifierInfo *II = Name.getAsIdentifierInfo();
if (!II) {
@@ -2367,6 +2513,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
D.getCXXScopeSpec(),
(TemplateParameterList**)TemplateParamLists.get(),
TemplateParamLists.size(),
+ /*never a friend*/ false,
isExplicitSpecialization)) {
if (TemplateParams->size() > 0) {
// There is no such thing as a variable template.
@@ -2388,8 +2535,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
}
- NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
- II, R, TInfo, SC);
+ VarDecl *NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
+ II, R, TInfo, SC, SCAsWritten);
if (D.isInvalidType())
NewVD->setInvalidDecl();
@@ -2767,6 +2914,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
+ DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
+ FunctionDecl::StorageClass SCAsWritten
+ = StorageClassSpecToFunctionDeclStorageClass(SCSpec, DC);
+
// Check that the return type is not an abstract class type.
// For record types, this is done by the AbstractClassUsageDiagnoser once
// the class has been completely parsed.
@@ -2827,7 +2978,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Create a FunctionDecl to satisfy the function definition parsing
// code path.
NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(),
- Name, R, TInfo, SC, isInline,
+ Name, R, TInfo, SC, SCAsWritten, isInline,
/*hasPrototype=*/true);
D.setInvalidType();
}
@@ -2876,7 +3027,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// This is a C++ method declaration.
NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
D.getIdentifierLoc(), Name, R, TInfo,
- isStatic, isInline);
+ isStatic, SCAsWritten, isInline);
isVirtualOkay = !isStatic;
} else {
@@ -2893,7 +3044,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
NewFD = FunctionDecl::Create(Context, DC,
D.getIdentifierLoc(),
- Name, R, TInfo, SC, isInline, HasPrototype);
+ Name, R, TInfo, SC, SCAsWritten, isInline,
+ HasPrototype);
}
if (D.isInvalidType())
@@ -2917,6 +3069,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
D.getCXXScopeSpec(),
(TemplateParameterList**)TemplateParamLists.get(),
TemplateParamLists.size(),
+ isFriend,
isExplicitSpecialization)) {
if (TemplateParams->size() > 0) {
// This is a function template
@@ -2935,7 +3088,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// This is a function template specialization.
isFunctionTemplateSpecialization = true;
- // C++0x [temp.expl.spec]p20 forbids "template<> void foo(int);".
+ // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);".
if (isFriend && isFunctionTemplateSpecialization) {
// We want to remove the "template<>", found here.
SourceRange RemoveRange = TemplateParams->getSourceRange();
@@ -3015,10 +3168,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (FunctionTemplate) {
FunctionTemplate->setObjectOfFriendDecl(false);
FunctionTemplate->setAccess(AS_public);
- } else {
- NewFD->setObjectOfFriendDecl(false);
}
-
+ NewFD->setObjectOfFriendDecl(false);
NewFD->setAccess(AS_public);
}
@@ -3072,6 +3223,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
assert(Param->getDeclContext() != NewFD && "Was set before ?");
Param->setDeclContext(NewFD);
Params.push_back(Param);
+
+ if (Param->isInvalidDecl())
+ NewFD->setInvalidDecl();
}
}
@@ -3091,6 +3245,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
ParmVarDecl *Param = ParmVarDecl::Create(Context, NewFD,
SourceLocation(), 0,
*AI, /*TInfo=*/0,
+ VarDecl::None,
VarDecl::None, 0);
Param->setImplicit();
Params.push_back(Param);
@@ -3139,24 +3294,39 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// "friend void foo<>(int);" is an implicit specialization decl.
isFunctionTemplateSpecialization = true;
}
+ } else if (isFriend && isFunctionTemplateSpecialization) {
+ // This combination is only possible in a recovery case; the user
+ // wrote something like:
+ // template <> friend void foo(int);
+ // which we're recovering from as if the user had written:
+ // friend void foo<>(int);
+ // Go ahead and fake up a template id.
+ HasExplicitTemplateArgs = true;
+ TemplateArgs.setLAngleLoc(D.getIdentifierLoc());
+ TemplateArgs.setRAngleLoc(D.getIdentifierLoc());
+ }
+
+ // If it's a friend (and only if it's a friend), it's possible
+ // that either the specialized function type or the specialized
+ // template is dependent, and therefore matching will fail. In
+ // this case, don't check the specialization yet.
+ if (isFunctionTemplateSpecialization && isFriend &&
+ (NewFD->getType()->isDependentType() || DC->isDependentContext())) {
+ assert(HasExplicitTemplateArgs &&
+ "friend function specialization without template args");
+ if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs,
+ Previous))
+ NewFD->setInvalidDecl();
+ } else if (isFunctionTemplateSpecialization) {
+ if (CheckFunctionTemplateSpecialization(NewFD,
+ (HasExplicitTemplateArgs ? &TemplateArgs : 0),
+ Previous))
+ NewFD->setInvalidDecl();
+ } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) {
+ if (CheckMemberSpecialization(NewFD, Previous))
+ NewFD->setInvalidDecl();
}
- if (isFunctionTemplateSpecialization) {
- if (isFriend && NewFD->getType()->isDependentType()) {
- // FIXME: When we see a friend of a function template
- // specialization with a dependent type, we can't match it now;
- // for now, we just drop it, until we have a reasonable way to
- // represent the parsed-but-not-matched friend function template
- // specialization in the AST.
- return 0;
- } else if (CheckFunctionTemplateSpecialization(NewFD,
- (HasExplicitTemplateArgs ? &TemplateArgs : 0),
- Previous))
- NewFD->setInvalidDecl();
- } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) &&
- CheckMemberSpecialization(NewFD, Previous))
- NewFD->setInvalidDecl();
-
// Perform semantic checking on the function declaration.
bool OverloadableAttrRequired = false; // FIXME: HACK!
CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
@@ -3166,17 +3336,25 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
+ NamedDecl *PrincipalDecl = (FunctionTemplate
+ ? cast<NamedDecl>(FunctionTemplate)
+ : NewFD);
+
if (isFriend && Redeclaration) {
- AccessSpecifier Access = NewFD->getPreviousDeclaration()->getAccess();
- if (FunctionTemplate) {
- FunctionTemplate->setObjectOfFriendDecl(true);
- FunctionTemplate->setAccess(Access);
- } else {
- NewFD->setObjectOfFriendDecl(true);
- }
+ AccessSpecifier Access = AS_public;
+ if (!NewFD->isInvalidDecl())
+ Access = NewFD->getPreviousDeclaration()->getAccess();
+
NewFD->setAccess(Access);
+ if (FunctionTemplate) FunctionTemplate->setAccess(Access);
+
+ PrincipalDecl->setObjectOfFriendDecl(true);
}
+ if (NewFD->isOverloadedOperator() && !DC->isRecord() &&
+ PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ PrincipalDecl->setNonMemberOperator();
+
// If we have a function template, check the template parameter
// list. This will check and merge default template arguments.
if (FunctionTemplate) {
@@ -3286,7 +3464,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// FIXME: Also include static functions declared but not defined.
if (!NewFD->isInvalidDecl() && IsFunctionDefinition
&& !NewFD->isInlined() && NewFD->getLinkage() == InternalLinkage
- && !NewFD->isUsed() && !NewFD->hasAttr<UnusedAttr>())
+ && !NewFD->isUsed() && !NewFD->hasAttr<UnusedAttr>()
+ && !NewFD->hasAttr<ConstructorAttr>()
+ && !NewFD->hasAttr<DestructorAttr>())
UnusedStaticFuncs.push_back(NewFD);
return NewFD;
@@ -3761,7 +3941,9 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
}
}
} else if (VDecl->isFileVarDecl()) {
- if (VDecl->getStorageClass() == VarDecl::Extern)
+ if (VDecl->getStorageClass() == VarDecl::Extern &&
+ (!getLangOptions().CPlusPlus ||
+ !Context.getBaseElementType(VDecl->getType()).isConstQualified()))
Diag(VDecl->getLocation(), diag::warn_extern_init);
if (!VDecl->isInvalidDecl()) {
InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1);
@@ -4030,8 +4212,10 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
VarDecl::StorageClass StorageClass = VarDecl::None;
+ VarDecl::StorageClass StorageClassAsWritten = VarDecl::None;
if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
StorageClass = VarDecl::Register;
+ StorageClassAsWritten = VarDecl::Register;
} else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) {
Diag(DS.getStorageClassSpecLoc(),
diag::err_invalid_storage_class_in_func_decl);
@@ -4084,55 +4268,24 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
}
}
- // Parameters can not be abstract class types.
- // For record types, this is done by the AbstractClassUsageDiagnoser once
- // the class has been completely parsed.
- if (!CurContext->isRecord() &&
- RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType,
- diag::err_abstract_type_in_decl,
- AbstractParamType))
- D.setInvalidType(true);
-
- QualType T = adjustParameterType(parmDeclType);
-
// Temporarily put parameter variables in the translation unit, not
// the enclosing context. This prevents them from accidentally
// looking like class members in C++.
- DeclContext *DC = Context.getTranslationUnitDecl();
-
- ParmVarDecl *New
- = ParmVarDecl::Create(Context, DC, D.getIdentifierLoc(), II,
- T, TInfo, StorageClass, 0);
+ ParmVarDecl *New = CheckParameter(Context.getTranslationUnitDecl(),
+ TInfo, parmDeclType, II,
+ D.getIdentifierLoc(),
+ StorageClass, StorageClassAsWritten);
if (D.isInvalidType())
- New->setInvalidDecl();
-
- // Parameter declarators cannot be interface types. All ObjC objects are
- // passed by reference.
- if (T->isObjCInterfaceType()) {
- Diag(D.getIdentifierLoc(),
- diag::err_object_cannot_be_passed_returned_by_value) << 1 << T;
- New->setInvalidDecl();
- }
-
+ New->setInvalidDecl();
+
// Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
if (D.getCXXScopeSpec().isSet()) {
Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator)
<< D.getCXXScopeSpec().getRange();
New->setInvalidDecl();
}
-
- // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage
- // duration shall not be qualified by an address-space qualifier."
- // Since all parameters have automatic store duration, they can not have
- // an address space.
- if (T.getAddressSpace() != 0) {
- Diag(D.getIdentifierLoc(),
- diag::err_arg_with_address_space);
- New->setInvalidDecl();
- }
-
-
+
// Add the parameter declaration into this scope.
S->AddDecl(DeclPtrTy::make(New));
if (II)
@@ -4146,9 +4299,43 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
return DeclPtrTy::make(New);
}
-void Sema::ActOnObjCCatchParam(DeclPtrTy D) {
- ParmVarDecl *Param = cast<ParmVarDecl>(D.getAs<Decl>());
- Param->setDeclContext(CurContext);
+ParmVarDecl *Sema::CheckParameter(DeclContext *DC,
+ TypeSourceInfo *TSInfo, QualType T,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ VarDecl::StorageClass StorageClass,
+ VarDecl::StorageClass StorageClassAsWritten) {
+ ParmVarDecl *New = ParmVarDecl::Create(Context, DC, NameLoc, Name,
+ adjustParameterType(T), TSInfo,
+ StorageClass, StorageClassAsWritten,
+ 0);
+
+ // Parameters can not be abstract class types.
+ // For record types, this is done by the AbstractClassUsageDiagnoser once
+ // the class has been completely parsed.
+ if (!CurContext->isRecord() &&
+ RequireNonAbstractType(NameLoc, T, diag::err_abstract_type_in_decl,
+ AbstractParamType))
+ New->setInvalidDecl();
+
+ // Parameter declarators cannot be interface types. All ObjC objects are
+ // passed by reference.
+ if (T->isObjCInterfaceType()) {
+ Diag(NameLoc,
+ diag::err_object_cannot_be_passed_returned_by_value) << 1 << T;
+ New->setInvalidDecl();
+ }
+
+ // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage
+ // duration shall not be qualified by an address-space qualifier."
+ // Since all parameters have automatic store duration, they can not have
+ // an address space.
+ if (T.getAddressSpace() != 0) {
+ Diag(NameLoc, diag::err_arg_with_address_space);
+ New->setInvalidDecl();
+ }
+
+ return New;
}
void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
@@ -4692,7 +4879,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
/// TagSpec indicates what kind of tag this is. TUK indicates whether this is a
/// reference/declaration/definition of a tag.
Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
- SourceLocation KWLoc, const CXXScopeSpec &SS,
+ SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
MultiTemplateParamsArg TemplateParameterLists,
@@ -4711,6 +4898,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
= MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
(TemplateParameterList**)TemplateParameterLists.get(),
TemplateParameterLists.size(),
+ TUK == TUK_Friend,
isExplicitSpecialization)) {
if (TemplateParams->size() > 0) {
// This is a declaration or definition of a class template (which may
@@ -4761,12 +4949,18 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
IsDependent = true;
return DeclPtrTy();
}
+ } else {
+ DC = computeDeclContext(SS, true);
+ if (!DC) {
+ Diag(SS.getRange().getBegin(), diag::err_dependent_nested_name_spec)
+ << SS.getRange();
+ return DeclPtrTy();
+ }
}
- if (RequireCompleteDeclContext(SS))
+ if (RequireCompleteDeclContext(SS, DC))
return DeclPtrTy::make((Decl *)0);
- DC = computeDeclContext(SS, true);
SearchDC = DC;
// Look-up name inside 'foo::'.
LookupQualifiedName(Previous, DC);
@@ -4891,17 +5085,10 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// class or function, the friend class or function is a member of
// the innermost enclosing namespace.
SearchDC = SearchDC->getEnclosingNamespaceContext();
-
- // Look up through our scopes until we find one with an entity which
- // matches our declaration context.
- while (S->getEntity() &&
- ((DeclContext *)S->getEntity())->getPrimaryContext() != SearchDC) {
- S = S->getParent();
- assert(S && "No enclosing scope matching the enclosing namespace.");
- }
}
- // In C++, look for a shadow friend decl.
+ // In C++, we need to do a redeclaration lookup to properly
+ // diagnose some problems.
if (getLangOptions().CPlusPlus) {
Previous.setRedeclarationKind(ForRedeclaration);
LookupQualifiedName(Previous, SearchDC);
@@ -4909,8 +5096,32 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
if (!Previous.empty()) {
- assert(Previous.isSingleResult());
- NamedDecl *PrevDecl = Previous.getFoundDecl();
+ NamedDecl *PrevDecl = (*Previous.begin())->getUnderlyingDecl();
+
+ // It's okay to have a tag decl in the same scope as a typedef
+ // which hides a tag decl in the same scope. Finding this
+ // insanity with a redeclaration lookup can only actually happen
+ // in C++.
+ //
+ // This is also okay for elaborated-type-specifiers, which is
+ // technically forbidden by the current standard but which is
+ // okay according to the likely resolution of an open issue;
+ // see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407
+ if (getLangOptions().CPlusPlus) {
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(PrevDecl)) {
+ if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
+ TagDecl *Tag = TT->getDecl();
+ if (Tag->getDeclName() == Name &&
+ Tag->getDeclContext()->getLookupContext()
+ ->Equals(TD->getDeclContext()->getLookupContext())) {
+ PrevDecl = Tag;
+ Previous.clear();
+ Previous.addDecl(Tag);
+ }
+ }
+ }
+ }
+
if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
// If this is a use of a previous tag, or if the tag is already declared
// in the same scope (so that the definition/declaration completes or
@@ -5002,23 +5213,61 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// If we get here, we're going to create a new Decl. If PrevDecl
// is non-NULL, it's a definition of the tag declared by
// PrevDecl. If it's NULL, we have a new definition.
+
+
+ // Otherwise, PrevDecl is not a tag, but was found with tag
+ // lookup. This is only actually possible in C++, where a few
+ // things like templates still live in the tag namespace.
} else {
- // PrevDecl is a namespace, template, or anything else
- // that lives in the IDNS_Tag identifier namespace.
- if (TUK == TUK_Reference || TUK == TUK_Friend ||
- isDeclInScope(PrevDecl, SearchDC, S)) {
- // The tag name clashes with a namespace name, issue an error and
- // recover by making this tag be anonymous.
+ assert(getLangOptions().CPlusPlus);
+
+ // Use a better diagnostic if an elaborated-type-specifier
+ // found the wrong kind of type on the first
+ // (non-redeclaration) lookup.
+ if ((TUK == TUK_Reference || TUK == TUK_Friend) &&
+ !Previous.isForRedeclaration()) {
+ unsigned Kind = 0;
+ if (isa<TypedefDecl>(PrevDecl)) Kind = 1;
+ else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 2;
+ Diag(NameLoc, diag::err_tag_reference_non_tag) << Kind;
+ Diag(PrevDecl->getLocation(), diag::note_declared_at);
+ Invalid = true;
+
+ // Otherwise, only diagnose if the declaration is in scope.
+ } else if (!isDeclInScope(PrevDecl, SearchDC, S)) {
+ // do nothing
+
+ // Diagnose implicit declarations introduced by elaborated types.
+ } else if (TUK == TUK_Reference || TUK == TUK_Friend) {
+ unsigned Kind = 0;
+ if (isa<TypedefDecl>(PrevDecl)) Kind = 1;
+ else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 2;
+ Diag(NameLoc, diag::err_tag_reference_conflict) << Kind;
+ Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl;
+ Invalid = true;
+
+ // Otherwise it's a declaration. Call out a particularly common
+ // case here.
+ } else if (isa<TypedefDecl>(PrevDecl)) {
+ Diag(NameLoc, diag::err_tag_definition_of_typedef)
+ << Name
+ << cast<TypedefDecl>(PrevDecl)->getUnderlyingType();
+ Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl;
+ Invalid = true;
+
+ // Otherwise, diagnose.
+ } else {
+ // The tag name clashes with something else in the target scope,
+ // issue an error and recover by making this tag be anonymous.
Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
Name = 0;
- Previous.clear();
Invalid = true;
- } else {
- // The existing declaration isn't relevant to us; we're in a
- // new scope, so clear out the previous declaration.
- Previous.clear();
}
+
+ // The existing declaration isn't relevant to us; we're in a
+ // new scope, so clear out the previous declaration.
+ Previous.clear();
}
}
@@ -5089,28 +5338,6 @@ CreateNewDecl:
New->addAttr(::new (Context) PragmaPackAttr(Alignment * 8));
}
- if (getLangOptions().CPlusPlus && SS.isEmpty() && Name && !Invalid) {
- // C++ [dcl.typedef]p3:
- // [...] Similarly, in a given scope, a class or enumeration
- // shall not be declared with the same name as a typedef-name
- // that is declared in that scope and refers to a type other
- // than the class or enumeration itself.
- LookupResult Lookup(*this, Name, NameLoc, LookupOrdinaryName,
- ForRedeclaration);
- LookupName(Lookup, S);
- TypedefDecl *PrevTypedef = Lookup.getAsSingle<TypedefDecl>();
- NamedDecl *PrevTypedefNamed = PrevTypedef;
- if (PrevTypedef && isDeclInScope(PrevTypedefNamed, SearchDC, S) &&
- Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) !=
- Context.getCanonicalType(Context.getTypeDeclType(New))) {
- Diag(Loc, diag::err_tag_definition_of_typedef)
- << Context.getTypeDeclType(New)
- << PrevTypedef->getUnderlyingType();
- Diag(PrevTypedef->getLocation(), diag::note_previous_definition);
- Invalid = true;
- }
- }
-
// If this is a specialization of a member class (of a class template),
// check the specialization.
if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous))
@@ -5175,7 +5402,7 @@ CreateNewDecl:
void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) {
AdjustDeclIfTemplate(TagD);
TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>());
-
+
// Enter the tag context.
PushDeclContext(S, Tag);
}
@@ -5321,11 +5548,23 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
if (!FieldTy->isDependentType()) {
uint64_t TypeSize = Context.getTypeSize(FieldTy);
if (Value.getZExtValue() > TypeSize) {
+ if (!getLangOptions().CPlusPlus) {
+ if (FieldName)
+ return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size)
+ << FieldName << (unsigned)Value.getZExtValue()
+ << (unsigned)TypeSize;
+
+ return Diag(FieldLoc, diag::err_anon_bitfield_width_exceeds_type_size)
+ << (unsigned)Value.getZExtValue() << (unsigned)TypeSize;
+ }
+
if (FieldName)
- return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size)
- << FieldName << (unsigned)TypeSize;
- return Diag(FieldLoc, diag::err_anon_bitfield_width_exceeds_type_size)
- << (unsigned)TypeSize;
+ Diag(FieldLoc, diag::warn_bitfield_width_exceeds_type_size)
+ << FieldName << (unsigned)Value.getZExtValue()
+ << (unsigned)TypeSize;
+ else
+ Diag(FieldLoc, diag::warn_anon_bitfield_width_exceeds_type_size)
+ << (unsigned)Value.getZExtValue() << (unsigned)TypeSize;
}
}
@@ -5363,7 +5602,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
- NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName,
+ NamedDecl *PrevDecl = LookupSingleName(S, II, Loc, LookupMemberName,
ForRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
@@ -5506,21 +5745,17 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
// because otherwise we'll never get complaints about
// copy constructors.
- const CXXSpecialMember invalid = (CXXSpecialMember) -1;
-
- CXXSpecialMember member;
+ CXXSpecialMember member = CXXInvalid;
if (!RDecl->hasTrivialCopyConstructor())
member = CXXCopyConstructor;
else if (!RDecl->hasTrivialConstructor())
- member = CXXDefaultConstructor;
+ member = CXXConstructor;
else if (!RDecl->hasTrivialCopyAssignment())
member = CXXCopyAssignment;
else if (!RDecl->hasTrivialDestructor())
member = CXXDestructor;
- else
- member = invalid;
- if (member != invalid) {
+ if (member != CXXInvalid) {
Diag(Loc, diag::err_illegal_union_member) << Name << member;
DiagnoseNontrivial(RT, member);
NewFD->setInvalidDecl();
@@ -5562,14 +5797,16 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
// Check whether the member was user-declared.
switch (member) {
- case CXXDefaultConstructor:
+ case CXXInvalid:
+ break;
+
+ case CXXConstructor:
if (RD->hasUserDeclaredConstructor()) {
typedef CXXRecordDecl::ctor_iterator ctor_iter;
for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce;++ci){
const FunctionDecl *body = 0;
ci->getBody(body);
- if (!body ||
- !cast<CXXConstructorDecl>(body)->isImplicitlyDefined(Context)) {
+ if (!body || !cast<CXXConstructorDecl>(body)->isImplicitlyDefined()) {
SourceLocation CtorLoc = ci->getLocation();
Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
return;
@@ -5637,7 +5874,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
bool (CXXRecordDecl::*hasTrivial)() const;
switch (member) {
- case CXXDefaultConstructor:
+ case CXXConstructor:
hasTrivial = &CXXRecordDecl::hasTrivialConstructor; break;
case CXXCopyConstructor:
hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break;
@@ -5727,10 +5964,13 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S,
// validate II.
}
-
+ if (T->isReferenceType()) {
+ Diag(Loc, diag::err_ivar_reference_type);
+ D.setInvalidType();
+ }
// C99 6.7.2.1p8: A member of a structure or union may have any type other
// than a variably modified type.
- if (T->isVariablyModifiedType()) {
+ else if (T->isVariablyModifiedType()) {
Diag(Loc, diag::err_typecheck_ivar_variable_size);
D.setInvalidType();
}
@@ -5747,8 +5987,16 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S,
// Case of ivar declared in an implementation. Context is that of its class.
EnclosingContext = IMPDecl->getClassInterface();
assert(EnclosingContext && "Implementation has no class interface!");
- } else
+ } else {
+ if (ObjCCategoryDecl *CDecl =
+ dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) {
+ if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension()) {
+ Diag(Loc, diag::err_misplaced_ivar) << CDecl->IsClassExtension();
+ return DeclPtrTy();
+ }
+ }
EnclosingContext = EnclosingDecl;
+ }
// Construct the decl.
ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context,
@@ -5756,7 +6004,7 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S,
TInfo, ac, (Expr *)BitfieldWidth);
if (II) {
- NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName,
+ NamedDecl *PrevDecl = LookupSingleName(S, II, Loc, LookupMemberName,
ForRedeclaration);
if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S)
&& !isa<TagDecl>(PrevDecl)) {
@@ -5926,16 +6174,14 @@ void Sema::ActOnFields(Scope* S,
CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac);
} else if (ObjCCategoryDecl *CDecl =
dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) {
- if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension())
- Diag(LBrac, diag::err_misplaced_ivar) << CDecl->IsClassExtension();
- else {
- // FIXME. Class extension does not have a LocEnd field.
- // CDecl->setLocEnd(RBrac);
- // Add ivar's to class extension's DeclContext.
- for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
- ClsFields[i]->setLexicalDeclContext(CDecl);
- CDecl->addDecl(ClsFields[i]);
- }
+ // case of ivars in class extension; all other cases have been
+ // reported as errors elsewhere.
+ // FIXME. Class extension does not have a LocEnd field.
+ // CDecl->setLocEnd(RBrac);
+ // Add ivar's to class extension's DeclContext.
+ for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
+ ClsFields[i]->setLexicalDeclContext(CDecl);
+ CDecl->addDecl(ClsFields[i]);
}
}
}
@@ -5950,7 +6196,7 @@ static bool isRepresentableIntegerValue(ASTContext &Context,
llvm::APSInt &Value,
QualType T) {
assert(T->isIntegralType() && "Integral type required!");
- unsigned BitWidth = Context.getTypeSize(T);
+ unsigned BitWidth = Context.getIntWidth(T);
if (Value.isUnsigned() || Value.isNonNegative())
return Value.getActiveBits() < BitWidth;
@@ -6083,7 +6329,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// value, then increment.
EnumVal = LastEnumConst->getInitVal();
EnumVal.setIsSigned(EltTy->isSignedIntegerType());
- EnumVal.zextOrTrunc(Context.getTypeSize(EltTy));
+ EnumVal.zextOrTrunc(Context.getIntWidth(EltTy));
++EnumVal;
// If we're not in C++, diagnose the overflow of enumerator values,
@@ -6105,7 +6351,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
if (!EltTy->isDependentType()) {
// Make the enumerator value match the signedness and size of the
// enumerator's type.
- EnumVal.zextOrTrunc(Context.getTypeSize(EltTy));
+ EnumVal.zextOrTrunc(Context.getIntWidth(EltTy));
EnumVal.setIsSigned(EltTy->isSignedIntegerType());
}
@@ -6131,7 +6377,7 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl,
// Verify that there isn't already something declared with this name in this
// scope.
- NamedDecl *PrevDecl = LookupSingleName(S, Id, LookupOrdinaryName,
+ NamedDecl *PrevDecl = LookupSingleName(S, Id, IdLoc, LookupOrdinaryName,
ForRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
@@ -6357,6 +6603,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
ECD->setInitExpr(new (Context) ImplicitCastExpr(NewTy,
CastExpr::CK_IntegralCast,
ECD->getInitExpr(),
+ CXXBaseSpecifierArray(),
/*isLvalue=*/false));
if (getLangOptions().CPlusPlus)
// C++ [dcl.enum]p4: Following the closing brace of an
@@ -6383,7 +6630,7 @@ Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc,
void Sema::ActOnPragmaWeakID(IdentifierInfo* Name,
SourceLocation PragmaLoc,
SourceLocation NameLoc) {
- Decl *PrevDecl = LookupSingleName(TUScope, Name, LookupOrdinaryName);
+ Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName);
if (PrevDecl) {
PrevDecl->addAttr(::new (Context) WeakAttr());
@@ -6399,7 +6646,8 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name,
SourceLocation PragmaLoc,
SourceLocation NameLoc,
SourceLocation AliasNameLoc) {
- Decl *PrevDecl = LookupSingleName(TUScope, AliasName, LookupOrdinaryName);
+ Decl *PrevDecl = LookupSingleName(TUScope, AliasName, AliasNameLoc,
+ LookupOrdinaryName);
WeakInfo W = WeakInfo(Name, NameLoc);
if (PrevDecl) {
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index cc24735..90aa9c1 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -118,7 +118,7 @@ static bool isFunctionOrMethodVariadic(const Decl *d) {
const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy);
return proto->isVariadic();
} else if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
- return BD->IsVariadic();
+ return BD->isVariadic();
else {
return cast<ObjCMethodDecl>(d)->isVariadic();
}
@@ -490,16 +490,9 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
}
static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // NOTE: We don't add the attribute to a FunctionDecl because the noreturn
- // trait will be part of the function's type.
-
- // Don't apply as a decl attribute to ValueDecl.
- // FIXME: probably ought to diagnose this.
- if (isa<ValueDecl>(d))
- return;
-
- if (HandleCommonNoReturnAttr(d, Attr, S))
- d->addAttr(::new (S.Context) NoReturnAttr());
+ /* Diagnostics (if any) was emitted by Sema::ProcessFnAttr(). */
+ assert(Attr.isInvalid() == false);
+ d->addAttr(::new (S.Context) NoReturnAttr());
}
static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
@@ -900,9 +893,12 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// We ignore weak import on properties and methods
return;
} else if (!(S.LangOpts.ObjCNonFragileABI && isa<ObjCInterfaceDecl>(D))) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 2 /*variable and function*/;
- return;
+ // Don't issue the warning for darwin as target; yet, ignore the attribute.
+ if (S.Context.Target.getTriple().getOS() != llvm::Triple::Darwin ||
+ !isa<ObjCInterfaceDecl>(D))
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 2 /*variable and function*/;
+ return;
}
// Merge should handle any subsequent violations.
@@ -1022,8 +1018,11 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
// Look up the function
+ // FIXME: Lookup probably isn't looking in the right place
+ // FIXME: The lookup source location should be in the attribute, not the
+ // start of the attribute.
NamedDecl *CleanupDecl
- = S.LookupSingleName(S.TUScope, Attr.getParameterName(),
+ = S.LookupSingleName(S.TUScope, Attr.getParameterName(), Attr.getLoc(),
Sema::LookupOrdinaryName);
if (!CleanupDecl) {
S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_found) <<
@@ -1643,6 +1642,27 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(::new (S.Context) GNUInlineAttr());
}
+static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // Diagnostic is emitted elsewhere: here we store the (valid) Attr
+ // in the Decl node for syntactic reasoning, e.g., pretty-printing.
+ assert(Attr.isInvalid() == false);
+
+ switch (Attr.getKind()) {
+ case AttributeList::AT_fastcall:
+ d->addAttr(::new (S.Context) FastCallAttr());
+ return;
+ case AttributeList::AT_stdcall:
+ d->addAttr(::new (S.Context) StdCallAttr());
+ return;
+ case AttributeList::AT_cdecl:
+ d->addAttr(::new (S.Context) CDeclAttr());
+ return;
+ default:
+ llvm_unreachable("unexpected attribute kind");
+ return;
+ }
+}
+
static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() != 1) {
@@ -1843,6 +1863,9 @@ static bool isKnownDeclSpecAttr(const AttributeList &Attr) {
/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4).
static void ProcessDeclAttribute(Scope *scope, Decl *D,
const AttributeList &Attr, Sema &S) {
+ if (Attr.isInvalid())
+ return;
+
if (Attr.isDeclspecAttribute() && !isKnownDeclSpecAttr(Attr))
// FIXME: Try to deal with other __declspec attributes!
return;
@@ -1927,7 +1950,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_stdcall:
case AttributeList::AT_cdecl:
case AttributeList::AT_fastcall:
- // These are all treated as type attributes.
+ HandleCallConvAttr(D, Attr, S);
break;
default:
// Ask target about the attribute.
@@ -1972,7 +1995,8 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) {
NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
VD->getLocation(), II,
VD->getType(), VD->getTypeSourceInfo(),
- VD->getStorageClass());
+ VD->getStorageClass(),
+ VD->getStorageClassAsWritten());
if (VD->getQualifier()) {
VarDecl *NewVD = cast<VarDecl>(NewD);
NewVD->setQualifierInfo(VD->getQualifier(), VD->getQualifierRange());
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 39e3739..6259b85a 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -16,12 +16,13 @@
#include "Lookup.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecordLayout.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Template.h"
#include "clang/Basic/PartialDiagnostic.h"
@@ -297,13 +298,15 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
<< OldParam->getDefaultArgRange();
Invalid = true;
} else if (OldParam->hasDefaultArg()) {
- // Merge the old default argument into the new parameter
+ // Merge the old default argument into the new parameter.
+ // It's important to use getInit() here; getDefaultArg()
+ // strips off any top-level CXXExprWithTemporaries.
NewParam->setHasInheritedDefaultArg();
if (OldParam->hasUninstantiatedDefaultArg())
NewParam->setUninstantiatedDefaultArg(
OldParam->getUninstantiatedDefaultArg());
else
- NewParam->setDefaultArg(OldParam->getDefaultArg());
+ NewParam->setDefaultArg(OldParam->getInit());
} else if (NewParam->hasDefaultArg()) {
if (New->getDescribedFunctionTemplate()) {
// Paragraph 4, quoted above, only applies to non-template functions.
@@ -710,6 +713,29 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) {
return DerivedRD->isDerivedFrom(BaseRD, Paths);
}
+void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
+ CXXBaseSpecifierArray &BasePathArray) {
+ assert(BasePathArray.empty() && "Base path array must be empty!");
+ assert(Paths.isRecordingPaths() && "Must record paths!");
+
+ const CXXBasePath &Path = Paths.front();
+
+ // We first go backward and check if we have a virtual base.
+ // FIXME: It would be better if CXXBasePath had the base specifier for
+ // the nearest virtual base.
+ unsigned Start = 0;
+ for (unsigned I = Path.size(); I != 0; --I) {
+ if (Path[I - 1].Base->isVirtual()) {
+ Start = I - 1;
+ break;
+ }
+ }
+
+ // Now add all bases.
+ for (unsigned I = Start, E = Path.size(); I != E; ++I)
+ BasePathArray.push_back(Path[I].Base);
+}
+
/// CheckDerivedToBaseConversion - Check whether the Derived-to-Base
/// conversion (where Derived and Base are class types) is
/// well-formed, meaning that the conversion is unambiguous (and
@@ -723,7 +749,8 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
unsigned InaccessibleBaseID,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
- DeclarationName Name) {
+ DeclarationName Name,
+ CXXBaseSpecifierArray *BasePath) {
// First, determine whether the path from Derived to Base is
// ambiguous. This is slightly more expensive than checking whether
// the Derived to Base conversion exists, because here we need to
@@ -736,17 +763,23 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
(void)DerivationOkay;
if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
- if (!InaccessibleBaseID)
- return false;
-
- // Check that the base class can be accessed.
- switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
- InaccessibleBaseID)) {
- case AR_accessible: return false;
- case AR_inaccessible: return true;
- case AR_dependent: return false;
- case AR_delayed: return false;
+ if (InaccessibleBaseID) {
+ // Check that the base class can be accessed.
+ switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
+ InaccessibleBaseID)) {
+ case AR_inaccessible:
+ return true;
+ case AR_accessible:
+ case AR_dependent:
+ case AR_delayed:
+ break;
+ }
}
+
+ // Build a base path if necessary.
+ if (BasePath)
+ BuildBasePathArray(Paths, *BasePath);
+ return false;
}
// We know that the derived-to-base conversion is ambiguous, and
@@ -775,12 +808,14 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
bool
Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
SourceLocation Loc, SourceRange Range,
+ CXXBaseSpecifierArray *BasePath,
bool IgnoreAccess) {
return CheckDerivedToBaseConversion(Derived, Base,
IgnoreAccess ? 0
: diag::err_upcast_to_inaccessible_base,
diag::err_ambiguous_derived_to_base_conv,
- Loc, Range, DeclarationName());
+ Loc, Range, DeclarationName(),
+ BasePath);
}
@@ -1013,7 +1048,7 @@ static bool FindBaseInitializer(Sema &SemaRef,
Sema::MemInitResult
Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
IdentifierInfo *MemberOrBase,
TypeTy *TemplateTypeTy,
SourceLocation IdLoc,
@@ -1076,6 +1111,9 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
if (!TyD) {
if (R.isAmbiguous()) return true;
+ // We don't want access-control diagnostics here.
+ R.suppressDiagnostics();
+
if (SS.isSet() && isDependentScopeSpecifier(SS)) {
bool NotUnknownSpecialization = false;
DeclContext *DC = computeDeclContext(SS, false);
@@ -1085,7 +1123,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
if (!NotUnknownSpecialization) {
// When the scope specifier can refer to a member of an unknown
// specialization, we take it as a type name.
- BaseType = CheckTypenameType((NestedNameSpecifier *)SS.getScopeRep(),
+ BaseType = CheckTypenameType(ETK_None,
+ (NestedNameSpecifier *)SS.getScopeRep(),
*MemberOrBase, SS.getRange());
if (BaseType.isNull())
return true;
@@ -1096,7 +1135,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
// If no results were found, try to correct typos.
if (R.empty() && BaseType.isNull() &&
- CorrectTypo(R, S, &SS, ClassDecl) && R.isSingleResult()) {
+ CorrectTypo(R, S, &SS, ClassDecl, 0, CTC_NoKeywords) &&
+ R.isSingleResult()) {
if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) {
if (Member->getDeclContext()->getLookupContext()->Equals(ClassDecl)) {
// We have found a non-static data member with a similar
@@ -1236,7 +1276,6 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
QualType FieldType = Member->getType();
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
if (FieldType->isDependentType() || HasDependentArg) {
// Can't check initialization for a member of dependent type or when
// any of the arguments are type-dependent expressions.
@@ -1334,6 +1373,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
ExprTemporaries.end());
return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ /*IsVirtual=*/false,
LParenLoc,
BaseInit.takeAs<Expr>(),
RParenLoc);
@@ -1369,7 +1409,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// mem-initializer is ill-formed.
if (!DirectBaseSpec && !VirtualBaseSpec)
return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
- << BaseType << ClassDecl->getNameAsCString()
+ << BaseType << Context.getTypeDeclType(ClassDecl)
<< BaseTInfo->getTypeLoc().getSourceRange();
CXXBaseSpecifier *BaseSpec
@@ -1379,7 +1419,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// Initialize the base.
InitializedEntity BaseEntity =
- InitializedEntity::InitializeBase(Context, BaseSpec);
+ InitializedEntity::InitializeBase(Context, BaseSpec, VirtualBaseSpec);
InitializationKind Kind =
InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc);
@@ -1414,23 +1454,199 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
= Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
RParenLoc));
return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ BaseSpec->isVirtual(),
LParenLoc,
Init.takeAs<Expr>(),
RParenLoc);
}
return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ BaseSpec->isVirtual(),
LParenLoc,
BaseInit.takeAs<Expr>(),
RParenLoc);
}
+/// ImplicitInitializerKind - How an implicit base or member initializer should
+/// initialize its base or member.
+enum ImplicitInitializerKind {
+ IIK_Default,
+ IIK_Copy,
+ IIK_Move
+};
+
+static bool
+BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
+ ImplicitInitializerKind ImplicitInitKind,
+ CXXBaseSpecifier *BaseSpec,
+ bool IsInheritedVirtualBase,
+ CXXBaseOrMemberInitializer *&CXXBaseInit) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeBase(SemaRef.Context, BaseSpec,
+ IsInheritedVirtualBase);
+
+ Sema::OwningExprResult BaseInit(SemaRef);
+
+ switch (ImplicitInitKind) {
+ case IIK_Default: {
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0);
+ BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind,
+ Sema::MultiExprArg(SemaRef, 0, 0));
+ break;
+ }
+
+ case IIK_Copy: {
+ ParmVarDecl *Param = Constructor->getParamDecl(0);
+ QualType ParamType = Param->getType().getNonReferenceType();
+
+ Expr *CopyCtorArg =
+ DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param,
+ Constructor->getLocation(), ParamType, 0);
+
+ // Cast to the base class to avoid ambiguities.
+ QualType ArgTy =
+ SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(),
+ ParamType.getQualifiers());
+ SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy,
+ CastExpr::CK_UncheckedDerivedToBase,
+ /*isLvalue=*/true,
+ CXXBaseSpecifierArray(BaseSpec));
+
+ InitializationKind InitKind
+ = InitializationKind::CreateDirect(Constructor->getLocation(),
+ SourceLocation(), SourceLocation());
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind,
+ &CopyCtorArg, 1);
+ BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind,
+ Sema::MultiExprArg(SemaRef,
+ (void**)&CopyCtorArg, 1));
+ break;
+ }
+
+ case IIK_Move:
+ assert(false && "Unhandled initializer kind!");
+ }
+
+ BaseInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid())
+ return true;
+
+ CXXBaseInit =
+ new (SemaRef.Context) CXXBaseOrMemberInitializer(SemaRef.Context,
+ SemaRef.Context.getTrivialTypeSourceInfo(BaseSpec->getType(),
+ SourceLocation()),
+ BaseSpec->isVirtual(),
+ SourceLocation(),
+ BaseInit.takeAs<Expr>(),
+ SourceLocation());
+
+ return false;
+}
+
+static bool
+BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
+ ImplicitInitializerKind ImplicitInitKind,
+ FieldDecl *Field,
+ CXXBaseOrMemberInitializer *&CXXMemberInit) {
+ if (ImplicitInitKind == IIK_Copy) {
+ // FIXME: We should not return early here, but will do so until
+ // we know how to handle copy initialization of arrays.
+ CXXMemberInit = 0;
+ return false;
+
+ ParmVarDecl *Param = Constructor->getParamDecl(0);
+ QualType ParamType = Param->getType().getNonReferenceType();
+
+ Expr *MemberExprBase =
+ DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param,
+ SourceLocation(), ParamType, 0);
+
+
+ Expr *CopyCtorArg =
+ MemberExpr::Create(SemaRef.Context, MemberExprBase, /*IsArrow=*/false,
+ 0, SourceRange(), Field,
+ DeclAccessPair::make(Field, Field->getAccess()),
+ SourceLocation(), 0,
+ Field->getType().getNonReferenceType());
+
+ InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
+ InitializationKind InitKind =
+ InitializationKind::CreateDirect(Constructor->getLocation(),
+ SourceLocation(), SourceLocation());
+
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind,
+ &CopyCtorArg, 1);
+
+ Sema::OwningExprResult MemberInit =
+ InitSeq.Perform(SemaRef, InitEntity, InitKind,
+ Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArg, 1), 0);
+ if (MemberInit.isInvalid())
+ return true;
+
+ CXXMemberInit = 0;
+ return false;
+ }
+
+ assert(ImplicitInitKind == IIK_Default && "Unhandled implicit init kind!");
+
+ QualType FieldBaseElementType =
+ SemaRef.Context.getBaseElementType(Field->getType());
+
+ if (FieldBaseElementType->isRecordType()) {
+ InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
+ InitializationKind InitKind =
+ InitializationKind::CreateDefault(Constructor->getLocation());
+
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0);
+ Sema::OwningExprResult MemberInit =
+ InitSeq.Perform(SemaRef, InitEntity, InitKind,
+ Sema::MultiExprArg(SemaRef, 0, 0));
+ MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(MemberInit));
+ if (MemberInit.isInvalid())
+ return true;
+
+ CXXMemberInit =
+ new (SemaRef.Context) CXXBaseOrMemberInitializer(SemaRef.Context,
+ Field, SourceLocation(),
+ SourceLocation(),
+ MemberInit.takeAs<Expr>(),
+ SourceLocation());
+ return false;
+ }
+
+ if (FieldBaseElementType->isReferenceType()) {
+ SemaRef.Diag(Constructor->getLocation(),
+ diag::err_uninitialized_member_in_ctor)
+ << (int)Constructor->isImplicit()
+ << SemaRef.Context.getTagDeclType(Constructor->getParent())
+ << 0 << Field->getDeclName();
+ SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
+ return true;
+ }
+
+ if (FieldBaseElementType.isConstQualified()) {
+ SemaRef.Diag(Constructor->getLocation(),
+ diag::err_uninitialized_member_in_ctor)
+ << (int)Constructor->isImplicit()
+ << SemaRef.Context.getTagDeclType(Constructor->getParent())
+ << 1 << Field->getDeclName();
+ SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
+ return true;
+ }
+
+ // Nothing to initialize.
+ CXXMemberInit = 0;
+ return false;
+}
+
bool
Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
CXXBaseOrMemberInitializer **Initializers,
unsigned NumInitializers,
bool AnyErrors) {
- if (Constructor->isDependentContext()) {
+ if (Constructor->getDeclContext()->isDependentContext()) {
// Just store the initializers as written, they will be checked during
// instantiation.
if (NumInitializers > 0) {
@@ -1445,6 +1661,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
return false;
}
+ ImplicitInitializerKind ImplicitInitKind = IIK_Default;
+
+ // FIXME: Handle implicit move constructors.
+ if (Constructor->isImplicit() && Constructor->isCopyConstructor())
+ ImplicitInitKind = IIK_Copy;
+
// We need to build the initializer AST according to order of construction
// and not what user specified in the Initializers list.
CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition();
@@ -1464,7 +1686,13 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
AllBaseFields[Member->getMember()] = Member;
}
- llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit;
+ // Keep track of the direct virtual bases.
+ llvm::SmallPtrSet<CXXBaseSpecifier *, 16> DirectVBases;
+ for (CXXRecordDecl::base_class_iterator I = ClassDecl->bases_begin(),
+ E = ClassDecl->bases_end(); I != E; ++I) {
+ if (I->isVirtual())
+ DirectVBases.insert(I);
+ }
// Push virtual bases before others.
for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
@@ -1474,26 +1702,15 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
= AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
AllToInit.push_back(Value);
} else if (!AnyErrors) {
- InitializedEntity InitEntity
- = InitializedEntity::InitializeBase(Context, VBase);
- InitializationKind InitKind
- = InitializationKind::CreateDefault(Constructor->getLocation());
- InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
- OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
- MultiExprArg(*this, 0, 0));
- BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
- if (BaseInit.isInvalid()) {
+ bool IsInheritedVirtualBase = !DirectVBases.count(VBase);
+ CXXBaseOrMemberInitializer *CXXBaseInit;
+ if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind,
+ VBase, IsInheritedVirtualBase,
+ CXXBaseInit)) {
HadError = true;
continue;
}
-
- CXXBaseOrMemberInitializer *CXXBaseInit =
- new (Context) CXXBaseOrMemberInitializer(Context,
- Context.getTrivialTypeSourceInfo(VBase->getType(),
- SourceLocation()),
- SourceLocation(),
- BaseInit.takeAs<Expr>(),
- SourceLocation());
+
AllToInit.push_back(CXXBaseInit);
}
}
@@ -1508,26 +1725,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
= AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
AllToInit.push_back(Value);
} else if (!AnyErrors) {
- InitializedEntity InitEntity
- = InitializedEntity::InitializeBase(Context, Base);
- InitializationKind InitKind
- = InitializationKind::CreateDefault(Constructor->getLocation());
- InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
- OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
- MultiExprArg(*this, 0, 0));
- BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
- if (BaseInit.isInvalid()) {
+ CXXBaseOrMemberInitializer *CXXBaseInit;
+ if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind,
+ Base, /*IsInheritedVirtualBase=*/false,
+ CXXBaseInit)) {
HadError = true;
continue;
}
- CXXBaseOrMemberInitializer *CXXBaseInit =
- new (Context) CXXBaseOrMemberInitializer(Context,
- Context.getTrivialTypeSourceInfo(Base->getType(),
- SourceLocation()),
- SourceLocation(),
- BaseInit.takeAs<Expr>(),
- SourceLocation());
AllToInit.push_back(CXXBaseInit);
}
}
@@ -1560,54 +1765,19 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
continue;
}
- if ((*Field)->getType()->isDependentType() || AnyErrors)
+ if (AnyErrors)
continue;
- QualType FT = Context.getBaseElementType((*Field)->getType());
- if (FT->getAs<RecordType>()) {
- InitializedEntity InitEntity
- = InitializedEntity::InitializeMember(*Field);
- InitializationKind InitKind
- = InitializationKind::CreateDefault(Constructor->getLocation());
-
- InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
- OwningExprResult MemberInit = InitSeq.Perform(*this, InitEntity, InitKind,
- MultiExprArg(*this, 0, 0));
- MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit));
- if (MemberInit.isInvalid()) {
- HadError = true;
- continue;
- }
-
- // Don't attach synthesized member initializers in a dependent
- // context; they'll be regenerated a template instantiation
- // time.
- if (CurContext->isDependentContext())
- continue;
-
- CXXBaseOrMemberInitializer *Member =
- new (Context) CXXBaseOrMemberInitializer(Context,
- *Field, SourceLocation(),
- SourceLocation(),
- MemberInit.takeAs<Expr>(),
- SourceLocation());
-
- AllToInit.push_back(Member);
- }
- else if (FT->isReferenceType()) {
- Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
- << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl)
- << 0 << (*Field)->getDeclName();
- Diag((*Field)->getLocation(), diag::note_declared_at);
- HadError = true;
- }
- else if (FT.isConstQualified()) {
- Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
- << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl)
- << 1 << (*Field)->getDeclName();
- Diag((*Field)->getLocation(), diag::note_declared_at);
+ CXXBaseOrMemberInitializer *Member;
+ if (BuildImplicitMemberInitializer(*this, Constructor, ImplicitInitKind,
+ *Field, Member)) {
HadError = true;
+ continue;
}
+
+ // If the member doesn't need to be initialized, it will be null.
+ if (Member)
+ AllToInit.push_back(Member);
}
NumInitializers = AllToInit.size();
@@ -1657,11 +1827,20 @@ static void *GetKeyForMember(ASTContext &Context,
if (MemberMaybeAnon && Field->isAnonymousStructOrUnion())
Field = Member->getAnonUnionMember();
- // If the field is a member of an anonymous union, we use record decl of the
- // union as the key.
+ // If the field is a member of an anonymous struct or union, our key
+ // is the anonymous record decl that's a direct child of the class.
RecordDecl *RD = Field->getParent();
- if (RD->isAnonymousStructOrUnion() && RD->isUnion())
+ if (RD->isAnonymousStructOrUnion()) {
+ while (true) {
+ RecordDecl *Parent = cast<RecordDecl>(RD->getDeclContext());
+ if (Parent->isAnonymousStructOrUnion())
+ RD = Parent;
+ else
+ break;
+ }
+
return static_cast<void *>(RD);
+ }
return static_cast<void *>(Field);
}
@@ -1669,89 +1848,153 @@ static void *GetKeyForMember(ASTContext &Context,
static void
DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
const CXXConstructorDecl *Constructor,
- CXXBaseOrMemberInitializer **MemInits,
- unsigned NumMemInits) {
- if (Constructor->isDependentContext())
+ CXXBaseOrMemberInitializer **Inits,
+ unsigned NumInits) {
+ if (Constructor->getDeclContext()->isDependentContext())
return;
- if (SemaRef.Diags.getDiagnosticLevel(diag::warn_base_initialized) ==
- Diagnostic::Ignored &&
- SemaRef.Diags.getDiagnosticLevel(diag::warn_field_initialized) ==
- Diagnostic::Ignored)
+ if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order)
+ == Diagnostic::Ignored)
return;
- // Also issue warning if order of ctor-initializer list does not match order
- // of 1) base class declarations and 2) order of non-static data members.
- llvm::SmallVector<const void*, 32> AllBaseOrMembers;
+ // Build the list of bases and members in the order that they'll
+ // actually be initialized. The explicit initializers should be in
+ // this same order but may be missing things.
+ llvm::SmallVector<const void*, 32> IdealInitKeys;
const CXXRecordDecl *ClassDecl = Constructor->getParent();
- // Push virtual bases before others.
+ // 1. Virtual bases.
for (CXXRecordDecl::base_class_const_iterator VBase =
ClassDecl->vbases_begin(),
E = ClassDecl->vbases_end(); VBase != E; ++VBase)
- AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context,
- VBase->getType()));
+ IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, VBase->getType()));
+ // 2. Non-virtual bases.
for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
- // Virtuals are alread in the virtual base list and are constructed
- // first.
if (Base->isVirtual())
continue;
- AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context,
- Base->getType()));
+ IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, Base->getType()));
}
+ // 3. Direct fields.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
E = ClassDecl->field_end(); Field != E; ++Field)
- AllBaseOrMembers.push_back(GetKeyForTopLevelField(*Field));
+ IdealInitKeys.push_back(GetKeyForTopLevelField(*Field));
- int Last = AllBaseOrMembers.size();
- int curIndex = 0;
- CXXBaseOrMemberInitializer *PrevMember = 0;
- for (unsigned i = 0; i < NumMemInits; i++) {
- CXXBaseOrMemberInitializer *Member = MemInits[i];
- void *MemberInCtorList = GetKeyForMember(SemaRef.Context, Member, true);
+ unsigned NumIdealInits = IdealInitKeys.size();
+ unsigned IdealIndex = 0;
+
+ CXXBaseOrMemberInitializer *PrevInit = 0;
+ for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) {
+ CXXBaseOrMemberInitializer *Init = Inits[InitIndex];
+ void *InitKey = GetKeyForMember(SemaRef.Context, Init, true);
- for (; curIndex < Last; curIndex++)
- if (MemberInCtorList == AllBaseOrMembers[curIndex])
+ // Scan forward to try to find this initializer in the idealized
+ // initializers list.
+ for (; IdealIndex != NumIdealInits; ++IdealIndex)
+ if (InitKey == IdealInitKeys[IdealIndex])
break;
- if (curIndex == Last) {
- assert(PrevMember && "Member not in member list?!");
- // Initializer as specified in ctor-initializer list is out of order.
- // Issue a warning diagnostic.
- if (PrevMember->isBaseInitializer()) {
- // Diagnostics is for an initialized base class.
- Type *BaseClass = PrevMember->getBaseClass();
- SemaRef.Diag(PrevMember->getSourceLocation(),
- diag::warn_base_initialized)
- << QualType(BaseClass, 0);
- } else {
- FieldDecl *Field = PrevMember->getMember();
- SemaRef.Diag(PrevMember->getSourceLocation(),
- diag::warn_field_initialized)
- << Field->getNameAsString();
- }
- // Also the note!
- if (FieldDecl *Field = Member->getMember())
- SemaRef.Diag(Member->getSourceLocation(),
- diag::note_fieldorbase_initialized_here) << 0
- << Field->getNameAsString();
- else {
- Type *BaseClass = Member->getBaseClass();
- SemaRef.Diag(Member->getSourceLocation(),
- diag::note_fieldorbase_initialized_here) << 1
- << QualType(BaseClass, 0);
- }
- for (curIndex = 0; curIndex < Last; curIndex++)
- if (MemberInCtorList == AllBaseOrMembers[curIndex])
+
+ // If we didn't find this initializer, it must be because we
+ // scanned past it on a previous iteration. That can only
+ // happen if we're out of order; emit a warning.
+ if (IdealIndex == NumIdealInits) {
+ assert(PrevInit && "initializer not found in initializer list");
+
+ Sema::SemaDiagnosticBuilder D =
+ SemaRef.Diag(PrevInit->getSourceLocation(),
+ diag::warn_initializer_out_of_order);
+
+ if (PrevInit->isMemberInitializer())
+ D << 0 << PrevInit->getMember()->getDeclName();
+ else
+ D << 1 << PrevInit->getBaseClassInfo()->getType();
+
+ if (Init->isMemberInitializer())
+ D << 0 << Init->getMember()->getDeclName();
+ else
+ D << 1 << Init->getBaseClassInfo()->getType();
+
+ // Move back to the initializer's location in the ideal list.
+ for (IdealIndex = 0; IdealIndex != NumIdealInits; ++IdealIndex)
+ if (InitKey == IdealInitKeys[IdealIndex])
break;
+
+ assert(IdealIndex != NumIdealInits &&
+ "initializer not found in initializer list");
}
- PrevMember = Member;
+
+ PrevInit = Init;
}
}
+namespace {
+bool CheckRedundantInit(Sema &S,
+ CXXBaseOrMemberInitializer *Init,
+ CXXBaseOrMemberInitializer *&PrevInit) {
+ if (!PrevInit) {
+ PrevInit = Init;
+ return false;
+ }
+
+ if (FieldDecl *Field = Init->getMember())
+ S.Diag(Init->getSourceLocation(),
+ diag::err_multiple_mem_initialization)
+ << Field->getDeclName()
+ << Init->getSourceRange();
+ else {
+ Type *BaseClass = Init->getBaseClass();
+ assert(BaseClass && "neither field nor base");
+ S.Diag(Init->getSourceLocation(),
+ diag::err_multiple_base_initialization)
+ << QualType(BaseClass, 0)
+ << Init->getSourceRange();
+ }
+ S.Diag(PrevInit->getSourceLocation(), diag::note_previous_initializer)
+ << 0 << PrevInit->getSourceRange();
+
+ return true;
+}
+
+typedef std::pair<NamedDecl *, CXXBaseOrMemberInitializer *> UnionEntry;
+typedef llvm::DenseMap<RecordDecl*, UnionEntry> RedundantUnionMap;
+
+bool CheckRedundantUnionInit(Sema &S,
+ CXXBaseOrMemberInitializer *Init,
+ RedundantUnionMap &Unions) {
+ FieldDecl *Field = Init->getMember();
+ RecordDecl *Parent = Field->getParent();
+ if (!Parent->isAnonymousStructOrUnion())
+ return false;
+
+ NamedDecl *Child = Field;
+ do {
+ if (Parent->isUnion()) {
+ UnionEntry &En = Unions[Parent];
+ if (En.first && En.first != Child) {
+ S.Diag(Init->getSourceLocation(),
+ diag::err_multiple_mem_union_initialization)
+ << Field->getDeclName()
+ << Init->getSourceRange();
+ S.Diag(En.second->getSourceLocation(), diag::note_previous_initializer)
+ << 0 << En.second->getSourceRange();
+ return true;
+ } else if (!En.first) {
+ En.first = Child;
+ En.second = Init;
+ }
+ }
+
+ Child = Parent;
+ Parent = cast<RecordDecl>(Parent->getDeclContext());
+ } while (Parent->isAnonymousStructOrUnion());
+
+ return false;
+}
+}
+
/// ActOnMemInitializers - Handle the member initializers for a constructor.
void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
@@ -1772,34 +2015,29 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
CXXBaseOrMemberInitializer **MemInits =
reinterpret_cast<CXXBaseOrMemberInitializer **>(meminits);
-
+
+ // Mapping for the duplicate initializers check.
+ // For member initializers, this is keyed with a FieldDecl*.
+ // For base initializers, this is keyed with a Type*.
llvm::DenseMap<void*, CXXBaseOrMemberInitializer *> Members;
+
+ // Mapping for the inconsistent anonymous-union initializers check.
+ RedundantUnionMap MemberUnions;
+
bool HadError = false;
for (unsigned i = 0; i < NumMemInits; i++) {
- CXXBaseOrMemberInitializer *Member = MemInits[i];
+ CXXBaseOrMemberInitializer *Init = MemInits[i];
- void *KeyToMember = GetKeyForMember(Context, Member);
- CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember];
- if (!PrevMember) {
- PrevMember = Member;
- continue;
- }
- if (FieldDecl *Field = Member->getMember())
- Diag(Member->getSourceLocation(),
- diag::error_multiple_mem_initialization)
- << Field->getNameAsString()
- << Member->getSourceRange();
- else {
- Type *BaseClass = Member->getBaseClass();
- assert(BaseClass && "ActOnMemInitializers - neither field or base");
- Diag(Member->getSourceLocation(),
- diag::error_multiple_base_initialization)
- << QualType(BaseClass, 0)
- << Member->getSourceRange();
+ if (Init->isMemberInitializer()) {
+ FieldDecl *Field = Init->getMember();
+ if (CheckRedundantInit(*this, Init, Members[Field]) ||
+ CheckRedundantUnionInit(*this, Init, MemberUnions))
+ HadError = true;
+ } else {
+ void *Key = GetKeyForBase(Context, QualType(Init->getBaseClass(), 0));
+ if (CheckRedundantInit(*this, Init, Members[Key]))
+ HadError = true;
}
- Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
- << 0;
- HadError = true;
}
if (HadError)
@@ -2060,12 +2298,12 @@ namespace {
/// \brief Perform semantic checks on a class definition that has been
/// completing, introducing implicitly-declared members, checking for
/// abstract types, etc.
-void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
+void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
if (!Record || Record->isInvalidDecl())
return;
if (!Record->isDependentType())
- AddImplicitlyDeclaredMembersToClass(Record);
+ AddImplicitlyDeclaredMembersToClass(S, Record);
if (Record->isInvalidDecl())
return;
@@ -2141,6 +2379,30 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
if (Record->isAbstract() && !Record->isInvalidDecl())
(void)AbstractClassUsageDiagnoser(*this, Record);
+
+ // If this is not an aggregate type and has no user-declared constructor,
+ // complain about any non-static data members of reference or const scalar
+ // type, since they will never get initializers.
+ if (!Record->isInvalidDecl() && !Record->isDependentType() &&
+ !Record->isAggregate() && !Record->hasUserDeclaredConstructor()) {
+ bool Complained = false;
+ for (RecordDecl::field_iterator F = Record->field_begin(),
+ FEnd = Record->field_end();
+ F != FEnd; ++F) {
+ if (F->getType()->isReferenceType() ||
+ (F->getType().isConstQualified() && F->getType()->isScalarType())) {
+ if (!Complained) {
+ Diag(Record->getLocation(), diag::warn_no_constructor_for_refconst)
+ << Record->getTagKind() << Record;
+ Complained = true;
+ }
+
+ Diag(F->getLocation(), diag::note_refconst_member_not_initialized)
+ << F->getType()->isReferenceType()
+ << F->getDeclName();
+ }
+ }
+ }
}
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
@@ -2157,7 +2419,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
(DeclPtrTy*)FieldCollector->getCurFields(),
FieldCollector->getCurNumFields(), LBrac, RBrac, AttrList);
- CheckCompletedCXXClass(
+ CheckCompletedCXXClass(S,
dyn_cast_or_null<CXXRecordDecl>(TagDecl.getAs<Decl>()));
}
@@ -2166,7 +2428,10 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
/// constructor, or destructor, to the given C++ class (C++
/// [special]p1). This routine can only be executed just before the
/// definition of the class is complete.
-void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
+///
+/// The scope, if provided, is the class scope.
+void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S,
+ CXXRecordDecl *ClassDecl) {
CanQualType ClassType
= Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
@@ -2197,7 +2462,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
DefaultCon->setAccess(AS_public);
DefaultCon->setImplicit();
DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor());
- ClassDecl->addDecl(DefaultCon);
+ if (S)
+ PushOnScopeChains(DefaultCon, S, true);
+ else
+ ClassDecl->addDecl(DefaultCon);
}
if (!ClassDecl->hasUserDeclaredCopyConstructor()) {
@@ -2278,9 +2546,13 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
ClassDecl->getLocation(),
/*IdentifierInfo=*/0,
ArgType, /*TInfo=*/0,
+ VarDecl::None,
VarDecl::None, 0);
CopyConstructor->setParams(&FromParam, 1);
- ClassDecl->addDecl(CopyConstructor);
+ if (S)
+ PushOnScopeChains(CopyConstructor, S, true);
+ else
+ ClassDecl->addDecl(CopyConstructor);
}
if (!ClassDecl->hasUserDeclaredCopyAssignment()) {
@@ -2354,7 +2626,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
/*FIXME:*/false,
false, 0, 0,
FunctionType::ExtInfo()),
- /*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true);
+ /*TInfo=*/0, /*isStatic=*/false,
+ /*StorageClassAsWritten=*/FunctionDecl::None,
+ /*isInline=*/true);
CopyAssignment->setAccess(AS_public);
CopyAssignment->setImplicit();
CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
@@ -2363,14 +2637,18 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
ClassDecl->getLocation(),
- /*IdentifierInfo=*/0,
+ /*Id=*/0,
ArgType, /*TInfo=*/0,
+ VarDecl::None,
VarDecl::None, 0);
CopyAssignment->setParams(&FromParam, 1);
// Don't call addedAssignmentOperator. There is no way to distinguish an
// implicit from an explicit assignment operator.
- ClassDecl->addDecl(CopyAssignment);
+ if (S)
+ PushOnScopeChains(CopyAssignment, S, true);
+ else
+ ClassDecl->addDecl(CopyAssignment);
AddOverriddenMethods(ClassDecl, CopyAssignment);
}
@@ -2394,7 +2672,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
Destructor->setAccess(AS_public);
Destructor->setImplicit();
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
- ClassDecl->addDecl(Destructor);
+ if (S)
+ PushOnScopeChains(Destructor, S, true);
+ else
+ ClassDecl->addDecl(Destructor);
// This could be uniqued if it ever proves significant.
Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty));
@@ -2591,8 +2872,12 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
}
}
- // Notify the class that we've added a constructor.
- ClassDecl->addedConstructor(Context, Constructor);
+ // Notify the class that we've added a constructor. In principle we
+ // don't need to do this for out-of-line declarations; in practice
+ // we only instantiate the most recent declaration of a method, so
+ // we have to call this for everything but friends.
+ if (!Constructor->getFriendObjectKind())
+ ClassDecl->addedConstructor(Context, Constructor);
}
/// CheckDestructor - Checks a fully-formed destructor for well-formedness,
@@ -2737,6 +3022,9 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
D.setInvalidType();
SC = FunctionDecl::None;
}
+
+ QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId);
+
if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) {
// Conversion functions don't have return types, but the parser will
// happily parse something like:
@@ -2749,27 +3037,35 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
Diag(D.getIdentifierLoc(), diag::err_conv_function_return_type)
<< SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
<< SourceRange(D.getIdentifierLoc());
+ D.setInvalidType();
}
+ const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
+
// Make sure we don't have any parameters.
- if (R->getAs<FunctionProtoType>()->getNumArgs() > 0) {
+ if (Proto->getNumArgs() > 0) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params);
// Delete the parameters.
D.getTypeObject(0).Fun.freeArgs();
D.setInvalidType();
+ } else if (Proto->isVariadic()) {
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic);
+ D.setInvalidType();
}
- // Make sure the conversion function isn't variadic.
- if (R->getAs<FunctionProtoType>()->isVariadic() && !D.isInvalidType()) {
- Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic);
+ // Diagnose "&operator bool()" and other such nonsense. This
+ // is actually a gcc extension which we don't support.
+ if (Proto->getResultType() != ConvType) {
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_with_complex_decl)
+ << Proto->getResultType();
D.setInvalidType();
+ ConvType = Proto->getResultType();
}
// C++ [class.conv.fct]p4:
// The conversion-type-id shall not represent a function type nor
// an array type.
- QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId);
if (ConvType->isArrayType()) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array);
ConvType = Context.getPointerType(ConvType);
@@ -2783,14 +3079,15 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// Rebuild the function type "R" without any parameters (in case any
// of the errors above fired) and with the conversion type as the
// return type.
- const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
- R = Context.getFunctionType(ConvType, 0, 0, false,
- Proto->getTypeQuals(),
- Proto->hasExceptionSpec(),
- Proto->hasAnyExceptionSpec(),
- Proto->getNumExceptions(),
- Proto->exception_begin(),
- Proto->getExtInfo());
+ if (D.isInvalidType()) {
+ R = Context.getFunctionType(ConvType, 0, 0, false,
+ Proto->getTypeQuals(),
+ Proto->hasExceptionSpec(),
+ Proto->hasAnyExceptionSpec(),
+ Proto->getNumExceptions(),
+ Proto->exception_begin(),
+ Proto->getExtInfo());
+ }
// C++0x explicit conversion operators.
if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x)
@@ -2886,7 +3183,7 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// in that declarative region, it is treated as an original-namespace-name.
NamedDecl *PrevDecl
- = LookupSingleName(DeclRegionScope, II, LookupOrdinaryName,
+ = LookupSingleName(DeclRegionScope, II, IdentLoc, LookupOrdinaryName,
ForRedeclaration);
if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) {
@@ -3013,7 +3310,7 @@ void Sema::ActOnFinishNamespaceDef(DeclPtrTy D, SourceLocation RBrace) {
Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S,
SourceLocation UsingLoc,
SourceLocation NamespcLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *NamespcName,
AttributeList *AttrList) {
@@ -3082,7 +3379,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
AccessSpecifier AS,
bool HasUsingKeyword,
SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
bool IsTypeName,
@@ -3363,7 +3660,7 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {
/// the lookup differently for these declarations.
NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
DeclarationName Name,
AttributeList *AttrList,
@@ -3438,7 +3735,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
if (!LookupContext) return D;
UsingDecl *UD = cast<UsingDecl>(D);
- if (RequireCompleteDeclContext(SS)) {
+ if (RequireCompleteDeclContext(SS, LookupContext)) {
UD->setInvalidDecl();
return UD;
}
@@ -3700,7 +3997,7 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
SourceLocation NamespaceLoc,
SourceLocation AliasLoc,
IdentifierInfo *Alias,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *Ident) {
@@ -3709,8 +4006,13 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
LookupParsedName(R, S, &SS);
// Check if we have a previous declaration with the same name.
- if (NamedDecl *PrevDecl
- = LookupSingleName(S, Alias, LookupOrdinaryName, ForRedeclaration)) {
+ NamedDecl *PrevDecl
+ = LookupSingleName(S, Alias, AliasLoc, LookupOrdinaryName,
+ ForRedeclaration);
+ if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S))
+ PrevDecl = 0;
+
+ if (PrevDecl) {
if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
// We already have an alias with the same name that points to the same
// namespace, so don't create a new one.
@@ -3746,26 +4048,47 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
return DeclPtrTy::make(AliasDecl);
}
+namespace {
+ /// \brief Scoped object used to handle the state changes required in Sema
+ /// to implicitly define the body of a C++ member function;
+ class ImplicitlyDefinedFunctionScope {
+ Sema &S;
+ DeclContext *PreviousContext;
+
+ public:
+ ImplicitlyDefinedFunctionScope(Sema &S, CXXMethodDecl *Method)
+ : S(S), PreviousContext(S.CurContext)
+ {
+ S.CurContext = Method;
+ S.PushFunctionScope();
+ S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
+ }
+
+ ~ImplicitlyDefinedFunctionScope() {
+ S.PopExpressionEvaluationContext();
+ S.PopFunctionOrBlockScope();
+ S.CurContext = PreviousContext;
+ }
+ };
+}
+
void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *Constructor) {
assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() &&
!Constructor->isUsed()) &&
"DefineImplicitDefaultConstructor - call it for implicit default ctor");
- CXXRecordDecl *ClassDecl
- = cast<CXXRecordDecl>(Constructor->getDeclContext());
+ CXXRecordDecl *ClassDecl = Constructor->getParent();
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
- DeclContext *PreviousContext = CurContext;
- CurContext = Constructor;
+ ImplicitlyDefinedFunctionScope Scope(*this, Constructor);
if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
+ << CXXConstructor << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
} else {
Constructor->setUsed();
}
- CurContext = PreviousContext;
}
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
@@ -3775,8 +4098,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
- DeclContext *PreviousContext = CurContext;
- CurContext = Destructor;
+ ImplicitlyDefinedFunctionScope Scope(*this, Destructor);
MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(),
Destructor->getParent());
@@ -3788,114 +4110,429 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
<< CXXDestructor << Context.getTagDeclType(ClassDecl);
Destructor->setInvalidDecl();
- CurContext = PreviousContext;
-
return;
}
- CurContext = PreviousContext;
Destructor->setUsed();
}
-void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
- CXXMethodDecl *MethodDecl) {
- assert((MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
- MethodDecl->getOverloadedOperator() == OO_Equal &&
- !MethodDecl->isUsed()) &&
- "DefineImplicitOverloadedAssign - call it for implicit assignment op");
+/// \brief Builds a statement that copies the given entity from \p From to
+/// \c To.
+///
+/// This routine is used to copy the members of a class with an
+/// implicitly-declared copy assignment operator. When the entities being
+/// copied are arrays, this routine builds for loops to copy them.
+///
+/// \param S The Sema object used for type-checking.
+///
+/// \param Loc The location where the implicit copy is being generated.
+///
+/// \param T The type of the expressions being copied. Both expressions must
+/// have this type.
+///
+/// \param To The expression we are copying to.
+///
+/// \param From The expression we are copying from.
+///
+/// \param Depth Internal parameter recording the depth of the recursion.
+///
+/// \returns A statement or a loop that copies the expressions.
+static Sema::OwningStmtResult
+BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
+ Sema::OwningExprResult To, Sema::OwningExprResult From,
+ unsigned Depth = 0) {
+ typedef Sema::OwningStmtResult OwningStmtResult;
+ typedef Sema::OwningExprResult OwningExprResult;
+
+ // C++0x [class.copy]p30:
+ // Each subobject is assigned in the manner appropriate to its type:
+ //
+ // - if the subobject is of class type, the copy assignment operator
+ // for the class is used (as if by explicit qualification; that is,
+ // ignoring any possible virtual overriding functions in more derived
+ // classes);
+ if (const RecordType *RecordTy = T->getAs<RecordType>()) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
+
+ // Look for operator=.
+ DeclarationName Name
+ = S.Context.DeclarationNames.getCXXOperatorName(OO_Equal);
+ LookupResult OpLookup(S, Name, Loc, Sema::LookupOrdinaryName);
+ S.LookupQualifiedName(OpLookup, ClassDecl, false);
+
+ // Filter out any result that isn't a copy-assignment operator.
+ LookupResult::Filter F = OpLookup.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ if (Method->isCopyAssignmentOperator())
+ continue;
+
+ F.erase();
+ }
+ F.done();
+
+ // Create the nested-name-specifier that will be used to qualify the
+ // reference to operator=; this is required to suppress the virtual
+ // call mechanism.
+ CXXScopeSpec SS;
+ SS.setRange(Loc);
+ SS.setScopeRep(NestedNameSpecifier::Create(S.Context, 0, false,
+ T.getTypePtr()));
+
+ // Create the reference to operator=.
+ OwningExprResult OpEqualRef
+ = S.BuildMemberReferenceExpr(move(To), T, Loc, /*isArrow=*/false, SS,
+ /*FirstQualifierInScope=*/0, OpLookup,
+ /*TemplateArgs=*/0,
+ /*SuppressQualifierCheck=*/true);
+ if (OpEqualRef.isInvalid())
+ return S.StmtError();
+
+ // Build the call to the assignment operator.
+ Expr *FromE = From.takeAs<Expr>();
+ OwningExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0,
+ OpEqualRef.takeAs<Expr>(),
+ Loc, &FromE, 1, 0, Loc);
+ if (Call.isInvalid())
+ return S.StmtError();
+
+ return S.Owned(Call.takeAs<Stmt>());
+ }
+
+ // - if the subobject is of scalar type, the built-in assignment
+ // operator is used.
+ const ConstantArrayType *ArrayTy = S.Context.getAsConstantArrayType(T);
+ if (!ArrayTy) {
+ OwningExprResult Assignment = S.CreateBuiltinBinOp(Loc,
+ BinaryOperator::Assign,
+ To.takeAs<Expr>(),
+ From.takeAs<Expr>());
+ if (Assignment.isInvalid())
+ return S.StmtError();
+
+ return S.Owned(Assignment.takeAs<Stmt>());
+ }
+
+ // - if the subobject is an array, each element is assigned, in the
+ // manner appropriate to the element type;
+
+ // Construct a loop over the array bounds, e.g.,
+ //
+ // for (__SIZE_TYPE__ i0 = 0; i0 != array-size; ++i0)
+ //
+ // that will copy each of the array elements.
+ QualType SizeType = S.Context.getSizeType();
+
+ // Create the iteration variable.
+ IdentifierInfo *IterationVarName = 0;
+ {
+ llvm::SmallString<8> Str;
+ llvm::raw_svector_ostream OS(Str);
+ OS << "__i" << Depth;
+ IterationVarName = &S.Context.Idents.get(OS.str());
+ }
+ VarDecl *IterationVar = VarDecl::Create(S.Context, S.CurContext, Loc,
+ IterationVarName, SizeType,
+ S.Context.getTrivialTypeSourceInfo(SizeType, Loc),
+ VarDecl::None, VarDecl::None);
+
+ // Initialize the iteration variable to zero.
+ llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0);
+ IterationVar->setInit(new (S.Context) IntegerLiteral(Zero, SizeType, Loc));
+
+ // Create a reference to the iteration variable; we'll use this several
+ // times throughout.
+ Expr *IterationVarRef
+ = S.BuildDeclRefExpr(IterationVar, SizeType, Loc).takeAs<Expr>();
+ assert(IterationVarRef && "Reference to invented variable cannot fail!");
+
+ // Create the DeclStmt that holds the iteration variable.
+ Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(IterationVar),Loc,Loc);
+
+ // Create the comparison against the array bound.
+ llvm::APInt Upper = ArrayTy->getSize();
+ Upper.zextOrTrunc(S.Context.getTypeSize(SizeType));
+ OwningExprResult Comparison
+ = S.Owned(new (S.Context) BinaryOperator(IterationVarRef->Retain(),
+ new (S.Context) IntegerLiteral(Upper, SizeType, Loc),
+ BinaryOperator::NE, S.Context.BoolTy, Loc));
+
+ // Create the pre-increment of the iteration variable.
+ OwningExprResult Increment
+ = S.Owned(new (S.Context) UnaryOperator(IterationVarRef->Retain(),
+ UnaryOperator::PreInc,
+ SizeType, Loc));
+
+ // Subscript the "from" and "to" expressions with the iteration variable.
+ From = S.CreateBuiltinArraySubscriptExpr(move(From), Loc,
+ S.Owned(IterationVarRef->Retain()),
+ Loc);
+ To = S.CreateBuiltinArraySubscriptExpr(move(To), Loc,
+ S.Owned(IterationVarRef->Retain()),
+ Loc);
+ assert(!From.isInvalid() && "Builtin subscripting can't fail!");
+ assert(!To.isInvalid() && "Builtin subscripting can't fail!");
+
+ // Build the copy for an individual element of the array.
+ OwningStmtResult Copy = BuildSingleCopyAssign(S, Loc,
+ ArrayTy->getElementType(),
+ move(To), move(From), Depth+1);
+ if (Copy.isInvalid()) {
+ InitStmt->Destroy(S.Context);
+ return S.StmtError();
+ }
+
+ // Construct the loop that copies all elements of this array.
+ return S.ActOnForStmt(Loc, Loc, S.Owned(InitStmt),
+ S.MakeFullExpr(Comparison),
+ Sema::DeclPtrTy(),
+ S.MakeFullExpr(Increment),
+ Loc, move(Copy));
+}
- CXXRecordDecl *ClassDecl
- = cast<CXXRecordDecl>(MethodDecl->getDeclContext());
+void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
+ CXXMethodDecl *CopyAssignOperator) {
+ assert((CopyAssignOperator->isImplicit() &&
+ CopyAssignOperator->isOverloadedOperator() &&
+ CopyAssignOperator->getOverloadedOperator() == OO_Equal &&
+ !CopyAssignOperator->isUsed()) &&
+ "DefineImplicitCopyAssignment called for wrong function");
+
+ CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent();
- DeclContext *PreviousContext = CurContext;
- CurContext = MethodDecl;
+ if (ClassDecl->isInvalidDecl() || CopyAssignOperator->isInvalidDecl()) {
+ CopyAssignOperator->setInvalidDecl();
+ return;
+ }
+
+ CopyAssignOperator->setUsed();
- // C++[class.copy] p12
- // Before the implicitly-declared copy assignment operator for a class is
- // implicitly defined, all implicitly-declared copy assignment operators
- // for its direct base classes and its nonstatic data members shall have
- // been implicitly defined.
- bool err = false;
+ ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator);
+
+ // C++0x [class.copy]p30:
+ // The implicitly-defined or explicitly-defaulted copy assignment operator
+ // for a non-union class X performs memberwise copy assignment of its
+ // subobjects. The direct base classes of X are assigned first, in the
+ // order of their declaration in the base-specifier-list, and then the
+ // immediate non-static data members of X are assigned, in the order in
+ // which they were declared in the class definition.
+
+ // The statements that form the synthesized function body.
+ ASTOwningVector<&ActionBase::DeleteStmt> Statements(*this);
+
+ // The parameter for the "other" object, which we are copying from.
+ ParmVarDecl *Other = CopyAssignOperator->getParamDecl(0);
+ Qualifiers OtherQuals = Other->getType().getQualifiers();
+ QualType OtherRefType = Other->getType();
+ if (const LValueReferenceType *OtherRef
+ = OtherRefType->getAs<LValueReferenceType>()) {
+ OtherRefType = OtherRef->getPointeeType();
+ OtherQuals = OtherRefType.getQualifiers();
+ }
+
+ // Our location for everything implicitly-generated.
+ SourceLocation Loc = CopyAssignOperator->getLocation();
+
+ // Construct a reference to the "other" object. We'll be using this
+ // throughout the generated ASTs.
+ Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, Loc).takeAs<Expr>();
+ assert(OtherRef && "Reference to parameter cannot fail!");
+
+ // Construct the "this" pointer. We'll be using this throughout the generated
+ // ASTs.
+ Expr *This = ActOnCXXThis(Loc).takeAs<Expr>();
+ assert(This && "Reference to this cannot fail!");
+
+ // Assign base classes.
+ bool Invalid = false;
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (CXXMethodDecl *BaseAssignOpMethod =
- getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0),
- BaseClassDecl)) {
- CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
- BaseAssignOpMethod,
- PDiag(diag::err_access_assign_base)
- << Base->getType());
-
- MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod);
+ // Form the assignment:
+ // static_cast<Base*>(this)->Base::operator=(static_cast<Base&>(other));
+ QualType BaseType = Base->getType().getUnqualifiedType();
+ CXXRecordDecl *BaseClassDecl = 0;
+ if (const RecordType *BaseRecordT = BaseType->getAs<RecordType>())
+ BaseClassDecl = cast<CXXRecordDecl>(BaseRecordT->getDecl());
+ else {
+ Invalid = true;
+ continue;
+ }
+
+ // Construct the "from" expression, which is an implicit cast to the
+ // appropriately-qualified base type.
+ Expr *From = OtherRef->Retain();
+ ImpCastExprToType(From, Context.getQualifiedType(BaseType, OtherQuals),
+ CastExpr::CK_UncheckedDerivedToBase, /*isLvalue=*/true,
+ CXXBaseSpecifierArray(Base));
+
+ // Dereference "this".
+ OwningExprResult To = CreateBuiltinUnaryOp(Loc, UnaryOperator::Deref,
+ Owned(This->Retain()));
+
+ // Implicitly cast "this" to the appropriately-qualified base type.
+ Expr *ToE = To.takeAs<Expr>();
+ ImpCastExprToType(ToE,
+ Context.getCVRQualifiedType(BaseType,
+ CopyAssignOperator->getTypeQualifiers()),
+ CastExpr::CK_UncheckedDerivedToBase,
+ /*isLvalue=*/true, CXXBaseSpecifierArray(Base));
+ To = Owned(ToE);
+
+ // Build the copy.
+ OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType,
+ move(To), Owned(From));
+ if (Copy.isInvalid()) {
+ Invalid = true;
+ continue;
}
+
+ // Success! Record the copy.
+ Statements.push_back(Copy.takeAs<Expr>());
}
+
+ // \brief Reference to the __builtin_memcpy function.
+ Expr *BuiltinMemCpyRef = 0;
+
+ // Assign non-static members.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- E = ClassDecl->field_end(); Field != E; ++Field) {
- QualType FieldType = Context.getCanonicalType((*Field)->getType());
- if (const ArrayType *Array = Context.getAsArrayType(FieldType))
- FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (CXXMethodDecl *FieldAssignOpMethod =
- getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0),
- FieldClassDecl)) {
- CheckDirectMemberAccess(Field->getLocation(),
- FieldAssignOpMethod,
- PDiag(diag::err_access_assign_field)
- << Field->getDeclName() << Field->getType());
-
- MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod);
- }
- } else if (FieldType->isReferenceType()) {
+ FieldEnd = ClassDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ // Check for members of reference type; we can't copy those.
+ if (Field->getType()->isReferenceType()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
- << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
+ << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(CurrentLocation, diag::note_first_required_here);
- err = true;
- } else if (FieldType.isConstQualified()) {
+ Diag(Loc, diag::note_first_required_here);
+ Invalid = true;
+ continue;
+ }
+
+ // Check for members of const-qualified, non-class type.
+ QualType BaseType = Context.getBaseElementType(Field->getType());
+ if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
- << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
+ << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(CurrentLocation, diag::note_first_required_here);
- err = true;
+ Diag(Loc, diag::note_first_required_here);
+ Invalid = true;
+ continue;
}
+
+ QualType FieldType = Field->getType().getNonReferenceType();
+
+ // Build references to the field in the object we're copying from and to.
+ CXXScopeSpec SS; // Intentionally empty
+ LookupResult MemberLookup(*this, Field->getDeclName(), Loc,
+ LookupMemberName);
+ MemberLookup.addDecl(*Field);
+ MemberLookup.resolveKind();
+ OwningExprResult From = BuildMemberReferenceExpr(Owned(OtherRef->Retain()),
+ OtherRefType,
+ Loc, /*IsArrow=*/false,
+ SS, 0, MemberLookup, 0);
+ OwningExprResult To = BuildMemberReferenceExpr(Owned(This->Retain()),
+ This->getType(),
+ Loc, /*IsArrow=*/true,
+ SS, 0, MemberLookup, 0);
+ assert(!From.isInvalid() && "Implicit field reference cannot fail");
+ assert(!To.isInvalid() && "Implicit field reference cannot fail");
+
+ // If the field should be copied with __builtin_memcpy rather than via
+ // explicit assignments, do so. This optimization only applies for arrays
+ // of scalars and arrays of class type with trivial copy-assignment
+ // operators.
+ if (FieldType->isArrayType() &&
+ (!BaseType->isRecordType() ||
+ cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl())
+ ->hasTrivialCopyAssignment())) {
+ // Compute the size of the memory buffer to be copied.
+ QualType SizeType = Context.getSizeType();
+ llvm::APInt Size(Context.getTypeSize(SizeType),
+ Context.getTypeSizeInChars(BaseType).getQuantity());
+ for (const ConstantArrayType *Array
+ = Context.getAsConstantArrayType(FieldType);
+ Array;
+ Array = Context.getAsConstantArrayType(Array->getElementType())) {
+ llvm::APInt ArraySize = Array->getSize();
+ ArraySize.zextOrTrunc(Size.getBitWidth());
+ Size *= ArraySize;
+ }
+
+ // Take the address of the field references for "from" and "to".
+ From = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(From));
+ To = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(To));
+
+ // Create a reference to the __builtin_memcpy builtin function.
+ if (!BuiltinMemCpyRef) {
+ LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc,
+ LookupOrdinaryName);
+ LookupName(R, TUScope, true);
+
+ FunctionDecl *BuiltinMemCpy = R.getAsSingle<FunctionDecl>();
+ if (!BuiltinMemCpy) {
+ // Something went horribly wrong earlier, and we will have complained
+ // about it.
+ Invalid = true;
+ continue;
+ }
+
+ BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy,
+ BuiltinMemCpy->getType(),
+ Loc, 0).takeAs<Expr>();
+ assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
+ }
+
+ ASTOwningVector<&ActionBase::DeleteExpr> CallArgs(*this);
+ CallArgs.push_back(To.takeAs<Expr>());
+ CallArgs.push_back(From.takeAs<Expr>());
+ CallArgs.push_back(new (Context) IntegerLiteral(Size, SizeType, Loc));
+ llvm::SmallVector<SourceLocation, 4> Commas; // FIXME: Silly
+ Commas.push_back(Loc);
+ Commas.push_back(Loc);
+ OwningExprResult Call = ActOnCallExpr(/*Scope=*/0,
+ Owned(BuiltinMemCpyRef->Retain()),
+ Loc, move_arg(CallArgs),
+ Commas.data(), Loc);
+ assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
+ Statements.push_back(Call.takeAs<Expr>());
+ continue;
+ }
+
+ // Build the copy of this field.
+ OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, FieldType,
+ move(To), move(From));
+ if (Copy.isInvalid()) {
+ Invalid = true;
+ continue;
+ }
+
+ // Success! Record the copy.
+ Statements.push_back(Copy.takeAs<Stmt>());
}
- if (!err)
- MethodDecl->setUsed();
- CurContext = PreviousContext;
-}
+ if (!Invalid) {
+ // Add a "return *this;"
+ OwningExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UnaryOperator::Deref,
+ Owned(This->Retain()));
+
+ OwningStmtResult Return = ActOnReturnStmt(Loc, move(ThisObj));
+ if (Return.isInvalid())
+ Invalid = true;
+ else {
+ Statements.push_back(Return.takeAs<Stmt>());
+ }
+ }
-CXXMethodDecl *
-Sema::getAssignOperatorMethod(SourceLocation CurrentLocation,
- ParmVarDecl *ParmDecl,
- CXXRecordDecl *ClassDecl) {
- QualType LHSType = Context.getTypeDeclType(ClassDecl);
- QualType RHSType(LHSType);
- // If class's assignment operator argument is const/volatile qualified,
- // look for operator = (const/volatile B&). Otherwise, look for
- // operator = (B&).
- RHSType = Context.getCVRQualifiedType(RHSType,
- ParmDecl->getType().getCVRQualifiers());
- ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl,
- LHSType,
- SourceLocation()));
- ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl,
- RHSType,
- CurrentLocation));
- Expr *Args[2] = { &*LHS, &*RHS };
- OverloadCandidateSet CandidateSet(CurrentLocation);
- AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2,
- CandidateSet);
- OverloadCandidateSet::iterator Best;
- if (BestViableFunction(CandidateSet, CurrentLocation, Best) == OR_Success)
- return cast<CXXMethodDecl>(Best->Function);
- assert(false &&
- "getAssignOperatorMethod - copy assignment operator method not found");
- return 0;
+ if (Invalid) {
+ CopyAssignOperator->setInvalidDecl();
+ return;
+ }
+
+ OwningStmtResult Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements),
+ /*isStmtExpr=*/false);
+ assert(!Body.isInvalid() && "Compound statement creation cannot fail");
+ CopyAssignOperator->setBody(Body.takeAs<Stmt>());
}
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
@@ -3906,32 +4543,21 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
!CopyConstructor->isUsed()) &&
"DefineImplicitCopyConstructor - call it for implicit copy ctor");
- CXXRecordDecl *ClassDecl
- = cast<CXXRecordDecl>(CopyConstructor->getDeclContext());
+ CXXRecordDecl *ClassDecl = CopyConstructor->getParent();
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
- DeclContext *PreviousContext = CurContext;
- CurContext = CopyConstructor;
+ ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor);
- // C++ [class.copy] p209
- // Before the implicitly-declared copy constructor for a class is
- // implicitly defined, all the implicitly-declared copy constructors
- // for its base class and its non-static data members shall have been
- // implicitly defined.
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(Context, TypeQuals)) {
- CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
- BaseCopyCtor,
- PDiag(diag::err_access_copy_base)
- << Base->getType());
-
- MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor);
- }
+ if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false)) {
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
+ CopyConstructor->setInvalidDecl();
+ } else {
+ CopyConstructor->setUsed();
}
+
+ // FIXME: Once SetBaseOrMemberInitializers can handle copy initialization of
+ // fields, this code below should be removed.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
Field != FieldEnd; ++Field) {
@@ -3952,9 +4578,6 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
}
}
}
- CopyConstructor->setUsed();
-
- CurContext = PreviousContext;
}
Sema::OwningExprResult
@@ -3962,7 +4585,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor,
MultiExprArg ExprArgs,
bool RequiresZeroInit,
- bool BaseInitialization) {
+ CXXConstructExpr::ConstructionKind ConstructKind) {
bool Elidable = false;
// C++0x [class.copy]p34:
@@ -3984,7 +4607,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
Elidable, move(ExprArgs), RequiresZeroInit,
- BaseInitialization);
+ ConstructKind);
}
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
@@ -3994,14 +4617,14 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, bool Elidable,
MultiExprArg ExprArgs,
bool RequiresZeroInit,
- bool BaseInitialization) {
+ CXXConstructExpr::ConstructionKind ConstructKind) {
unsigned NumExprs = ExprArgs.size();
Expr **Exprs = (Expr **)ExprArgs.release();
MarkDeclarationReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
Constructor, Elidable, Exprs, NumExprs,
- RequiresZeroInit, BaseInitialization));
+ RequiresZeroInit, ConstructKind));
}
bool Sema::InitializeVarWithConstructor(VarDecl *VD,
@@ -4138,113 +4761,6 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
FinalizeVarWithDestructor(VDecl, Record);
}
-/// \brief Add the applicable constructor candidates for an initialization
-/// by constructor.
-static void AddConstructorInitializationCandidates(Sema &SemaRef,
- QualType ClassType,
- Expr **Args,
- unsigned NumArgs,
- InitializationKind Kind,
- OverloadCandidateSet &CandidateSet) {
- // C++ [dcl.init]p14:
- // If the initialization is direct-initialization, or if it is
- // copy-initialization where the cv-unqualified version of the
- // source type is the same class as, or a derived class of, the
- // class of the destination, constructors are considered. The
- // applicable constructors are enumerated (13.3.1.3), and the
- // best one is chosen through overload resolution (13.3). The
- // constructor so selected is called to initialize the object,
- // with the initializer expression(s) as its argument(s). If no
- // constructor applies, or the overload resolution is ambiguous,
- // the initialization is ill-formed.
- const RecordType *ClassRec = ClassType->getAs<RecordType>();
- assert(ClassRec && "Can only initialize a class type here");
-
- // FIXME: When we decide not to synthesize the implicitly-declared
- // constructors, we'll need to make them appear here.
-
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl());
- DeclarationName ConstructorName
- = SemaRef.Context.DeclarationNames.getCXXConstructorName(
- SemaRef.Context.getCanonicalType(ClassType).getUnqualifiedType());
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName);
- Con != ConEnd; ++Con) {
- DeclAccessPair FoundDecl = DeclAccessPair::make(*Con, (*Con)->getAccess());
-
- // Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = 0;
- FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con);
- if (ConstructorTmpl)
- Constructor
- = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
- else
- Constructor = cast<CXXConstructorDecl>(*Con);
-
- if ((Kind.getKind() == InitializationKind::IK_Direct) ||
- (Kind.getKind() == InitializationKind::IK_Value) ||
- (Kind.getKind() == InitializationKind::IK_Copy &&
- Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) ||
- ((Kind.getKind() == InitializationKind::IK_Default) &&
- Constructor->isDefaultConstructor())) {
- if (ConstructorTmpl)
- SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ 0,
- Args, NumArgs, CandidateSet);
- else
- SemaRef.AddOverloadCandidate(Constructor, FoundDecl,
- Args, NumArgs, CandidateSet);
- }
- }
-}
-
-/// \brief Attempt to perform initialization by constructor
-/// (C++ [dcl.init]p14), which may occur as part of direct-initialization or
-/// copy-initialization.
-///
-/// This routine determines whether initialization by constructor is possible,
-/// but it does not emit any diagnostics in the case where the initialization
-/// is ill-formed.
-///
-/// \param ClassType the type of the object being initialized, which must have
-/// class type.
-///
-/// \param Args the arguments provided to initialize the object
-///
-/// \param NumArgs the number of arguments provided to initialize the object
-///
-/// \param Kind the type of initialization being performed
-///
-/// \returns the constructor used to initialize the object, if successful.
-/// Otherwise, emits a diagnostic and returns NULL.
-CXXConstructorDecl *
-Sema::TryInitializationByConstructor(QualType ClassType,
- Expr **Args, unsigned NumArgs,
- SourceLocation Loc,
- InitializationKind Kind) {
- // Build the overload candidate set
- OverloadCandidateSet CandidateSet(Loc);
- AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind,
- CandidateSet);
-
- // Determine whether we found a constructor we can use.
- OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Loc, Best)) {
- case OR_Success:
- case OR_Deleted:
- // We found a constructor. Return it.
- return cast<CXXConstructorDecl>(Best->Function);
-
- case OR_No_Viable_Function:
- case OR_Ambiguous:
- // Overload resolution failed. Return nothing.
- return 0;
- }
-
- // Silence GCC warning
- return 0;
-}
-
/// \brief Given a constructor and the set of arguments provided for the
/// constructor, convert the arguments and add any required default arguments
/// to form a proper call to this constructor.
@@ -4281,472 +4797,6 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
return Invalid;
}
-/// CompareReferenceRelationship - Compare the two types T1 and T2 to
-/// determine whether they are reference-related,
-/// reference-compatible, reference-compatible with added
-/// qualification, or incompatible, for use in C++ initialization by
-/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference
-/// type, and the first type (T1) is the pointee type of the reference
-/// type being initialized.
-Sema::ReferenceCompareResult
-Sema::CompareReferenceRelationship(SourceLocation Loc,
- QualType OrigT1, QualType OrigT2,
- bool& DerivedToBase) {
- assert(!OrigT1->isReferenceType() &&
- "T1 must be the pointee type of the reference type");
- assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
-
- QualType T1 = Context.getCanonicalType(OrigT1);
- QualType T2 = Context.getCanonicalType(OrigT2);
- Qualifiers T1Quals, T2Quals;
- QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
- QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
-
- // C++ [dcl.init.ref]p4:
- // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
- // reference-related to "cv2 T2" if T1 is the same type as T2, or
- // T1 is a base class of T2.
- if (UnqualT1 == UnqualT2)
- DerivedToBase = false;
- else if (!RequireCompleteType(Loc, OrigT1, PDiag()) &&
- !RequireCompleteType(Loc, OrigT2, PDiag()) &&
- IsDerivedFrom(UnqualT2, UnqualT1))
- DerivedToBase = true;
- else
- return Ref_Incompatible;
-
- // At this point, we know that T1 and T2 are reference-related (at
- // least).
-
- // If the type is an array type, promote the element qualifiers to the type
- // for comparison.
- if (isa<ArrayType>(T1) && T1Quals)
- T1 = Context.getQualifiedType(UnqualT1, T1Quals);
- if (isa<ArrayType>(T2) && T2Quals)
- T2 = Context.getQualifiedType(UnqualT2, T2Quals);
-
- // C++ [dcl.init.ref]p4:
- // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is
- // reference-related to T2 and cv1 is the same cv-qualification
- // as, or greater cv-qualification than, cv2. For purposes of
- // overload resolution, cases for which cv1 is greater
- // cv-qualification than cv2 are identified as
- // reference-compatible with added qualification (see 13.3.3.2).
- if (T1Quals.getCVRQualifiers() == T2Quals.getCVRQualifiers())
- return Ref_Compatible;
- else if (T1.isMoreQualifiedThan(T2))
- return Ref_Compatible_With_Added_Qualification;
- else
- return Ref_Related;
-}
-
-/// CheckReferenceInit - Check the initialization of a reference
-/// variable with the given initializer (C++ [dcl.init.ref]). Init is
-/// the initializer (either a simple initializer or an initializer
-/// list), and DeclType is the type of the declaration. When ICS is
-/// non-null, this routine will compute the implicit conversion
-/// sequence according to C++ [over.ics.ref] and will not produce any
-/// diagnostics; when ICS is null, it will emit diagnostics when any
-/// errors are found. Either way, a return value of true indicates
-/// that there was a failure, a return value of false indicates that
-/// the reference initialization succeeded.
-///
-/// When @p SuppressUserConversions, user-defined conversions are
-/// suppressed.
-/// When @p AllowExplicit, we also permit explicit user-defined
-/// conversion functions.
-/// When @p ForceRValue, we unconditionally treat the initializer as an rvalue.
-/// When @p IgnoreBaseAccess, we don't do access control on to-base conversion.
-/// This is used when this is called from a C-style cast.
-bool
-Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
- SourceLocation DeclLoc,
- bool SuppressUserConversions,
- bool AllowExplicit, bool ForceRValue,
- ImplicitConversionSequence *ICS,
- bool IgnoreBaseAccess) {
- assert(DeclType->isReferenceType() && "Reference init needs a reference");
-
- QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType();
- QualType T2 = Init->getType();
-
- // If the initializer is the address of an overloaded function, try
- // to resolve the overloaded function. If all goes well, T2 is the
- // type of the resulting function.
- if (Context.getCanonicalType(T2) == Context.OverloadTy) {
- DeclAccessPair Found;
- FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType,
- ICS != 0, Found);
- if (Fn) {
- // Since we're performing this reference-initialization for
- // real, update the initializer with the resulting function.
- if (!ICS) {
- if (DiagnoseUseOfDecl(Fn, DeclLoc))
- return true;
-
- CheckAddressOfMemberAccess(Init, Found);
- Init = FixOverloadedFunctionReference(Init, Found, Fn);
- }
-
- T2 = Fn->getType();
- }
- }
-
- // Compute some basic properties of the types and the initializer.
- bool isRValRef = DeclType->isRValueReferenceType();
- bool DerivedToBase = false;
- Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression :
- Init->isLvalue(Context);
- ReferenceCompareResult RefRelationship
- = CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase);
-
- // Most paths end in a failed conversion.
- if (ICS) {
- ICS->setBad(BadConversionSequence::no_conversion, Init, DeclType);
- }
-
- // C++ [dcl.init.ref]p5:
- // A reference to type "cv1 T1" is initialized by an expression
- // of type "cv2 T2" as follows:
-
- // -- If the initializer expression
-
- // Rvalue references cannot bind to lvalues (N2812).
- // There is absolutely no situation where they can. In particular, note that
- // this is ill-formed, even if B has a user-defined conversion to A&&:
- // B b;
- // A&& r = b;
- if (isRValRef && InitLvalue == Expr::LV_Valid) {
- if (!ICS)
- Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref)
- << Init->getSourceRange();
- return true;
- }
-
- bool BindsDirectly = false;
- // -- is an lvalue (but is not a bit-field), and "cv1 T1" is
- // reference-compatible with "cv2 T2," or
- //
- // Note that the bit-field check is skipped if we are just computing
- // the implicit conversion sequence (C++ [over.best.ics]p2).
- if (InitLvalue == Expr::LV_Valid && (ICS || !Init->getBitField()) &&
- RefRelationship >= Ref_Compatible_With_Added_Qualification) {
- BindsDirectly = true;
-
- if (ICS) {
- // C++ [over.ics.ref]p1:
- // When a parameter of reference type binds directly (8.5.3)
- // to an argument expression, the implicit conversion sequence
- // is the identity conversion, unless the argument expression
- // 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->setStandard();
- ICS->Standard.First = ICK_Identity;
- ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
- ICS->Standard.Third = ICK_Identity;
- ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
- ICS->Standard.setToType(0, T2);
- ICS->Standard.setToType(1, T1);
- ICS->Standard.setToType(2, T1);
- ICS->Standard.ReferenceBinding = true;
- ICS->Standard.DirectBinding = true;
- ICS->Standard.RRefBinding = false;
- ICS->Standard.CopyConstructor = 0;
-
- // Nothing more to do: the inaccessibility/ambiguity check for
- // derived-to-base conversions is suppressed when we're
- // computing the implicit conversion sequence (C++
- // [over.best.ics]p2).
- return false;
- } else {
- // Perform the conversion.
- CastExpr::CastKind CK = CastExpr::CK_NoOp;
- if (DerivedToBase)
- CK = CastExpr::CK_DerivedToBase;
- else if(CheckExceptionSpecCompatibility(Init, T1))
- return true;
- ImpCastExprToType(Init, T1, CK, /*isLvalue=*/true);
- }
- }
-
- // -- has a class type (i.e., T2 is a class type) and can be
- // implicitly converted to an lvalue of type "cv3 T3,"
- // where "cv1 T1" is reference-compatible with "cv3 T3"
- // 92) (this conversion is selected by enumerating the
- // applicable conversion functions (13.3.1.6) and choosing
- // the best one through overload resolution (13.3)),
- if (!isRValRef && !SuppressUserConversions && T2->isRecordType() &&
- !RequireCompleteType(DeclLoc, T2, 0)) {
- CXXRecordDecl *T2RecordDecl
- = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
-
- OverloadCandidateSet CandidateSet(DeclLoc);
- const UnresolvedSetImpl *Conversions
- = T2RecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
- NamedDecl *D = *I;
- CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
- if (isa<UsingShadowDecl>(D))
- D = cast<UsingShadowDecl>(D)->getTargetDecl();
-
- FunctionTemplateDecl *ConvTemplate
- = dyn_cast<FunctionTemplateDecl>(D);
- CXXConversionDecl *Conv;
- if (ConvTemplate)
- Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
- else
- Conv = cast<CXXConversionDecl>(D);
-
- // If the conversion function doesn't return a reference type,
- // it can't be considered for this conversion.
- if (Conv->getConversionType()->isLValueReferenceType() &&
- (AllowExplicit || !Conv->isExplicit())) {
- if (ConvTemplate)
- AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC,
- Init, DeclType, CandidateSet);
- else
- AddConversionCandidate(Conv, I.getPair(), ActingDC, Init,
- DeclType, CandidateSet);
- }
- }
-
- OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, DeclLoc, Best)) {
- case OR_Success:
- // C++ [over.ics.ref]p1:
- //
- // [...] If the parameter binds directly to the result of
- // applying a conversion function to the argument
- // expression, the implicit conversion sequence is a
- // user-defined conversion sequence (13.3.3.1.2), with the
- // second standard conversion sequence either an identity
- // 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.
- if (!Best->FinalConversion.DirectBinding)
- break;
-
- // This is a direct binding.
- BindsDirectly = true;
-
- if (ICS) {
- ICS->setUserDefined();
- ICS->UserDefined.Before = Best->Conversions[0].Standard;
- ICS->UserDefined.After = Best->FinalConversion;
- ICS->UserDefined.ConversionFunction = Best->Function;
- ICS->UserDefined.EllipsisConversion = false;
- assert(ICS->UserDefined.After.ReferenceBinding &&
- ICS->UserDefined.After.DirectBinding &&
- "Expected a direct reference binding!");
- return false;
- } else {
- OwningExprResult InitConversion =
- BuildCXXCastArgument(DeclLoc, QualType(),
- CastExpr::CK_UserDefinedConversion,
- cast<CXXMethodDecl>(Best->Function),
- Owned(Init));
- Init = InitConversion.takeAs<Expr>();
-
- if (CheckExceptionSpecCompatibility(Init, T1))
- return true;
- ImpCastExprToType(Init, T1, CastExpr::CK_UserDefinedConversion,
- /*isLvalue=*/true);
- }
- break;
-
- case OR_Ambiguous:
- if (ICS) {
- ICS->setAmbiguous();
- for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
- Cand != CandidateSet.end(); ++Cand)
- if (Cand->Viable)
- ICS->Ambiguous.addConversion(Cand->Function);
- break;
- }
- Diag(DeclLoc, diag::err_ref_init_ambiguous) << DeclType << Init->getType()
- << Init->getSourceRange();
- PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, &Init, 1);
- return true;
-
- case OR_No_Viable_Function:
- case OR_Deleted:
- // There was no suitable conversion, or we found a deleted
- // conversion; continue with other checks.
- break;
- }
- }
-
- if (BindsDirectly) {
- // C++ [dcl.init.ref]p4:
- // [...] In all cases where the reference-related or
- // reference-compatible relationship of two types is used to
- // establish the validity of a reference binding, and T1 is a
- // base class of T2, a program that necessitates such a binding
- // is ill-formed if T1 is an inaccessible (clause 11) or
- // ambiguous (10.2) base class of T2.
- //
- // Note that we only check this condition when we're allowed to
- // complain about errors, because we should not be checking for
- // ambiguity (or inaccessibility) unless the reference binding
- // actually happens.
- if (DerivedToBase)
- return CheckDerivedToBaseConversion(T2, T1, DeclLoc,
- Init->getSourceRange(),
- IgnoreBaseAccess);
- else
- return false;
- }
-
- // -- Otherwise, the reference shall be to a 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 (!isRValRef && T1.getCVRQualifiers() != Qualifiers::Const) {
- if (!ICS)
- Diag(DeclLoc, diag::err_not_reference_to_const_init)
- << T1.isVolatileQualified()
- << T1 << int(InitLvalue != Expr::LV_Valid)
- << T2 << Init->getSourceRange();
- return true;
- }
-
- // -- If the initializer expression is an rvalue, with T2 a
- // class type, and "cv1 T1" is reference-compatible with
- // "cv2 T2," the reference is bound in one of the
- // following ways (the choice is implementation-defined):
- //
- // -- The reference is bound to the object represented by
- // the rvalue (see 3.10) or to a sub-object within that
- // object.
- //
- // -- A temporary of type "cv1 T2" [sic] is created, and
- // a constructor is called to copy the entire rvalue
- // object into the temporary. The reference is bound to
- // the temporary or to a sub-object within the
- // temporary.
- //
- // The constructor that would be used to make the copy
- // shall be callable whether or not the copy is actually
- // done.
- //
- // Note that C++0x [dcl.init.ref]p5 takes away this implementation
- // freedom, so we will always take the first option and never build
- // a temporary in this case. FIXME: We will, however, have to check
- // for the presence of a copy constructor in C++98/03 mode.
- if (InitLvalue != Expr::LV_Valid && T2->isRecordType() &&
- RefRelationship >= Ref_Compatible_With_Added_Qualification) {
- if (ICS) {
- ICS->setStandard();
- ICS->Standard.First = ICK_Identity;
- ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
- ICS->Standard.Third = ICK_Identity;
- ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
- ICS->Standard.setToType(0, T2);
- ICS->Standard.setToType(1, T1);
- ICS->Standard.setToType(2, T1);
- ICS->Standard.ReferenceBinding = true;
- ICS->Standard.DirectBinding = false;
- ICS->Standard.RRefBinding = isRValRef;
- ICS->Standard.CopyConstructor = 0;
- } else {
- CastExpr::CastKind CK = CastExpr::CK_NoOp;
- if (DerivedToBase)
- CK = CastExpr::CK_DerivedToBase;
- else if(CheckExceptionSpecCompatibility(Init, T1))
- return true;
- ImpCastExprToType(Init, T1, CK, /*isLvalue=*/false);
- }
- return false;
- }
-
- // -- Otherwise, a temporary of type "cv1 T1" is created and
- // initialized from the initializer expression using the
- // rules for a non-reference copy initialization (8.5). The
- // reference is then bound to the temporary. 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.
- if (RefRelationship == Ref_Related) {
- // If cv1 == cv2 or cv1 is a greater cv-qualified than cv2, then
- // we would be reference-compatible or reference-compatible with
- // added qualification. But that wasn't the case, so the reference
- // initialization fails.
- if (!ICS)
- Diag(DeclLoc, diag::err_reference_init_drops_quals)
- << T1 << int(InitLvalue != Expr::LV_Valid)
- << T2 << Init->getSourceRange();
- return true;
- }
-
- // If at least one of the types is a class type, the types are not
- // related, and we aren't allowed any user conversions, the
- // reference binding fails. This case is important for breaking
- // recursion, since TryImplicitConversion below will attempt to
- // create a temporary through the use of a copy constructor.
- if (SuppressUserConversions && RefRelationship == Ref_Incompatible &&
- (T1->isRecordType() || T2->isRecordType())) {
- if (!ICS)
- Diag(DeclLoc, diag::err_typecheck_convert_incompatible)
- << DeclType << Init->getType() << AA_Initializing << Init->getSourceRange();
- return true;
- }
-
- // Actually try to convert the initializer to T1.
- if (ICS) {
- // C++ [over.ics.ref]p2:
- //
- // When a parameter of reference type is not bound directly to
- // an argument expression, the conversion sequence is the one
- // required to convert the argument expression to the
- // underlying type of the reference according to
- // 13.3.3.1. Conceptually, this conversion sequence corresponds
- // to copy-initializing a temporary of the underlying type with
- // the argument expression. Any difference in top-level
- // cv-qualification is subsumed by the initialization itself
- // and does not constitute a conversion.
- *ICS = TryImplicitConversion(Init, T1, SuppressUserConversions,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
-
- // Of course, that's still a reference binding.
- if (ICS->isStandard()) {
- ICS->Standard.ReferenceBinding = true;
- ICS->Standard.RRefBinding = isRValRef;
- } else if (ICS->isUserDefined()) {
- ICS->UserDefined.After.ReferenceBinding = true;
- ICS->UserDefined.After.RRefBinding = isRValRef;
- }
- return ICS->isBad();
- } else {
- ImplicitConversionSequence Conversions;
- bool badConversion = PerformImplicitConversion(Init, T1, AA_Initializing,
- false, false,
- Conversions);
- if (badConversion) {
- if (Conversions.isAmbiguous()) {
- Diag(DeclLoc,
- diag::err_lvalue_to_rvalue_ambig_ref) << Init->getSourceRange();
- for (int j = Conversions.Ambiguous.conversions().size()-1;
- j >= 0; j--) {
- FunctionDecl *Func = Conversions.Ambiguous.conversions()[j];
- NoteOverloadCandidate(Func);
- }
- }
- else {
- if (isRValRef)
- Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref)
- << Init->getSourceRange();
- else
- Diag(DeclLoc, diag::err_invalid_initialization)
- << DeclType << Init->getType() << Init->getSourceRange();
- }
- }
- return badConversion;
- }
-}
-
static inline bool
CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef,
const FunctionDecl *FnDecl) {
@@ -5044,17 +5094,32 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
bool Valid = false;
- // FIXME: Check for the one valid template signature
- // template <char...> type operator "" name();
-
- if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) {
+ // template <char...> type operator "" name() is the only valid template
+ // signature, and the only valid signature with no parameters.
+ if (FnDecl->param_size() == 0) {
+ if (FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate()) {
+ // Must have only one template parameter
+ TemplateParameterList *Params = TpDecl->getTemplateParameters();
+ if (Params->size() == 1) {
+ NonTypeTemplateParmDecl *PmDecl =
+ cast<NonTypeTemplateParmDecl>(Params->getParam(0));
+
+ // The template parameter must be a char parameter pack.
+ // FIXME: This test will always fail because non-type parameter packs
+ // have not been implemented.
+ if (PmDecl && PmDecl->isTemplateParameterPack() &&
+ Context.hasSameType(PmDecl->getType(), Context.CharTy))
+ Valid = true;
+ }
+ }
+ } else {
// Check the first parameter
+ FunctionDecl::param_iterator Param = FnDecl->param_begin();
+
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
+ // unsigned long long int, long double, and any character type are allowed
+ // as the only parameters.
if (Context.hasSameType(T, Context.UnsignedLongLongTy) ||
Context.hasSameType(T, Context.LongDoubleTy) ||
Context.hasSameType(T, Context.CharTy) ||
@@ -5066,7 +5131,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
goto FinishedParams;
}
- // Otherwise it must be a pointer to const; let's strip those.
+ // Otherwise it must be a pointer to const; let's strip those qualifiers.
const PointerType *PT = T->getAs<PointerType>();
if (!PT)
goto FinishedParams;
@@ -5121,13 +5186,12 @@ FinishedParams:
Sema::DeclPtrTy Sema::ActOnStartLinkageSpecification(Scope *S,
SourceLocation ExternLoc,
SourceLocation LangLoc,
- const char *Lang,
- unsigned StrSize,
+ llvm::StringRef Lang,
SourceLocation LBraceLoc) {
LinkageSpecDecl::LanguageIDs Language;
- if (strncmp(Lang, "\"C\"", StrSize) == 0)
+ if (Lang == "\"C\"")
Language = LinkageSpecDecl::lang_c;
- else if (strncmp(Lang, "\"C++\"", StrSize) == 0)
+ else if (Lang == "\"C++\"")
Language = LinkageSpecDecl::lang_cxx;
else {
Diag(LangLoc, diag::err_bad_language);
@@ -5212,8 +5276,10 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
Invalid = true;
VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc,
- Name, ExDeclType, TInfo, VarDecl::None);
-
+ Name, ExDeclType, TInfo, VarDecl::None,
+ VarDecl::None);
+ ExDecl->setExceptionVariable(true);
+
if (!Invalid) {
if (const RecordType *RecordTy = ExDeclType->getAs<RecordType>()) {
// C++ [except.handle]p16:
@@ -5254,7 +5320,9 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
bool Invalid = D.isInvalidType();
IdentifierInfo *II = D.getIdentifier();
- if (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) {
+ if (NamedDecl *PrevDecl = LookupSingleName(S, II, D.getIdentifierLoc(),
+ LookupOrdinaryName,
+ ForRedeclaration)) {
// The scope should be freshly made just for us. There is just no way
// it contains any previous declaration.
assert(!S->isDeclScope(DeclPtrTy::make(PrevDecl)));
@@ -5318,6 +5386,62 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
return DeclPtrTy::make(Decl);
}
+/// \brief Perform semantic analysis of the given friend type declaration.
+///
+/// \returns A friend declaration that.
+FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc,
+ TypeSourceInfo *TSInfo) {
+ assert(TSInfo && "NULL TypeSourceInfo for friend type declaration");
+
+ QualType T = TSInfo->getType();
+ SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange();
+
+ if (!getLangOptions().CPlusPlus0x) {
+ // C++03 [class.friend]p2:
+ // An elaborated-type-specifier shall be used in a friend declaration
+ // for a class.*
+ //
+ // * The class-key of the elaborated-type-specifier is required.
+ if (!ActiveTemplateInstantiations.empty()) {
+ // Do not complain about the form of friend template types during
+ // template instantiation; we will already have complained when the
+ // template was declared.
+ } else if (!T->isElaboratedTypeSpecifier()) {
+ // If we evaluated the type to a record type, suggest putting
+ // a tag in front.
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ RecordDecl *RD = RT->getDecl();
+
+ std::string InsertionText = std::string(" ") + RD->getKindName();
+
+ Diag(TypeRange.getBegin(), diag::ext_unelaborated_friend_type)
+ << (unsigned) RD->getTagKind()
+ << T
+ << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc),
+ InsertionText);
+ } else {
+ Diag(FriendLoc, diag::ext_nonclass_type_friend)
+ << T
+ << SourceRange(FriendLoc, TypeRange.getEnd());
+ }
+ } else if (T->getAs<EnumType>()) {
+ Diag(FriendLoc, diag::ext_enum_friend)
+ << T
+ << SourceRange(FriendLoc, TypeRange.getEnd());
+ }
+ }
+
+ // C++0x [class.friend]p3:
+ // If the type specifier in a friend declaration designates a (possibly
+ // cv-qualified) class type, that class is declared as a friend; otherwise,
+ // the friend declaration is ignored.
+
+ // FIXME: C++0x has some syntactic restrictions on friend type declarations
+ // in [class.friend]p3 that we do not implement.
+
+ return FriendDecl::Create(Context, CurContext, FriendLoc, TSInfo, FriendLoc);
+}
+
/// Handle a friend type declaration. This works in tandem with
/// ActOnTag.
///
@@ -5351,6 +5475,9 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
if (TheDeclarator.isInvalidType())
return DeclPtrTy();
+ if (!TSI)
+ TSI = Context.getTrivialTypeSourceInfo(T, DS.getSourceRange().getBegin());
+
// This is definitely an error in C++98. It's probably meant to
// be forbidden in C++0x, too, but the specification is just
// poorly written.
@@ -5370,41 +5497,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
<< DS.getSourceRange();
return DeclPtrTy();
}
-
- // C++ [class.friend]p2:
- // An elaborated-type-specifier shall be used in a friend declaration
- // for a class.*
- // * The class-key of the elaborated-type-specifier is required.
- // This is one of the rare places in Clang where it's legitimate to
- // ask about the "spelling" of the type.
- if (!getLangOptions().CPlusPlus0x && !T->isElaboratedTypeSpecifier()) {
- // If we evaluated the type to a record type, suggest putting
- // a tag in front.
- if (const RecordType *RT = T->getAs<RecordType>()) {
- RecordDecl *RD = RT->getDecl();
-
- std::string InsertionText = std::string(" ") + RD->getKindName();
-
- Diag(DS.getTypeSpecTypeLoc(), diag::err_unelaborated_friend_type)
- << (unsigned) RD->getTagKind()
- << T
- << SourceRange(DS.getFriendSpecLoc())
- << FixItHint::CreateInsertion(DS.getTypeSpecTypeLoc(), InsertionText);
- return DeclPtrTy();
- }else {
- Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
- << DS.getSourceRange();
- return DeclPtrTy();
- }
- }
-
- // Enum types cannot be friends.
- if (T->getAs<EnumType>()) {
- Diag(DS.getTypeSpecTypeLoc(), diag::err_enum_friend)
- << SourceRange(DS.getFriendSpecLoc());
- return DeclPtrTy();
- }
-
+
// C++98 [class.friend]p1: A friend of a class is a function
// or class that is not a member of the class . . .
// This is fixed in DR77, which just barely didn't make the C++03
@@ -5417,15 +5510,18 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// friend a member of an arbitrary specialization of your template).
Decl *D;
- if (TempParams.size())
+ if (unsigned NumTempParamLists = TempParams.size())
D = FriendTemplateDecl::Create(Context, CurContext, Loc,
- TempParams.size(),
+ NumTempParamLists,
(TemplateParameterList**) TempParams.release(),
TSI,
DS.getFriendSpecLoc());
else
- D = FriendDecl::Create(Context, CurContext, Loc, TSI,
- DS.getFriendSpecLoc());
+ D = CheckFriendTypeDecl(DS.getFriendSpecLoc(), TSI);
+
+ if (!D)
+ return DeclPtrTy();
+
D->setAccess(AS_public);
CurContext->addDecl(D);
@@ -5493,11 +5589,11 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
LookupResult Previous(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName,
ForRedeclaration);
if (!ScopeQual.isInvalid() && ScopeQual.isSet()) {
- // FIXME: RequireCompleteDeclContext
DC = computeDeclContext(ScopeQual);
// FIXME: handle dependent contexts
if (!DC) return DeclPtrTy();
+ if (RequireCompleteDeclContext(ScopeQual, DC)) return DeclPtrTy();
LookupQualifiedName(Previous, DC);
@@ -5595,9 +5691,6 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
FrD->setAccess(AS_public);
CurContext->addDecl(FrD);
- if (D.getName().getKind() == UnqualifiedId::IK_TemplateId)
- FrD->setSpecialization(true);
-
return DeclPtrTy::make(ND);
}
@@ -5701,10 +5794,10 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
// Check if we the conversion from derived to base is valid.
if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy,
- diag::err_covariant_return_inaccessible_base,
- diag::err_covariant_return_ambiguous_derived_to_base_conv,
- // FIXME: Should this point to the return type?
- New->getLocation(), SourceRange(), New->getDeclName())) {
+ diag::err_covariant_return_inaccessible_base,
+ diag::err_covariant_return_ambiguous_derived_to_base_conv,
+ // FIXME: Should this point to the return type?
+ New->getLocation(), SourceRange(), New->getDeclName(), 0)) {
Diag(Old->getLocation(), diag::note_overridden_virtual_function);
return true;
}
@@ -5830,7 +5923,7 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
return Dcl;
}
-static bool needsVtable(CXXMethodDecl *MD, ASTContext &Context) {
+static bool needsVTable(CXXMethodDecl *MD, ASTContext &Context) {
// Ignore dependent types.
if (MD->isDependentContext())
return false;
@@ -5893,7 +5986,7 @@ void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc,
// We will need to mark all of the virtual members as referenced to build the
// vtable.
- if (!needsVtable(MD, Context))
+ if (!needsVTable(MD, Context))
return;
TemplateSpecializationKind kind = RD->getTemplateSpecializationKind();
@@ -5944,3 +6037,44 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
MarkVirtualMembersReferenced(Loc, Base);
}
}
+
+/// SetIvarInitializers - This routine builds initialization ASTs for the
+/// Objective-C implementation whose ivars need be initialized.
+void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
+ if (!getLangOptions().CPlusPlus)
+ return;
+ if (const ObjCInterfaceDecl *OID = ObjCImplementation->getClassInterface()) {
+ llvm::SmallVector<ObjCIvarDecl*, 8> ivars;
+ CollectIvarsToConstructOrDestruct(OID, ivars);
+ if (ivars.empty())
+ return;
+ llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
+ for (unsigned i = 0; i < ivars.size(); i++) {
+ FieldDecl *Field = ivars[i];
+ CXXBaseOrMemberInitializer *Member;
+ InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
+ InitializationKind InitKind =
+ InitializationKind::CreateDefault(ObjCImplementation->getLocation());
+
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ Sema::OwningExprResult MemberInit =
+ InitSeq.Perform(*this, InitEntity, InitKind,
+ Sema::MultiExprArg(*this, 0, 0));
+ MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit));
+ // Note, MemberInit could actually come back empty if no initialization
+ // is required (e.g., because it would call a trivial default constructor)
+ if (!MemberInit.get() || MemberInit.isInvalid())
+ continue;
+
+ Member =
+ new (Context) CXXBaseOrMemberInitializer(Context,
+ Field, SourceLocation(),
+ SourceLocation(),
+ MemberInit.takeAs<Expr>(),
+ SourceLocation());
+ AllToInit.push_back(Member);
+ }
+ ObjCImplementation->setIvarInitializers(Context,
+ AllToInit.data(), AllToInit.size());
+ }
+}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 0c47e63..d446cc1 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -66,13 +66,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
assert(ClassName && "Missing class identifier");
// Check for another declaration kind with the same name.
- NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
- if (PrevDecl && PrevDecl->isTemplateParameter()) {
- // Maybe we will complain about the shadowed template parameter.
- DiagnoseTemplateParameterShadow(ClassLoc, PrevDecl);
- // Just pretend that we didn't see the previous declaration.
- PrevDecl = 0;
- }
+ NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, ClassLoc,
+ LookupOrdinaryName, ForRedeclaration);
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
@@ -98,6 +93,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
// Since this ObjCInterfaceDecl was created by a forward declaration,
// we now add it to the DeclContext since it wasn't added before
// (see ActOnForwardClassDeclaration).
+ IDecl->setLexicalDeclContext(CurContext);
CurContext->addDecl(IDecl);
if (AttrList)
@@ -114,12 +110,13 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (SuperName) {
// Check if a different kind of symbol declared in this scope.
- PrevDecl = LookupSingleName(TUScope, SuperName, LookupOrdinaryName);
+ PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc,
+ LookupOrdinaryName);
if (!PrevDecl) {
// Try to correct for a typo in the superclass name.
LookupResult R(*this, SuperName, SuperLoc, LookupOrdinaryName);
- if (CorrectTypo(R, TUScope, 0) &&
+ if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
(PrevDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
Diag(SuperLoc, diag::err_undef_superclass_suggest)
<< SuperName << ClassName << PrevDecl->getDeclName();
@@ -198,7 +195,8 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
IdentifierInfo *ClassName,
SourceLocation ClassLocation) {
// Look for previous declaration of alias name
- NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, LookupOrdinaryName);
+ NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, AliasLocation,
+ LookupOrdinaryName, ForRedeclaration);
if (ADecl) {
if (isa<ObjCCompatibleAliasDecl>(ADecl))
Diag(AliasLocation, diag::warn_previous_alias_decl);
@@ -208,13 +206,15 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
return DeclPtrTy();
}
// Check for class declaration
- NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
+ NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation,
+ LookupOrdinaryName, ForRedeclaration);
if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(CDeclU)) {
QualType T = TDecl->getUnderlyingType();
if (T->isObjCInterfaceType()) {
if (NamedDecl *IDecl = T->getAs<ObjCInterfaceType>()->getDecl()) {
ClassName = IDecl->getIdentifier();
- CDeclU = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
+ CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation,
+ LookupOrdinaryName, ForRedeclaration);
}
}
}
@@ -243,7 +243,8 @@ void Sema::CheckForwardProtocolDeclarationForCircularDependency(
for (ObjCList<ObjCProtocolDecl>::iterator I = PList.begin(),
E = PList.end(); I != E; ++I) {
- if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier())) {
+ if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier(),
+ Ploc)) {
if (PDecl->getIdentifier() == PName) {
Diag(Ploc, diag::err_protocol_has_circular_dependency);
Diag(PrevLoc, diag::note_previous_definition);
@@ -265,7 +266,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
AttributeList *AttrList) {
// FIXME: Deal with AttrList.
assert(ProtocolName && "Missing protocol identifier");
- ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName);
+ ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName, ProtocolLoc);
if (PDecl) {
// Protocol already seen. Better be a forward protocol declaration
if (!PDecl->isForwardDecl()) {
@@ -312,11 +313,12 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
unsigned NumProtocols,
llvm::SmallVectorImpl<DeclPtrTy> &Protocols) {
for (unsigned i = 0; i != NumProtocols; ++i) {
- ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first);
+ ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first,
+ ProtocolId[i].second);
if (!PDecl) {
LookupResult R(*this, ProtocolId[i].first, ProtocolId[i].second,
LookupObjCProtocolName);
- if (CorrectTypo(R, TUScope, 0) &&
+ if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
(PDecl = R.getAsSingle<ObjCProtocolDecl>())) {
Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest)
<< ProtocolId[i].first << R.getLookupName();
@@ -382,7 +384,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
for (unsigned i = 0; i != NumElts; ++i) {
IdentifierInfo *Ident = IdentList[i].first;
- ObjCProtocolDecl *PDecl = LookupProtocol(Ident);
+ ObjCProtocolDecl *PDecl = LookupProtocol(Ident, IdentList[i].second);
if (PDecl == 0) { // Not already seen?
PDecl = ObjCProtocolDecl::Create(Context, CurContext,
IdentList[i].second, Ident);
@@ -413,7 +415,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc) {
ObjCCategoryDecl *CDecl = 0;
- ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc);
+ ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true);
/// Check that class of this category is already completely declared.
if (!IDecl || IDecl->isForwardDecl()) {
@@ -491,7 +493,7 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation(
SourceLocation AtCatImplLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
IdentifierInfo *CatName, SourceLocation CatLoc) {
- ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc);
+ ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true);
ObjCCategoryDecl *CatIDecl = 0;
if (IDecl) {
CatIDecl = IDecl->FindCategoryDeclaration(CatName);
@@ -539,7 +541,8 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
ObjCInterfaceDecl* IDecl = 0;
// Check for another declaration kind with the same name.
NamedDecl *PrevDecl
- = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
+ = LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName,
+ ForRedeclaration);
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
@@ -553,7 +556,7 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
// 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) &&
+ if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
(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
@@ -576,7 +579,8 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
ObjCInterfaceDecl* SDecl = 0;
if (SuperClassname) {
// Check if a different kind of symbol declared in this scope.
- PrevDecl = LookupSingleName(TUScope, SuperClassname, LookupOrdinaryName);
+ PrevDecl = LookupSingleName(TUScope, SuperClassname, SuperClassLoc,
+ LookupOrdinaryName);
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
Diag(SuperClassLoc, diag::err_redefinition_different_kind)
<< SuperClassname;
@@ -1003,7 +1007,8 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
for (unsigned i = 0; i != NumElts; ++i) {
// Check for another declaration kind with the same name.
NamedDecl *PrevDecl
- = LookupSingleName(TUScope, IdentList[i], LookupOrdinaryName);
+ = LookupSingleName(TUScope, IdentList[i], IdentLocs[i],
+ LookupOrdinaryName, ForRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(AtClassLoc, PrevDecl);
@@ -1436,6 +1441,7 @@ void Sema::ActOnAtEnd(SourceRange AtEnd,
IDecl = IDecl->getSuperClass();
}
}
+ SetIvarInitializers(IC);
} else if (ObjCCategoryImplDecl* CatImplClass =
dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
CatImplClass->setAtEndRange(AtEnd);
@@ -1487,6 +1493,16 @@ CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) {
return ret;
}
+static inline
+bool containsInvalidMethodImplAttribute(const AttributeList *A) {
+ // The 'ibaction' attribute is allowed on method definitions because of
+ // how the IBAction macro is used on both method declarations and definitions.
+ // If the method definitions contains any other attributes, return true.
+ while (A && A->getKind() == AttributeList::AT_IBAction)
+ A = A->getNext();
+ return A != NULL;
+}
+
Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
SourceLocation MethodLoc, SourceLocation EndLoc,
tok::TokenKind MethodType, DeclPtrTy classDecl,
@@ -1495,7 +1511,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
// optional arguments. The number of types/arguments is obtained
// from the Sel.getNumArgs().
ObjCArgInfo *ArgInfo,
- llvm::SmallVectorImpl<Declarator> &Cdecls,
+ DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args
AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind,
bool isVariadic) {
Decl *ClassDecl = classDecl.getAs<Decl>();
@@ -1550,7 +1566,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
ParmVarDecl* Param
= ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc,
ArgInfo[i].Name, ArgType, DI,
- VarDecl::None, 0);
+ VarDecl::None, VarDecl::None, 0);
if (ArgType->isObjCInterfaceType()) {
Diag(ArgInfo[i].NameLoc,
@@ -1568,7 +1584,27 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
Params.push_back(Param);
}
- ObjCMethod->setMethodParams(Context, Params.data(), Sel.getNumArgs());
+ for (unsigned i = 0, e = CNumArgs; i != e; ++i) {
+ ParmVarDecl *Param = CParamInfo[i].Param.getAs<ParmVarDecl>();
+ QualType ArgType = Param->getType();
+ if (ArgType.isNull())
+ ArgType = Context.getObjCIdType();
+ else
+ // Perform the default array/function conversions (C99 6.7.5.3p[7,8]).
+ ArgType = adjustParameterType(ArgType);
+ if (ArgType->isObjCInterfaceType()) {
+ Diag(Param->getLocation(),
+ diag::err_object_cannot_be_passed_returned_by_value)
+ << 1 << ArgType;
+ Param->setInvalidDecl();
+ }
+ Param->setDeclContext(ObjCMethod);
+ IdResolver.RemoveDecl(Param);
+ Params.push_back(Param);
+ }
+
+ ObjCMethod->setMethodParams(Context, Params.data(), Params.size(),
+ Sel.getNumArgs());
ObjCMethod->setObjCDeclQualifier(
CvtQTToAstBitMask(ReturnQT.getObjCDeclQualifier()));
const ObjCMethodDecl *PrevMethod = 0;
@@ -1593,7 +1629,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
}
InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel,
MethodType == tok::minus);
- if (AttrList)
+ if (containsInvalidMethodImplAttribute(AttrList))
Diag(EndLoc, diag::warn_attribute_method_def);
} else if (ObjCCategoryImplDecl *CatImpDecl =
dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
@@ -1604,7 +1640,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
PrevMethod = CatImpDecl->getClassMethod(Sel);
CatImpDecl->addClassMethod(ObjCMethod);
}
- if (AttrList)
+ if (containsInvalidMethodImplAttribute(AttrList))
Diag(EndLoc, diag::warn_attribute_method_def);
}
if (PrevMethod) {
@@ -1638,7 +1674,7 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
IdentifierInfo *ClassName,
llvm::SmallVectorImpl<DeclPtrTy> &Decls) {
// Check that ClassName is a valid class
- ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName);
+ ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName, DeclStart);
if (!Class) {
Diag(DeclStart, diag::err_undef_interface) << ClassName;
return;
@@ -1672,3 +1708,146 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
}
}
+/// \brief Build a type-check a new Objective-C exception variable declaration.
+VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo,
+ QualType T,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ bool Invalid) {
+ // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage
+ // duration shall not be qualified by an address-space qualifier."
+ // Since all parameters have automatic store duration, they can not have
+ // an address space.
+ if (T.getAddressSpace() != 0) {
+ Diag(NameLoc, diag::err_arg_with_address_space);
+ Invalid = true;
+ }
+
+ // An @catch parameter must be an unqualified object pointer type;
+ // FIXME: Recover from "NSObject foo" by inserting the * in "NSObject *foo"?
+ if (Invalid) {
+ // Don't do any further checking.
+ } else if (T->isDependentType()) {
+ // Okay: we don't know what this type will instantiate to.
+ } else if (!T->isObjCObjectPointerType()) {
+ Invalid = true;
+ Diag(NameLoc ,diag::err_catch_param_not_objc_type);
+ } else if (T->isObjCQualifiedIdType()) {
+ Invalid = true;
+ Diag(NameLoc, diag::err_illegal_qualifiers_on_catch_parm);
+ }
+
+ VarDecl *New = VarDecl::Create(Context, CurContext, NameLoc, Name, T, TInfo,
+ VarDecl::None, VarDecl::None);
+ New->setExceptionVariable(true);
+
+ if (Invalid)
+ New->setInvalidDecl();
+ return New;
+}
+
+Sema::DeclPtrTy Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
+ const DeclSpec &DS = D.getDeclSpec();
+
+ // We allow the "register" storage class on exception variables because
+ // GCC did, but we drop it completely. Any other storage class is an error.
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
+ Diag(DS.getStorageClassSpecLoc(), diag::warn_register_objc_catch_parm)
+ << FixItHint::CreateRemoval(SourceRange(DS.getStorageClassSpecLoc()));
+ } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) {
+ Diag(DS.getStorageClassSpecLoc(), diag::err_storage_spec_on_catch_parm)
+ << DS.getStorageClassSpec();
+ }
+ if (D.getDeclSpec().isThreadSpecified())
+ Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+ D.getMutableDeclSpec().ClearStorageClassSpecs();
+
+ DiagnoseFunctionSpecifiers(D);
+
+ // Check that there are no default arguments inside the type of this
+ // exception object (C++ only).
+ if (getLangOptions().CPlusPlus)
+ CheckExtraCXXDefaultArguments(D);
+
+ TypeSourceInfo *TInfo = 0;
+ TagDecl *OwnedDecl = 0;
+ QualType ExceptionType = GetTypeForDeclarator(D, S, &TInfo, &OwnedDecl);
+
+ if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) {
+ // Objective-C++: Types shall not be defined in exception types.
+ Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type)
+ << Context.getTypeDeclType(OwnedDecl);
+ }
+
+ VarDecl *New = BuildObjCExceptionDecl(TInfo, ExceptionType, D.getIdentifier(),
+ D.getIdentifierLoc(),
+ D.isInvalidType());
+
+ // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
+ if (D.getCXXScopeSpec().isSet()) {
+ Diag(D.getIdentifierLoc(), diag::err_qualified_objc_catch_parm)
+ << D.getCXXScopeSpec().getRange();
+ New->setInvalidDecl();
+ }
+
+ // Add the parameter declaration into this scope.
+ S->AddDecl(DeclPtrTy::make(New));
+ if (D.getIdentifier())
+ IdResolver.AddDecl(New);
+
+ ProcessDeclAttributes(S, New, D);
+
+ if (New->hasAttr<BlocksAttr>())
+ Diag(New->getLocation(), diag::err_block_on_nonlocal);
+ return DeclPtrTy::make(New);
+}
+
+/// CollectIvarsToConstructOrDestruct - Collect those ivars which require
+/// initialization.
+void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI,
+ llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
+ for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(),
+ E = OI->ivar_end(); I != E; ++I) {
+ ObjCIvarDecl *Iv = (*I);
+ QualType QT = Context.getBaseElementType(Iv->getType());
+ if (isa<RecordType>(QT))
+ Ivars.push_back(*I);
+ }
+
+ // Find ivars to construct/destruct in class extension.
+ if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) {
+ for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(),
+ E = CDecl->ivar_end(); I != E; ++I) {
+ ObjCIvarDecl *Iv = (*I);
+ QualType QT = Context.getBaseElementType(Iv->getType());
+ if (isa<RecordType>(QT))
+ Ivars.push_back(*I);
+ }
+ }
+
+ // Also add any ivar defined in this class's implementation. This
+ // includes synthesized ivars.
+ if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) {
+ for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
+ E = ImplDecl->ivar_end(); I != E; ++I) {
+ ObjCIvarDecl *Iv = (*I);
+ QualType QT = Context.getBaseElementType(Iv->getType());
+ if (isa<RecordType>(QT))
+ Ivars.push_back(*I);
+ }
+ }
+}
+
+void ObjCImplementationDecl::setIvarInitializers(ASTContext &C,
+ CXXBaseOrMemberInitializer ** initializers,
+ unsigned numInitializers) {
+ if (numInitializers > 0) {
+ NumIvarInitializers = numInitializers;
+ CXXBaseOrMemberInitializer **ivarInitializers =
+ new (C) CXXBaseOrMemberInitializer*[NumIvarInitializers];
+ memcpy(ivarInitializers, initializers,
+ numInitializers * sizeof(CXXBaseOrMemberInitializer*));
+ IvarInitializers = ivarInitializers;
+ }
+}
+
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 2dfb954..c4ab03f 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -16,10 +16,13 @@
#include "Lookup.h"
#include "AnalysisBasedWarnings.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -80,6 +83,9 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
const SentinelAttr *attr = D->getAttr<SentinelAttr>();
if (!attr)
return;
+
+ // FIXME: In C++0x, if any of the arguments are parameter pack
+ // expansions, we can't check for the sentinel now.
int sentinelPos = attr->getSentinel();
int nullPos = attr->getNullPos();
@@ -155,6 +161,8 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
}
Expr *sentinelExpr = Args[sentinel];
if (sentinelExpr && (!isa<GNUNullExpr>(sentinelExpr) &&
+ !sentinelExpr->isTypeDependent() &&
+ !sentinelExpr->isValueDependent() &&
(!sentinelExpr->getType()->isPointerType() ||
!sentinelExpr->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)))) {
@@ -454,7 +462,10 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc,
}
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
+ if (isa<NonTypeTemplateParmDecl>(VD)) {
+ // Non-type template parameters can be referenced anywhere they are
+ // visible.
+ } else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
if (const FunctionDecl *FD = MD->getParent()->isLocalClass()) {
if (VD->hasLocalStorage() && VD->getDeclContext() != CurContext) {
Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function)
@@ -769,24 +780,6 @@ static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
return true;
}
-/// Determines if this is an instance member of a class.
-static bool IsInstanceMember(NamedDecl *D) {
- assert(D->isCXXClassMember() &&
- "checking whether non-member is instance member");
-
- if (isa<FieldDecl>(D)) return true;
-
- if (isa<CXXMethodDecl>(D))
- return !cast<CXXMethodDecl>(D)->isStatic();
-
- if (isa<FunctionTemplateDecl>(D)) {
- D = cast<FunctionTemplateDecl>(D)->getTemplatedDecl();
- return !cast<CXXMethodDecl>(D)->isStatic();
- }
-
- return false;
-}
-
enum IMAKind {
/// The reference is definitely not an instance member access.
IMA_Static,
@@ -846,8 +839,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
bool hasNonInstance = false;
llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- NamedDecl *D = (*I)->getUnderlyingDecl();
- if (IsInstanceMember(D)) {
+ NamedDecl *D = *I;
+ if (D->isCXXInstanceMember()) {
CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
// If this is a member of an anonymous record, move out to the
@@ -913,7 +906,7 @@ static void DiagnoseInstanceReference(Sema &SemaRef,
/// Diagnose an empty lookup.
///
/// \return false if new lookup candidates were found
-bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
+bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS,
LookupResult &R) {
DeclarationName Name = R.getLookupName();
@@ -964,43 +957,55 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
}
// We didn't find anything, so try to correct for a typo.
- if (S && CorrectTypo(R, S, &SS)) {
- if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) {
- if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
- else
- Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << R.getLookupName()
- << SS.getRange()
- << FixItHint::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;
- }
+ DeclarationName Corrected;
+ if (S && (Corrected = CorrectTypo(R, S, &SS))) {
+ if (!R.empty()) {
+ if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) {
+ if (SS.isEmpty())
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName()
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
+ else
+ Diag(R.getNameLoc(), diag::err_no_member_suggest)
+ << Name << computeDeclContext(SS, false) << R.getLookupName()
+ << SS.getRange()
+ << FixItHint::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;
+ }
+
+ if (isa<TypeDecl>(*R.begin()) || isa<ObjCInterfaceDecl>(*R.begin())) {
+ // FIXME: If we ended up with a typo for a type name or
+ // Objective-C class name, we're in trouble because the parser
+ // is in the wrong place to recover. Suggest the typo
+ // correction, but don't make it a fix-it since we're not going
+ // to recover well anyway.
+ if (SS.isEmpty())
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName();
+ else
+ Diag(R.getNameLoc(), diag::err_no_member_suggest)
+ << Name << computeDeclContext(SS, false) << R.getLookupName()
+ << SS.getRange();
- if (isa<TypeDecl>(*R.begin()) || isa<ObjCInterfaceDecl>(*R.begin())) {
- // FIXME: If we ended up with a typo for a type name or
- // Objective-C class name, we're in trouble because the parser
- // is in the wrong place to recover. Suggest the typo
- // correction, but don't make it a fix-it since we're not going
- // to recover well anyway.
+ // Don't try to recover; it won't work.
+ return true;
+ }
+ } else {
+ // FIXME: We found a keyword. Suggest it, but don't provide a fix-it
+ // because we aren't able to recover.
if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName();
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << Corrected;
else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << R.getLookupName()
- << SS.getRange();
-
- // Don't try to recover; it won't work.
+ << Name << computeDeclContext(SS, false) << Corrected
+ << SS.getRange();
return true;
}
-
R.clear();
}
@@ -1019,7 +1024,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
}
Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Id,
bool HasTrailingLParen,
bool isAddressOfOperand) {
@@ -1064,6 +1069,15 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
if (TemplateArgs) {
// Just re-use the lookup done by isTemplateName.
DecomposeTemplateName(R, Id);
+
+ // Re-derive the naming class.
+ if (SS.isSet()) {
+ NestedNameSpecifier *Qualifier
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ if (const Type *Ty = Qualifier->getAsType())
+ if (CXXRecordDecl *NamingClass = Ty->getAsCXXRecordDecl())
+ R.setNamingClass(NamingClass);
+ }
} else {
bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl());
LookupParsedName(R, S, &SS, !IvarLookupFollowUp);
@@ -1123,16 +1137,15 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
// Warn about constructs like:
// if (void *X = foo()) { ... } else { X }.
// In the else block, the pointer is always false.
-
if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) {
Scope *CheckS = S;
while (CheckS && CheckS->getControlParent()) {
- if (CheckS->isWithinElse() &&
+ if ((CheckS->getFlags() & Scope::ElseScope) &&
CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) {
ExprError(Diag(NameLoc, diag::warn_value_always_zero)
<< Var->getDeclName()
- << (Var->getType()->isPointerType()? 2 :
- Var->getType()->isBooleanType()? 1 : 0));
+ << (Var->getType()->isPointerType() ? 2 :
+ Var->getType()->isBooleanType() ? 1 : 0));
break;
}
@@ -1218,15 +1231,16 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
/// There's a large number of things which don't need to be done along
/// this path.
Sema::OwningExprResult
-Sema::BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS,
+Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
DeclarationName Name,
SourceLocation NameLoc) {
DeclContext *DC;
- if (!(DC = computeDeclContext(SS, false)) ||
- DC->isDependentContext() ||
- RequireCompleteDeclContext(SS))
+ if (!(DC = computeDeclContext(SS, false)) || DC->isDependentContext())
return BuildDependentDeclRefExpr(SS, Name, NameLoc, 0);
+ if (RequireCompleteDeclContext(SS, DC))
+ return ExprError();
+
LookupResult R(*this, Name, NameLoc, LookupOrdinaryName);
LookupQualifiedName(R, DC);
@@ -1251,9 +1265,9 @@ Sema::BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS,
/// Returns a null sentinel to indicate trivial success.
Sema::OwningExprResult
Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
- IdentifierInfo *II,
- bool AllowBuiltinCreation) {
+ IdentifierInfo *II, bool AllowBuiltinCreation) {
SourceLocation Loc = Lookup.getNameLoc();
+ ObjCMethodDecl *CurMethod = getCurMethodDecl();
// There are two cases to handle here. 1) scoped lookup could have failed,
// in which case we should look for an ivar. 2) scoped lookup could have
@@ -1264,7 +1278,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
// If we're in a class method, we don't normally want to look for
// ivars. But if we don't find anything else, and there's an
// ivar, that's an error.
- bool IsClassMethod = getCurMethodDecl()->isClassMethod();
+ bool IsClassMethod = CurMethod->isClassMethod();
bool LookForIvars;
if (Lookup.empty())
@@ -1276,7 +1290,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod());
ObjCInterfaceDecl *IFace = 0;
if (LookForIvars) {
- IFace = getCurMethodDecl()->getClassInterface();
+ IFace = CurMethod->getClassInterface();
ObjCInterfaceDecl *ClassDeclared;
if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
// Diagnose using an ivar in a class method.
@@ -1311,9 +1325,9 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
ObjCIvarRefExpr(IV, IV->getType(), Loc,
SelfExpr.takeAs<Expr>(), true, true));
}
- } else if (getCurMethodDecl()->isInstanceMethod()) {
+ } else if (CurMethod->isInstanceMethod()) {
// We should warn if a local variable hides an ivar.
- ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
+ ObjCInterfaceDecl *IFace = CurMethod->getClassInterface();
ObjCInterfaceDecl *ClassDeclared;
if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
if (IV->getAccessControl() != ObjCIvarDecl::Private ||
@@ -1322,17 +1336,6 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
}
}
- // Needed to implement property "super.method" notation.
- if (Lookup.empty() && II->isStr("super")) {
- QualType T;
-
- if (getCurMethodDecl()->isInstanceMethod())
- T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType(
- getCurMethodDecl()->getClassInterface()));
- else
- 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()) {
@@ -1449,14 +1452,15 @@ Sema::PerformObjectMemberConversion(Expr *&From,
// type of the object type, in which case we just ignore it.
// Otherwise build the appropriate casts.
if (IsDerivedFrom(FromRecordType, QRecordType)) {
+ CXXBaseSpecifierArray BasePath;
if (CheckDerivedToBaseConversion(FromRecordType, QRecordType,
- FromLoc, FromRange))
+ FromLoc, FromRange, &BasePath))
return true;
if (PointerConversions)
QType = Context.getPointerType(QType);
ImpCastExprToType(From, QType, CastExpr::CK_UncheckedDerivedToBase,
- /*isLvalue*/ !PointerConversions);
+ /*isLvalue=*/!PointerConversions, BasePath);
FromType = QType;
FromRecordType = QRecordType;
@@ -1484,15 +1488,16 @@ Sema::PerformObjectMemberConversion(Expr *&From,
// conversion is non-trivial.
if (!Context.hasSameUnqualifiedType(FromRecordType, URecordType)) {
assert(IsDerivedFrom(FromRecordType, URecordType));
+ CXXBaseSpecifierArray BasePath;
if (CheckDerivedToBaseConversion(FromRecordType, URecordType,
- FromLoc, FromRange))
+ FromLoc, FromRange, &BasePath))
return true;
-
+
QualType UType = URecordType;
if (PointerConversions)
UType = Context.getPointerType(UType);
ImpCastExprToType(From, UType, CastExpr::CK_UncheckedDerivedToBase,
- /*isLvalue*/ !PointerConversions);
+ /*isLvalue=*/!PointerConversions, BasePath);
FromType = UType;
FromRecordType = URecordType;
}
@@ -1502,23 +1507,22 @@ Sema::PerformObjectMemberConversion(Expr *&From,
IgnoreAccess = true;
}
- if (CheckDerivedToBaseConversion(FromRecordType,
- DestRecordType,
- FromLoc,
- FromRange,
+ CXXBaseSpecifierArray BasePath;
+ if (CheckDerivedToBaseConversion(FromRecordType, DestRecordType,
+ FromLoc, FromRange, &BasePath,
IgnoreAccess))
return true;
ImpCastExprToType(From, DestType, CastExpr::CK_UncheckedDerivedToBase,
- /*isLvalue=*/ !PointerConversions);
+ /*isLvalue=*/!PointerConversions, BasePath);
return false;
}
/// \brief Build a MemberExpr AST node.
static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
const CXXScopeSpec &SS, ValueDecl *Member,
- NamedDecl *FoundDecl, SourceLocation Loc,
- QualType Ty,
+ DeclAccessPair FoundDecl,
+ SourceLocation Loc, QualType Ty,
const TemplateArgumentListInfo *TemplateArgs = 0) {
NestedNameSpecifier *Qualifier = 0;
SourceRange QualifierRange;
@@ -2484,7 +2488,8 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType,
}
}
- assert(BaseType->isDependentType() || Name.isDependentName());
+ assert(BaseType->isDependentType() || Name.isDependentName() ||
+ isDependentScopeSpecifier(SS));
// 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.
@@ -2510,11 +2515,8 @@ static void DiagnoseQualifiedMemberReference(Sema &SemaRef,
if (!BaseExpr)
return DiagnoseInstanceReference(SemaRef, SS, R);
- // FIXME: this is an exceedingly lame diagnostic for some of the more
- // complicated cases here.
- DeclContext *DC = R.getRepresentativeDecl()->getDeclContext();
- SemaRef.Diag(R.getNameLoc(), diag::err_not_direct_base_or_virtual)
- << SS.getRange() << DC << BaseType;
+ SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_of_unrelated)
+ << SS.getRange() << R.getRepresentativeDecl() << BaseType;
}
// Check whether the declarations we found through a nested-name
@@ -2545,7 +2547,7 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
// If this is an implicit member reference and we find a
// non-instance member, it's not an error.
- if (!BaseExpr && !IsInstanceMember((*I)->getUnderlyingDecl()))
+ if (!BaseExpr && !(*I)->isCXXInstanceMember())
return false;
// Note that we use the DC of the decl, not the underlying decl.
@@ -2567,7 +2569,7 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
static bool
LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
SourceRange BaseRange, const RecordType *RTy,
- SourceLocation OpLoc, const CXXScopeSpec &SS) {
+ SourceLocation OpLoc, CXXScopeSpec &SS) {
RecordDecl *RDecl = RTy->getDecl();
if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
SemaRef.PDiag(diag::err_typecheck_incomplete_tag)
@@ -2580,7 +2582,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
// nested-name-specifier.
DC = SemaRef.computeDeclContext(SS, false);
- if (SemaRef.RequireCompleteDeclContext(SS)) {
+ if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
<< SS.getRange() << DC;
return true;
@@ -2604,7 +2606,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
// We didn't find anything with the given name, so try to correct
// for typos.
DeclarationName Name = R.getLookupName();
- if (SemaRef.CorrectTypo(R, 0, &SS, DC) &&
+ if (SemaRef.CorrectTypo(R, 0, &SS, DC, false, Sema::CTC_MemberLookup) &&
+ !R.empty() &&
(isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) {
SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
<< Name << DC << R.getLookupName() << SS.getRange()
@@ -2624,7 +2627,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
Sema::OwningExprResult
Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
DeclarationName Name, SourceLocation NameLoc,
const TemplateArgumentListInfo *TemplateArgs) {
@@ -2675,13 +2678,15 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
const CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs) {
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool SuppressQualifierCheck) {
Expr *BaseExpr = Base.takeAs<Expr>();
QualType BaseType = BaseExprType;
if (IsArrow) {
assert(BaseType->isPointerType());
BaseType = BaseType->getAs<PointerType>()->getPointeeType();
}
+ R.setBaseObjectType(BaseType);
NestedNameSpecifier *Qualifier =
static_cast<NestedNameSpecifier*>(SS.getScopeRep());
@@ -2713,6 +2718,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
if ((SS.isSet() || !BaseExpr ||
(isa<CXXThisExpr>(BaseExpr) &&
cast<CXXThisExpr>(BaseExpr)->isImplicit())) &&
+ !SuppressQualifierCheck &&
CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
return ExprError();
@@ -2742,7 +2748,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
}
assert(R.isSingleResult());
- NamedDecl *FoundDecl = *R.begin();
+ DeclAccessPair FoundDecl = R.begin().getPair();
NamedDecl *MemberDecl = R.getFoundDecl();
// FIXME: diagnose the presence of template arguments now.
@@ -2756,7 +2762,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
// Handle the implicit-member-access case.
if (!BaseExpr) {
// If this is not an instance member, convert to a non-member access.
- if (!IsInstanceMember(MemberDecl))
+ if (!MemberDecl->isCXXInstanceMember())
return BuildDeclarationNameExpr(SS, R.getNameLoc(), MemberDecl);
SourceLocation Loc = R.getNameLoc();
@@ -2833,16 +2839,18 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
Owned(BaseExpr);
+ // We found something that we didn't expect. Complain.
if (isa<TypeDecl>(MemberDecl))
- return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type)
- << MemberName << int(IsArrow));
+ Diag(MemberLoc,diag::err_typecheck_member_reference_type)
+ << MemberName << BaseType << int(IsArrow);
+ else
+ Diag(MemberLoc, diag::err_typecheck_member_reference_unknown)
+ << MemberName << BaseType << int(IsArrow);
- // We found a declaration kind that we didn't expect. This is a
- // generic error message that tells the user that she can't refer
- // to this member with '.' or '->'.
- return ExprError(Diag(MemberLoc,
- diag::err_typecheck_member_reference_unknown)
- << MemberName << int(IsArrow));
+ Diag(MemberDecl->getLocation(), diag::note_member_declared_here)
+ << MemberName;
+ R.suppressDiagnostics();
+ return ExprError();
}
/// Look up the given member of the given non-type-dependent
@@ -2858,7 +2866,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
Sema::OwningExprResult
Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
bool &IsArrow, SourceLocation OpLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
DeclPtrTy ObjCImpDecl) {
assert(BaseExpr && "no base expression");
@@ -3060,7 +3068,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// Attempt to correct for typos in ivar names.
LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
LookupMemberName);
- if (CorrectTypo(Res, 0, 0, IDecl) &&
+ if (CorrectTypo(Res, 0, 0, IDecl, false, CTC_MemberLookup) &&
(IV = Res.getAsSingle<ObjCIvarDecl>())) {
Diag(R.getNameLoc(),
diag::err_typecheck_member_reference_ivar_suggest)
@@ -3145,117 +3153,23 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
if (DiagnoseUseOfDecl(OMD, MemberLoc))
return ExprError();
- return Owned(new (Context) ObjCMessageExpr(Context, BaseExpr, Sel,
- OMD->getResultType(),
- OMD, OpLoc, MemberLoc,
- NULL, 0));
+ return Owned(ObjCMessageExpr::Create(Context,
+ OMD->getResultType().getNonReferenceType(),
+ OpLoc, BaseExpr, Sel,
+ OMD, NULL, 0, MemberLoc));
}
}
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
<< MemberName << BaseType);
}
+
// Handle Objective-C property access, which is "Obj.property" where Obj is a
// pointer to a (potentially qualified) interface type.
- const ObjCObjectPointerType *OPT;
- if (!IsArrow && (OPT = BaseType->getAsObjCInterfacePointerType())) {
- const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
- ObjCInterfaceDecl *IFace = IFaceT->getDecl();
- IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
-
- // Search for a declared property first.
- if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) {
- // Check whether we can reference this property.
- if (DiagnoseUseOfDecl(PD, MemberLoc))
- return ExprError();
- QualType ResTy = PD->getType();
- Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
- ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
- if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))
- ResTy = Getter->getResultType();
- return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
- MemberLoc, BaseExpr));
- }
- // Check protocols on qualified interfaces.
- for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
- E = OPT->qual_end(); I != E; ++I)
- if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
- // Check whether we can reference this property.
- if (DiagnoseUseOfDecl(PD, MemberLoc))
- return ExprError();
-
- return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
- MemberLoc, BaseExpr));
- }
- // If that failed, look for an "implicit" property by seeing if the nullary
- // selector is implemented.
-
- // FIXME: The logic for looking up nullary and unary selectors should be
- // shared with the code in ActOnInstanceMessage.
-
- Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
- ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
-
- // If this reference is in an @implementation, check for 'private' methods.
- if (!Getter)
- Getter = IFace->lookupPrivateInstanceMethod(Sel);
-
- // Look through local category implementations associated with the class.
- if (!Getter)
- Getter = IFace->getCategoryInstanceMethod(Sel);
- if (Getter) {
- // Check if we can reference this property.
- if (DiagnoseUseOfDecl(Getter, MemberLoc))
- return ExprError();
- }
- // If we found a getter then this may be a valid dot-reference, we
- // will look for the matching setter, in case it is needed.
- Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(), Member);
- ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
- if (!Setter) {
- // If this reference is in an @implementation, also check for 'private'
- // methods.
- Setter = IFace->lookupPrivateInstanceMethod(SetterSel);
- }
- // Look through local category implementations associated with the class.
- if (!Setter)
- Setter = IFace->getCategoryInstanceMethod(SetterSel);
-
- if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
- return ExprError();
-
- if (Getter) {
- QualType PType;
- PType = Getter->getResultType();
- 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()
- << FixItHint::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);
- }
- Diag(MemberLoc, diag::err_property_not_found)
- << MemberName << BaseType;
- if (Setter && !Getter)
- Diag(Setter->getLocation(), diag::note_getter_unavailable)
- << MemberName << BaseExpr->getSourceRange();
- return ExprError();
- }
+ if (!IsArrow)
+ if (const ObjCObjectPointerType *OPT =
+ BaseType->getAsObjCInterfacePointerType())
+ return HandleExprPropertyRefExpr(OPT, BaseExpr, MemberName, MemberLoc);
// Handle the following exceptional case (*Obj).isa.
if (!IsArrow &&
@@ -3296,7 +3210,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
SourceLocation OpLoc,
tok::TokenKind OpKind,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Id,
DeclPtrTy ObjCImpDecl,
bool HasTrailingLParen) {
@@ -3323,7 +3237,8 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
Expr *Base = BaseArg.takeAs<Expr>();
OwningExprResult Result(*this);
- if (Base->getType()->isDependentType() || Name.isDependentName()) {
+ if (Base->getType()->isDependentType() || Name.isDependentName() ||
+ isDependentScopeSpecifier(SS)) {
Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(),
IsArrow, OpLoc,
SS, FirstQualifierInScope,
@@ -3334,6 +3249,21 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
if (TemplateArgs) {
// Re-use the lookup done for the template name.
DecomposeTemplateName(R, Id);
+
+ // Re-derive the naming class.
+ if (SS.isSet()) {
+ NestedNameSpecifier *Qualifier
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ if (const Type *Ty = Qualifier->getAsType())
+ if (CXXRecordDecl *NamingClass = Ty->getAsCXXRecordDecl())
+ R.setNamingClass(NamingClass);
+ } else {
+ QualType BaseType = Base->getType();
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>())
+ BaseType = Ptr->getPointeeType();
+ if (CXXRecordDecl *NamingClass = BaseType->getAsCXXRecordDecl())
+ R.setNamingClass(NamingClass);
+ }
} else {
Result = LookupMemberExpr(R, Base, IsArrow, OpLoc,
SS, ObjCImpDecl);
@@ -3443,7 +3373,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
if (NumArgs < NumArgsInProto) {
if (!FDecl || NumArgs < FDecl->getMinRequiredArguments())
return Diag(RParenLoc, diag::err_typecheck_call_too_few_args)
- << Fn->getType()->isBlockPointerType() << Fn->getSourceRange();
+ << Fn->getType()->isBlockPointerType()
+ << NumArgsInProto << NumArgs << Fn->getSourceRange();
Call->setNumArgs(Context, NumArgsInProto);
}
@@ -3453,7 +3384,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
if (!Proto->isVariadic()) {
Diag(Args[NumArgsInProto]->getLocStart(),
diag::err_typecheck_call_too_many_args)
- << Fn->getType()->isBlockPointerType() << Fn->getSourceRange()
+ << Fn->getType()->isBlockPointerType()
+ << NumArgsInProto << NumArgs << Fn->getSourceRange()
<< SourceRange(Args[NumArgsInProto]->getLocStart(),
Args[NumArgs-1]->getLocEnd());
// This deletes the extra arguments.
@@ -3613,7 +3545,8 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
// declarations (all methods or method templates) or a single
// method template.
assert((MemE->getNumDecls() > 1) ||
- isa<FunctionTemplateDecl>(*MemE->decls_begin()));
+ isa<FunctionTemplateDecl>(
+ (*MemE->decls_begin())->getUnderlyingDecl()));
(void)MemE;
return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
@@ -3666,7 +3599,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
Expr *NakedFn = Fn->IgnoreParens();
if (isa<UnresolvedLookupExpr>(NakedFn)) {
UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(NakedFn);
- return BuildOverloadedCallExpr(Fn, ULE, LParenLoc, Args, NumArgs,
+ return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc);
}
@@ -3851,8 +3784,8 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist,
// Semantic analysis for initializers is done by ActOnDeclarator() and
// CheckInitializer() - it requires knowledge of the object being intialized.
- InitListExpr *E = new (Context) InitListExpr(LBraceLoc, InitList, NumInit,
- RBraceLoc);
+ InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitList,
+ NumInit, RBraceLoc);
E->setType(Context.VoidTy); // FIXME: just a place holder for now.
return Owned(E);
}
@@ -3895,11 +3828,11 @@ static CastExpr::CastKind getScalarCastKind(ASTContext &Context,
/// CheckCastTypes - Check type constraints for casting between types.
bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
CastExpr::CastKind& Kind,
- CXXMethodDecl *& ConversionDecl,
+ CXXBaseSpecifierArray &BasePath,
bool FunctionalStyle) {
if (getLangOptions().CPlusPlus)
- return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle,
- ConversionDecl);
+ return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, BasePath,
+ FunctionalStyle);
DefaultFunctionArrayLvalueConversion(castExpr);
@@ -3962,9 +3895,6 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
if (castExpr->getType()->isVectorType())
return CheckVectorCast(TyR, castExpr->getType(), castType, Kind);
- if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr))
- return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR;
-
if (isa<ObjCSelectorExpr>(castExpr))
return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr);
@@ -4062,27 +3992,15 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
SourceLocation RParenLoc, ExprArg Op) {
Expr *castExpr = static_cast<Expr*>(Op.get());
- CXXMethodDecl *Method = 0;
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ CXXBaseSpecifierArray BasePath;
if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr,
- Kind, Method))
+ Kind, BasePath))
return ExprError();
- if (Method) {
- // FIXME: preserve type source info here
- OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, Ty->getType(),
- Kind, Method, move(Op));
-
- if (CastArg.isInvalid())
- return ExprError();
-
- castExpr = CastArg.takeAs<Expr>();
- } else {
- Op.release();
- }
-
+ Op.release();
return Owned(new (Context) CStyleCastExpr(Ty->getType().getNonReferenceType(),
- Kind, castExpr, Ty,
+ Kind, castExpr, BasePath, Ty,
LParenLoc, RParenLoc));
}
@@ -4126,7 +4044,8 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
// FIXME: This means that pretty-printing the final AST will produce curly
// braces instead of the original commas.
Op.release();
- InitListExpr *E = new (Context) InitListExpr(LParenLoc, &initExprs[0],
+ InitListExpr *E = new (Context) InitListExpr(Context, LParenLoc,
+ &initExprs[0],
initExprs.size(), RParenLoc);
E->setType(Ty);
return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, Owned(E));
@@ -4856,7 +4775,7 @@ static void ConstructTransparentUnion(ASTContext &C, Expr *&E,
QualType UnionType, FieldDecl *Field) {
// Build an initializer list that designates the appropriate member
// of the transparent union.
- InitListExpr *Initializer = new (C) InitListExpr(SourceLocation(),
+ InitListExpr *Initializer = new (C) InitListExpr(C, SourceLocation(),
&E, 1,
SourceLocation());
Initializer->setType(UnionType);
@@ -5419,11 +5338,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
DiagRuntimeBehavior(Loc,
PDiag(diag::warn_stringcompare)
<< isa<ObjCEncodeExpr>(literalStringStripped)
- << literalString->getSourceRange()
- << FixItHint::CreateReplacement(SourceRange(Loc), ", ")
- << FixItHint::CreateInsertion(lex->getLocStart(), "strcmp(")
- << FixItHint::CreateInsertion(PP.getLocForEndOfToken(rex->getLocEnd()),
- resultComparison));
+ << literalString->getSourceRange());
}
}
@@ -5480,7 +5395,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// C++ [expr.eq]p1 uses the same notion for (in)equality
// comparisons of pointers.
bool NonStandardCompositeType = false;
- QualType T = FindCompositePointerType(lex, rex,
+ QualType T = FindCompositePointerType(Loc, lex, rex,
isSFINAEContext()? 0 : &NonStandardCompositeType);
if (T.isNull()) {
Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
@@ -5553,7 +5468,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// that is the union of the cv-qualification signatures of the operand
// types.
bool NonStandardCompositeType = false;
- QualType T = FindCompositePointerType(lex, rex,
+ QualType T = FindCompositePointerType(Loc, lex, rex,
isSFINAEContext()? 0 : &NonStandardCompositeType);
if (T.isNull()) {
Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
@@ -5944,7 +5859,7 @@ QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) {
/// CheckIncrementDecrementOperand - unlike most "Check" methods, this routine
/// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions.
QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
- bool isInc) {
+ bool isInc, bool isPrefix) {
if (Op->isTypeDependent())
return Context.DependentTy;
@@ -6007,7 +5922,11 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
// Now make sure the operand is a modifiable lvalue.
if (CheckForModifiableLvalue(Op, OpLoc, *this))
return QualType();
- return ResType;
+ // In C++, a prefix increment is the same type as the operand. Otherwise
+ // (in C or with postfix), the increment is the unqualified type of the
+ // operand.
+ return isPrefix && getLangOptions().CPlusPlus
+ ? ResType : ResType.getUnqualifiedType();
}
/// getPrimaryDecl - Helper function for CheckAddressOfOperand().
@@ -6395,33 +6314,37 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
/// ParenRange in parentheses.
static void SuggestParentheses(Sema &Self, SourceLocation Loc,
const PartialDiagnostic &PD,
- SourceRange ParenRange,
- const PartialDiagnostic &SecondPD,
+ const PartialDiagnostic &FirstNote,
+ SourceRange FirstParenRange,
+ const PartialDiagnostic &SecondNote,
SourceRange SecondParenRange) {
- SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd());
- if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
- // We can't display the parentheses, so just dig the
- // warning/error and return.
- Self.Diag(Loc, PD);
+ Self.Diag(Loc, PD);
+
+ if (!FirstNote.getDiagID())
+ return;
+
+ SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd());
+ if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
+ // We can't display the parentheses, so just return.
return;
}
- Self.Diag(Loc, PD)
- << FixItHint::CreateInsertion(ParenRange.getBegin(), "(")
+ Self.Diag(Loc, FirstNote)
+ << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(")
<< FixItHint::CreateInsertion(EndLoc, ")");
- if (!SecondPD.getDiagID())
+ if (!SecondNote.getDiagID())
return;
EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd());
if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
// We can't display the parentheses, so just dig the
// warning/error and return.
- Self.Diag(Loc, SecondPD);
+ Self.Diag(Loc, SecondNote);
return;
}
- Self.Diag(Loc, SecondPD)
+ Self.Diag(Loc, SecondNote)
<< FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(")
<< FixItHint::CreateInsertion(EndLoc, ")");
}
@@ -6455,19 +6378,23 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc,
Self.PDiag(diag::warn_precedence_bitwise_rel)
<< SourceRange(lhs->getLocStart(), OpLoc)
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc),
- lhs->getSourceRange(),
Self.PDiag(diag::note_precedence_bitwise_first)
<< BinOp::getOpcodeStr(Opc),
- SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()));
+ SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()),
+ Self.PDiag(diag::note_precedence_bitwise_silence)
+ << BinOp::getOpcodeStr(lhsopc),
+ lhs->getSourceRange());
else if (BinOp::isComparisonOp(rhsopc))
SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::warn_precedence_bitwise_rel)
<< SourceRange(OpLoc, rhs->getLocEnd())
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc),
- rhs->getSourceRange(),
Self.PDiag(diag::note_precedence_bitwise_first)
<< BinOp::getOpcodeStr(Opc),
- SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()));
+ SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()),
+ Self.PDiag(diag::note_precedence_bitwise_silence)
+ << BinOp::getOpcodeStr(rhsopc),
+ rhs->getSourceRange());
}
/// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky
@@ -6532,14 +6459,16 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
case UnaryOperator::OffsetOf:
assert(false && "Invalid unary operator");
break;
-
+
case UnaryOperator::PreInc:
case UnaryOperator::PreDec:
case UnaryOperator::PostInc:
case UnaryOperator::PostDec:
resultType = CheckIncrementDecrementOperand(Input, OpLoc,
Opc == UnaryOperator::PreInc ||
- Opc == UnaryOperator::PostInc);
+ Opc == UnaryOperator::PostInc,
+ Opc == UnaryOperator::PreInc ||
+ Opc == UnaryOperator::PreDec);
break;
case UnaryOperator::AddrOf:
resultType = CheckAddressOfOperand(Input, OpLoc);
@@ -6690,6 +6619,157 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, StmtArg substmt,
return Owned(new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc));
}
+Sema::OwningExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
+ TypeSourceInfo *TInfo,
+ OffsetOfComponent *CompPtr,
+ unsigned NumComponents,
+ SourceLocation RParenLoc) {
+ QualType ArgTy = TInfo->getType();
+ bool Dependent = ArgTy->isDependentType();
+ SourceRange TypeRange = TInfo->getTypeLoc().getSourceRange();
+
+ // We must have at least one component that refers to the type, and the first
+ // one is known to be a field designator. Verify that the ArgTy represents
+ // a struct/union/class.
+ if (!Dependent && !ArgTy->isRecordType())
+ return ExprError(Diag(BuiltinLoc, diag::err_offsetof_record_type)
+ << ArgTy << TypeRange);
+
+ // Type must be complete per C99 7.17p3 because a declaring a variable
+ // with an incomplete type would be ill-formed.
+ if (!Dependent
+ && RequireCompleteType(BuiltinLoc, ArgTy,
+ PDiag(diag::err_offsetof_incomplete_type)
+ << TypeRange))
+ return ExprError();
+
+ // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a
+ // GCC extension, diagnose them.
+ // FIXME: This diagnostic isn't actually visible because the location is in
+ // a system header!
+ if (NumComponents != 1)
+ Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator)
+ << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd);
+
+ bool DidWarnAboutNonPOD = false;
+ QualType CurrentType = ArgTy;
+ typedef OffsetOfExpr::OffsetOfNode OffsetOfNode;
+ llvm::SmallVector<OffsetOfNode, 4> Comps;
+ llvm::SmallVector<Expr*, 4> Exprs;
+ for (unsigned i = 0; i != NumComponents; ++i) {
+ const OffsetOfComponent &OC = CompPtr[i];
+ if (OC.isBrackets) {
+ // Offset of an array sub-field. TODO: Should we allow vector elements?
+ if (!CurrentType->isDependentType()) {
+ const ArrayType *AT = Context.getAsArrayType(CurrentType);
+ if(!AT)
+ return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type)
+ << CurrentType);
+ CurrentType = AT->getElementType();
+ } else
+ CurrentType = Context.DependentTy;
+
+ // The expression must be an integral expression.
+ // FIXME: An integral constant expression?
+ Expr *Idx = static_cast<Expr*>(OC.U.E);
+ if (!Idx->isTypeDependent() && !Idx->isValueDependent() &&
+ !Idx->getType()->isIntegerType())
+ return ExprError(Diag(Idx->getLocStart(),
+ diag::err_typecheck_subscript_not_integer)
+ << Idx->getSourceRange());
+
+ // Record this array index.
+ Comps.push_back(OffsetOfNode(OC.LocStart, Exprs.size(), OC.LocEnd));
+ Exprs.push_back(Idx);
+ continue;
+ }
+
+ // Offset of a field.
+ if (CurrentType->isDependentType()) {
+ // We have the offset of a field, but we can't look into the dependent
+ // type. Just record the identifier of the field.
+ Comps.push_back(OffsetOfNode(OC.LocStart, OC.U.IdentInfo, OC.LocEnd));
+ CurrentType = Context.DependentTy;
+ continue;
+ }
+
+ // We need to have a complete type to look into.
+ if (RequireCompleteType(OC.LocStart, CurrentType,
+ diag::err_offsetof_incomplete_type))
+ return ExprError();
+
+ // Look for the designated field.
+ const RecordType *RC = CurrentType->getAs<RecordType>();
+ if (!RC)
+ return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type)
+ << CurrentType);
+ RecordDecl *RD = RC->getDecl();
+
+ // C++ [lib.support.types]p5:
+ // The macro offsetof accepts a restricted set of type arguments in this
+ // International Standard. type shall be a POD structure or a POD union
+ // (clause 9).
+ if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
+ if (!CRD->isPOD() && !DidWarnAboutNonPOD &&
+ DiagRuntimeBehavior(BuiltinLoc,
+ PDiag(diag::warn_offsetof_non_pod_type)
+ << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
+ << CurrentType))
+ DidWarnAboutNonPOD = true;
+ }
+
+ // Look for the field.
+ LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName);
+ LookupQualifiedName(R, RD);
+ FieldDecl *MemberDecl = R.getAsSingle<FieldDecl>();
+ if (!MemberDecl)
+ return ExprError(Diag(BuiltinLoc, diag::err_no_member)
+ << OC.U.IdentInfo << RD << SourceRange(OC.LocStart,
+ OC.LocEnd));
+
+ // C99 7.17p3:
+ // (If the specified member is a bit-field, the behavior is undefined.)
+ //
+ // We diagnose this as an error.
+ if (MemberDecl->getBitWidth()) {
+ Diag(OC.LocEnd, diag::err_offsetof_bitfield)
+ << MemberDecl->getDeclName()
+ << SourceRange(BuiltinLoc, RParenLoc);
+ Diag(MemberDecl->getLocation(), diag::note_bitfield_decl);
+ return ExprError();
+ }
+
+ // If the member was found in a base class, introduce OffsetOfNodes for
+ // the base class indirections.
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (IsDerivedFrom(CurrentType,
+ Context.getTypeDeclType(MemberDecl->getParent()),
+ Paths)) {
+ CXXBasePath &Path = Paths.front();
+ for (CXXBasePath::iterator B = Path.begin(), BEnd = Path.end();
+ B != BEnd; ++B)
+ Comps.push_back(OffsetOfNode(B->Base));
+ }
+
+ if (cast<RecordDecl>(MemberDecl->getDeclContext())->
+ isAnonymousStructOrUnion()) {
+ llvm::SmallVector<FieldDecl*, 4> Path;
+ BuildAnonymousStructUnionMemberPath(MemberDecl, Path);
+ unsigned n = Path.size();
+ for (int j = n - 1; j > -1; --j)
+ Comps.push_back(OffsetOfNode(OC.LocStart, Path[j], OC.LocEnd));
+ } else {
+ Comps.push_back(OffsetOfNode(OC.LocStart, MemberDecl, OC.LocEnd));
+ }
+ CurrentType = MemberDecl->getType().getNonReferenceType();
+ }
+
+ return Owned(OffsetOfExpr::Create(Context, Context.getSizeType(), BuiltinLoc,
+ TInfo, Comps.data(), Comps.size(),
+ Exprs.data(), Exprs.size(), RParenLoc));
+}
+
Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
SourceLocation BuiltinLoc,
SourceLocation TypeLoc,
@@ -6697,45 +6777,56 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
OffsetOfComponent *CompPtr,
unsigned NumComponents,
SourceLocation RPLoc) {
- // FIXME: This function leaks all expressions in the offset components on
- // error.
- // FIXME: Preserve type source info.
- QualType ArgTy = GetTypeFromParser(argty);
- assert(!ArgTy.isNull() && "Missing type argument!");
- bool Dependent = ArgTy->isDependentType();
+ TypeSourceInfo *ArgTInfo;
+ QualType ArgTy = GetTypeFromParser(argty, &ArgTInfo);
+ if (ArgTy.isNull())
+ return ExprError();
+ if (getLangOptions().CPlusPlus) {
+ if (!ArgTInfo)
+ ArgTInfo = Context.getTrivialTypeSourceInfo(ArgTy, TypeLoc);
+
+ return BuildBuiltinOffsetOf(BuiltinLoc, ArgTInfo, CompPtr, NumComponents,
+ RPLoc);
+ }
+
+ // FIXME: The code below is marked for death, once we have proper CodeGen
+ // support for non-constant OffsetOf expressions.
+
+ bool Dependent = ArgTy->isDependentType();
+
// We must have at least one component that refers to the type, and the first
// one is known to be a field designator. Verify that the ArgTy represents
// a struct/union/class.
if (!Dependent && !ArgTy->isRecordType())
return ExprError(Diag(TypeLoc, diag::err_offsetof_record_type) << ArgTy);
-
+
// FIXME: Type must be complete per C99 7.17p3 because a declaring a variable
// with an incomplete type would be illegal.
-
+
// Otherwise, create a null pointer as the base, and iteratively process
// the offsetof designators.
QualType ArgTyPtr = Context.getPointerType(ArgTy);
Expr* Res = new (Context) ImplicitValueInitExpr(ArgTyPtr);
Res = new (Context) UnaryOperator(Res, UnaryOperator::Deref,
ArgTy, SourceLocation());
-
+
// offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a
// GCC extension, diagnose them.
// FIXME: This diagnostic isn't actually visible because the location is in
// a system header!
if (NumComponents != 1)
Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator)
- << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd);
-
+ << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd);
+
if (!Dependent) {
bool DidWarnAboutNonPOD = false;
-
+
if (RequireCompleteType(TypeLoc, Res->getType(),
diag::err_offsetof_incomplete_type))
return ExprError();
-
+
// FIXME: Dependent case loses a lot of information here. And probably
// leaks like a sieve.
for (unsigned i = 0; i != NumComponents; ++i) {
@@ -6746,71 +6837,83 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
if (!AT) {
Res->Destroy(Context);
return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type)
- << Res->getType());
+ << Res->getType());
}
-
+
// FIXME: C++: Verify that operator[] isn't overloaded.
-
+
// Promote the array so it looks more like a normal array subscript
// expression.
DefaultFunctionArrayLvalueConversion(Res);
-
+
// C99 6.5.2.1p1
Expr *Idx = static_cast<Expr*>(OC.U.E);
// FIXME: Leaks Res
if (!Idx->isTypeDependent() && !Idx->getType()->isIntegerType())
return ExprError(Diag(Idx->getLocStart(),
diag::err_typecheck_subscript_not_integer)
- << Idx->getSourceRange());
-
+ << Idx->getSourceRange());
+
Res = new (Context) ArraySubscriptExpr(Res, Idx, AT->getElementType(),
OC.LocEnd);
continue;
}
-
+
const RecordType *RC = Res->getType()->getAs<RecordType>();
if (!RC) {
Res->Destroy(Context);
return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type)
- << Res->getType());
+ << Res->getType());
}
-
+
// Get the decl corresponding to this.
RecordDecl *RD = RC->getDecl();
if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
if (!CRD->isPOD() && !DidWarnAboutNonPOD &&
DiagRuntimeBehavior(BuiltinLoc,
PDiag(diag::warn_offsetof_non_pod_type)
- << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
- << Res->getType()))
+ << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
+ << Res->getType()))
DidWarnAboutNonPOD = true;
}
-
+
LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName);
LookupQualifiedName(R, RD);
-
+
FieldDecl *MemberDecl = R.getAsSingle<FieldDecl>();
// FIXME: Leaks Res
if (!MemberDecl)
return ExprError(Diag(BuiltinLoc, diag::err_no_member)
- << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd));
-
+ << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd));
+
+ // C99 7.17p3:
+ // (If the specified member is a bit-field, the behavior is undefined.)
+ //
+ // We diagnose this as an error.
+ if (MemberDecl->getBitWidth()) {
+ Diag(OC.LocEnd, diag::err_offsetof_bitfield)
+ << MemberDecl->getDeclName()
+ << SourceRange(BuiltinLoc, RPLoc);
+ Diag(MemberDecl->getLocation(), diag::note_bitfield_decl);
+ return ExprError();
+ }
+
// FIXME: C++: Verify that MemberDecl isn't a static field.
// FIXME: Verify that MemberDecl isn't a bitfield.
if (cast<RecordDecl>(MemberDecl->getDeclContext())->isAnonymousStructOrUnion()) {
Res = BuildAnonymousStructUnionMemberReference(
- OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>();
+ OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>();
} else {
PerformObjectMemberConversion(Res, /*Qualifier=*/0,
*R.begin(), MemberDecl);
// MemberDecl->getType() doesn't get the right qualifiers, but it
// doesn't matter here.
Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd,
- MemberDecl->getType().getNonReferenceType());
+ MemberDecl->getType().getNonReferenceType());
}
}
}
-
+
return Owned(new (Context) UnaryOperator(Res, UnaryOperator::OffsetOf,
Context.getSizeType(), BuiltinLoc));
}
@@ -7127,7 +7230,7 @@ Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
return Owned(new (Context) GNUNullExpr(Ty, TokenLoc));
}
-static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType,
+static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType,
Expr *SrcExpr, FixItHint &Hint) {
if (!SemaRef.getLangOptions().ObjC1)
return;
@@ -7155,7 +7258,11 @@ static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType,
bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
SourceLocation Loc,
QualType DstType, QualType SrcType,
- Expr *SrcExpr, AssignmentAction Action) {
+ Expr *SrcExpr, AssignmentAction Action,
+ bool *Complained) {
+ if (Complained)
+ *Complained = false;
+
// Decode the result (notice that AST's are still created for extensions).
bool isInvalid = false;
unsigned DiagKind;
@@ -7218,8 +7325,30 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
break;
}
- Diag(Loc, DiagKind) << DstType << SrcType << Action
+ QualType FirstType, SecondType;
+ switch (Action) {
+ case AA_Assigning:
+ case AA_Initializing:
+ // The destination type comes first.
+ FirstType = DstType;
+ SecondType = SrcType;
+ break;
+
+ case AA_Returning:
+ case AA_Passing:
+ case AA_Converting:
+ case AA_Sending:
+ case AA_Casting:
+ // The source type comes first.
+ FirstType = SrcType;
+ SecondType = DstType;
+ break;
+ }
+
+ Diag(Loc, DiagKind) << FirstType << SecondType << Action
<< SrcExpr->getSourceRange() << Hint;
+ if (Complained)
+ *Complained = true;
return isInvalid;
}
@@ -7328,8 +7457,13 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
// (e.g. (void)sizeof()) constitute a use for warning purposes (-Wunused-variables and
// -Wunused-parameters)
if (isa<ParmVarDecl>(D) ||
- (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod()))
+ (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod())) {
D->setUsed(true);
+ return;
+ }
+
+ if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D))
+ return;
// Do not mark anything as "used" within a dependent context; wait for
// an instantiation.
@@ -7375,7 +7509,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
if (!MethodDecl->isUsed())
- DefineImplicitOverloadedAssign(Loc, MethodDecl);
+ DefineImplicitCopyAssignment(Loc, MethodDecl);
}
}
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
@@ -7536,12 +7670,12 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
SourceLocation Open = E->getSourceRange().getBegin();
SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd());
- Diag(Loc, diagnostic)
- << E->getSourceRange()
- << FixItHint::CreateInsertion(Open, "(")
- << FixItHint::CreateInsertion(Close, ")");
+ Diag(Loc, diagnostic) << E->getSourceRange();
Diag(Loc, diag::note_condition_assign_to_comparison)
<< FixItHint::CreateReplacement(Loc, "==");
+ Diag(Loc, diag::note_condition_assign_silence)
+ << FixItHint::CreateInsertion(Open, "(")
+ << FixItHint::CreateInsertion(Close, ")");
}
bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) {
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 501c877..425fc2d 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -29,7 +29,7 @@ using namespace clang;
Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
IdentifierInfo &II,
SourceLocation NameLoc,
- Scope *S, const CXXScopeSpec &SS,
+ Scope *S, CXXScopeSpec &SS,
TypeTy *ObjectTypePtr,
bool EnteringContext) {
// Determine where to perform name lookup.
@@ -261,7 +261,7 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
Range = SourceRange(NameLoc);
}
- return CheckTypenameType(NNS, II, Range).getAsOpaquePtr();
+ return CheckTypenameType(ETK_None, NNS, II, Range).getAsOpaquePtr();
}
if (ObjectTypePtr)
@@ -273,89 +273,107 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
return 0;
}
-/// ActOnCXXTypeidOfType - Parse typeid( type-id ).
+/// \brief Build a C++ typeid expression with a type operand.
+Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
+ SourceLocation TypeidLoc,
+ TypeSourceInfo *Operand,
+ SourceLocation RParenLoc) {
+ // C++ [expr.typeid]p4:
+ // The top-level cv-qualifiers of the lvalue expression or the type-id
+ // that is the operand of typeid are always ignored.
+ // If the type of the type-id is a class type or a reference to a class
+ // type, the class shall be completely-defined.
+ QualType T = Operand->getType().getNonReferenceType();
+ if (T->getAs<RecordType>() &&
+ RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid))
+ return ExprError();
+
+ return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(),
+ Operand,
+ SourceRange(TypeidLoc, RParenLoc)));
+}
+
+/// \brief Build a C++ typeid expression with an expression operand.
+Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
+ SourceLocation TypeidLoc,
+ ExprArg Operand,
+ SourceLocation RParenLoc) {
+ bool isUnevaluatedOperand = true;
+ Expr *E = static_cast<Expr *>(Operand.get());
+ if (E && !E->isTypeDependent()) {
+ QualType T = E->getType();
+ if (const RecordType *RecordT = T->getAs<RecordType>()) {
+ CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl());
+ // C++ [expr.typeid]p3:
+ // [...] If the type of the expression is a class type, the class
+ // shall be completely-defined.
+ if (RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid))
+ return ExprError();
+
+ // C++ [expr.typeid]p3:
+ // When typeid is applied to an expression other than an lvalue of a
+ // polymorphic class type [...] [the] expression is an unevaluated
+ // operand. [...]
+ if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid)
+ isUnevaluatedOperand = false;
+ }
+
+ // C++ [expr.typeid]p4:
+ // [...] If the type of the type-id is a reference to a possibly
+ // cv-qualified type, the result of the typeid expression refers to a
+ // std::type_info object representing the cv-unqualified referenced
+ // type.
+ if (T.hasQualifiers()) {
+ ImpCastExprToType(E, T.getUnqualifiedType(), CastExpr::CK_NoOp,
+ E->isLvalue(Context));
+ Operand.release();
+ Operand = Owned(E);
+ }
+ }
+
+ // If this is an unevaluated operand, clear out the set of
+ // declaration references we have been computing and eliminate any
+ // temporaries introduced in its computation.
+ if (isUnevaluatedOperand)
+ ExprEvalContexts.back().Context = Unevaluated;
+
+ return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(),
+ Operand.takeAs<Expr>(),
+ SourceRange(TypeidLoc, RParenLoc)));
+}
+
+/// ActOnCXXTypeidOfType - Parse typeid( type-id ) or typeid (expression);
Action::OwningExprResult
Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
bool isType, void *TyOrExpr, SourceLocation RParenLoc) {
+ // Find the std::type_info type.
if (!StdNamespace)
return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
- if (isType) {
- // C++ [expr.typeid]p4:
- // The top-level cv-qualifiers of the lvalue expression or the type-id
- // that is the operand of typeid are always ignored.
- // FIXME: Preserve type source info.
- // FIXME: Preserve the type before we stripped the cv-qualifiers?
- QualType T = GetTypeFromParser(TyOrExpr);
- if (T.isNull())
- return ExprError();
-
- // C++ [expr.typeid]p4:
- // If the type of the type-id is a class type or a reference to a class
- // type, the class shall be completely-defined.
- QualType CheckT = T;
- if (const ReferenceType *RefType = CheckT->getAs<ReferenceType>())
- CheckT = RefType->getPointeeType();
-
- if (CheckT->getAs<RecordType>() &&
- RequireCompleteType(OpLoc, CheckT, diag::err_incomplete_typeid))
- return ExprError();
-
- TyOrExpr = T.getUnqualifiedType().getAsOpaquePtr();
- }
-
IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info");
LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName);
LookupQualifiedName(R, StdNamespace);
RecordDecl *TypeInfoRecordDecl = R.getAsSingle<RecordDecl>();
if (!TypeInfoRecordDecl)
return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
-
+
QualType TypeInfoType = Context.getTypeDeclType(TypeInfoRecordDecl);
+
+ if (isType) {
+ // The operand is a type; handle it as such.
+ TypeSourceInfo *TInfo = 0;
+ QualType T = GetTypeFromParser(TyOrExpr, &TInfo);
+ if (T.isNull())
+ return ExprError();
+
+ if (!TInfo)
+ TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc);
- if (!isType) {
- bool isUnevaluatedOperand = true;
- Expr *E = static_cast<Expr *>(TyOrExpr);
- if (E && !E->isTypeDependent()) {
- QualType T = E->getType();
- if (const RecordType *RecordT = T->getAs<RecordType>()) {
- CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl());
- // C++ [expr.typeid]p3:
- // [...] If the type of the expression is a class type, the class
- // shall be completely-defined.
- if (RequireCompleteType(OpLoc, T, diag::err_incomplete_typeid))
- return ExprError();
-
- // C++ [expr.typeid]p3:
- // When typeid is applied to an expression other than an lvalue of a
- // polymorphic class type [...] [the] expression is an unevaluated
- // operand. [...]
- if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid)
- isUnevaluatedOperand = false;
- }
-
- // C++ [expr.typeid]p4:
- // [...] If the type of the type-id is a reference to a possibly
- // cv-qualified type, the result of the typeid expression refers to a
- // std::type_info object representing the cv-unqualified referenced
- // type.
- if (T.hasQualifiers()) {
- ImpCastExprToType(E, T.getUnqualifiedType(), CastExpr::CK_NoOp,
- E->isLvalue(Context));
- TyOrExpr = E;
- }
- }
-
- // If this is an unevaluated operand, clear out the set of
- // declaration references we have been computing and eliminate any
- // temporaries introduced in its computation.
- if (isUnevaluatedOperand)
- ExprEvalContexts.back().Context = Unevaluated;
+ return BuildCXXTypeId(TypeInfoType, OpLoc, TInfo, RParenLoc);
}
- return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr,
- TypeInfoType.withConst(),
- SourceRange(OpLoc, RParenLoc)));
+ // The operand is an expression.
+ return BuildCXXTypeId(TypeInfoType, OpLoc, Owned((Expr*)TyOrExpr), RParenLoc);
}
/// ActOnCXXBoolLiteral - Parse {true,false} literals.
@@ -399,10 +417,10 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
// If the type of the exception would be an incomplete type or a pointer
// to an incomplete type other than (cv) void the program is ill-formed.
QualType Ty = E->getType();
- int isPointer = 0;
+ bool isPointer = false;
if (const PointerType* Ptr = Ty->getAs<PointerType>()) {
Ty = Ptr->getPointeeType();
- isPointer = 1;
+ isPointer = true;
}
if (!isPointer || !Ty->isVoidType()) {
if (RequireCompleteType(ThrowLoc, Ty,
@@ -411,20 +429,22 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
<< E->getSourceRange()))
return true;
- // FIXME: This is just a hack to mark the copy constructor referenced.
- // This should go away when the next FIXME is fixed.
- const RecordType *RT = Ty->getAs<RecordType>();
- if (!RT)
- return false;
-
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialCopyConstructor())
- return false;
- CXXConstructorDecl *CopyCtor = RD->getCopyConstructor(Context, 0);
- MarkDeclarationReferenced(ThrowLoc, CopyCtor);
+ if (RequireNonAbstractType(ThrowLoc, E->getType(),
+ PDiag(diag::err_throw_abstract_type)
+ << E->getSourceRange()))
+ return true;
}
- // FIXME: Construct a temporary here.
+ // Initialize the exception result. This implicitly weeds out
+ // abstract types or types with inaccessible copy constructors.
+ InitializedEntity Entity =
+ InitializedEntity::InitializeException(ThrowLoc, E->getType());
+ OwningExprResult Res = PerformCopyInitialization(Entity,
+ SourceLocation(),
+ Owned(E));
+ if (Res.isInvalid())
+ return true;
+ E = Res.takeAs<Expr>();
return false;
}
@@ -499,25 +519,17 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
//
if (NumExprs == 1) {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
- CXXMethodDecl *Method = 0;
- if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, Method,
+ CXXBaseSpecifierArray BasePath;
+ if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, BasePath,
/*FunctionalStyle=*/true))
return ExprError();
exprs.release();
- if (Method) {
- OwningExprResult CastArg
- = BuildCXXCastArgument(TypeRange.getBegin(), Ty.getNonReferenceType(),
- Kind, Method, Owned(Exprs[0]));
- if (CastArg.isInvalid())
- return ExprError();
-
- Exprs[0] = CastArg.takeAs<Expr>();
- }
return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(),
TInfo, TyBeginLoc, Kind,
- Exprs[0], RParenLoc));
+ Exprs[0], BasePath,
+ RParenLoc));
}
if (const RecordType *RT = Ty->getAs<RecordType>()) {
@@ -708,10 +720,10 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
OperatorNew->getType()->getAs<FunctionProtoType>();
VariadicCallType CallType =
Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply;
- bool Invalid = GatherArgumentsForCall(PlacementLParen, OperatorNew,
- Proto, 1, PlaceArgs, NumPlaceArgs,
- AllPlaceArgs, CallType);
- if (Invalid)
+
+ if (GatherArgumentsForCall(PlacementLParen, OperatorNew,
+ Proto, 1, PlaceArgs, NumPlaceArgs,
+ AllPlaceArgs, CallType))
return ExprError();
NumPlaceArgs = AllPlaceArgs.size();
@@ -726,6 +738,15 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
unsigned NumConsArgs = ConstructorArgs.size();
ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this);
+ // Array 'new' can't have any initializers.
+ if (NumConsArgs && ArraySize) {
+ SourceRange InitRange(ConsArgs[0]->getLocStart(),
+ ConsArgs[NumConsArgs - 1]->getLocEnd());
+
+ Diag(StartLoc, diag::err_new_array_init_args) << InitRange;
+ return ExprError();
+ }
+
if (!AllocType->isDependentType() &&
!Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) {
// C++0x [expr.new]p15:
@@ -892,6 +913,13 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
return true;
}
+ // We don't need an operator delete if we're running under
+ // -fno-exceptions.
+ if (!getLangOptions().Exceptions) {
+ OperatorDelete = 0;
+ return false;
+ }
+
// FindAllocationOverload can change the passed in arguments, so we need to
// copy them back.
if (NumPlaceArgs > 0)
@@ -1214,7 +1242,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
FunctionType::ExtInfo());
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
- FnType, /*TInfo=*/0, FunctionDecl::None, false, true);
+ FnType, /*TInfo=*/0, FunctionDecl::None,
+ FunctionDecl::None, false, true);
Alloc->setImplicit();
if (AddMallocAttr)
@@ -1222,6 +1251,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
0, Argument, /*TInfo=*/0,
+ VarDecl::None,
VarDecl::None, 0);
Alloc->setParams(&Param, 1);
@@ -1258,8 +1288,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
F != FEnd; ++F) {
- Diag((*F)->getLocation(),
- diag::note_delete_member_function_declared_here)
+ Diag((*F)->getLocation(), diag::note_member_declared_here)
<< Name;
}
@@ -1396,6 +1425,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
return ExprError();
}
+ MarkDeclarationReferenced(StartLoc, OperatorDelete);
+
// FIXME: Check access and ambiguity of operator delete and destructor.
}
@@ -1469,45 +1500,43 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
return false;
}
-/// PerformImplicitConversion - Perform an implicit conversion of the
-/// expression From to the type ToType. Returns true if there was an
-/// error, false otherwise. The expression From is replaced with the
-/// converted expression. Flavor is the kind of conversion we're
-/// performing, used in the error message. If @p AllowExplicit,
-/// explicit user-defined conversions are permitted. @p Elidable should be true
-/// when called for copies which may be elided (C++ 12.8p15). C++0x overload
-/// resolution works differently in that case.
-bool
-Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
- AssignmentAction Action, bool AllowExplicit,
- bool Elidable) {
- ImplicitConversionSequence ICS;
- return PerformImplicitConversion(From, ToType, Action, AllowExplicit,
- Elidable, ICS);
-}
-
-bool
-Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
- AssignmentAction Action, bool AllowExplicit,
- bool Elidable,
- ImplicitConversionSequence& ICS) {
- ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
- if (Elidable && getLangOptions().CPlusPlus0x) {
- ICS = TryImplicitConversion(From, ToType,
- /*SuppressUserConversions=*/false,
- AllowExplicit,
- /*ForceRValue=*/true,
- /*InOverloadResolution=*/false);
- }
- if (ICS.isBad()) {
- ICS = TryImplicitConversion(From, ToType,
- /*SuppressUserConversions=*/false,
- AllowExplicit,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
- }
- return PerformImplicitConversion(From, ToType, ICS, Action);
-}
+static Sema::OwningExprResult BuildCXXCastArgument(Sema &S,
+ SourceLocation CastLoc,
+ QualType Ty,
+ CastExpr::CastKind Kind,
+ CXXMethodDecl *Method,
+ Sema::ExprArg Arg) {
+ Expr *From = Arg.takeAs<Expr>();
+
+ switch (Kind) {
+ default: assert(0 && "Unhandled cast kind!");
+ case CastExpr::CK_ConstructorConversion: {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
+
+ if (S.CompleteConstructorCall(cast<CXXConstructorDecl>(Method),
+ Sema::MultiExprArg(S, (void **)&From, 1),
+ CastLoc, ConstructorArgs))
+ return S.ExprError();
+
+ Sema::OwningExprResult Result =
+ S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
+ move_arg(ConstructorArgs));
+ if (Result.isInvalid())
+ return S.ExprError();
+
+ return S.MaybeBindToTemporary(Result.takeAs<Expr>());
+ }
+
+ case CastExpr::CK_UserDefinedConversion: {
+ assert(!From->getType()->isPointerType() && "Arg can't have pointer type!");
+
+ // Create an implicit call expr that calls it.
+ // FIXME: pass the FoundDecl for the user-defined conversion here
+ CXXMemberCallExpr *CE = S.BuildCXXMemberCallExpr(From, Method, Method);
+ return S.MaybeBindToTemporary(CE);
+ }
+ }
+}
/// PerformImplicitConversion - Perform an implicit conversion of the
/// expression From to the type ToType using the pre-computed implicit
@@ -1560,7 +1589,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
}
OwningExprResult CastArg
- = BuildCXXCastArgument(From->getLocStart(),
+ = BuildCXXCastArgument(*this,
+ From->getLocStart(),
ToType.getNonReferenceType(),
CastKind, cast<CXXMethodDecl>(FD),
Owned(From));
@@ -1639,6 +1669,21 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
return false;
}
+ // Resolve overloaded function references.
+ if (Context.hasSameType(FromType, Context.OverloadTy)) {
+ DeclAccessPair Found;
+ FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType,
+ true, Found);
+ if (!Fn)
+ return true;
+
+ if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin()))
+ return true;
+
+ From = FixOverloadedFunctionReference(From, Found, Fn);
+ FromType = From->getType();
+ }
+
// Perform the first implicit conversion.
switch (SCS.First) {
case ICK_Identity:
@@ -1652,25 +1697,6 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
break;
case ICK_Function_To_Pointer:
- if (Context.getCanonicalType(FromType) == Context.OverloadTy) {
- DeclAccessPair Found;
- FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType,
- true, Found);
- if (!Fn)
- return true;
-
- if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin()))
- return true;
-
- From = FixOverloadedFunctionReference(From, Found, Fn);
- FromType = From->getType();
-
- // If there's already an address-of operator in the expression, we have
- // the right type already, and the code below would just introduce an
- // invalid additional pointer level.
- if (FromType->isPointerType() || FromType->isMemberFunctionPointerType())
- break;
- }
FromType = Context.getPointerType(FromType);
ImpCastExprToType(From, FromType, CastExpr::CK_FunctionToPointerDecay);
break;
@@ -1741,19 +1767,22 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
- if (CheckPointerConversion(From, ToType, Kind, IgnoreBaseAccess))
+ CXXBaseSpecifierArray BasePath;
+ if (CheckPointerConversion(From, ToType, Kind, BasePath, IgnoreBaseAccess))
return true;
- ImpCastExprToType(From, ToType, Kind);
+ ImpCastExprToType(From, ToType, Kind, /*isLvalue=*/false, BasePath);
break;
}
case ICK_Pointer_Member: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
- if (CheckMemberPointerConversion(From, ToType, Kind, IgnoreBaseAccess))
+ CXXBaseSpecifierArray BasePath;
+ if (CheckMemberPointerConversion(From, ToType, Kind, BasePath,
+ IgnoreBaseAccess))
return true;
if (CheckExceptionSpecCompatibility(From, ToType))
return true;
- ImpCastExprToType(From, ToType, Kind);
+ ImpCastExprToType(From, ToType, Kind, /*isLvalue=*/false, BasePath);
break;
}
case ICK_Boolean_Conversion: {
@@ -1769,7 +1798,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
if (CheckDerivedToBaseConversion(From->getType(),
ToType.getNonReferenceType(),
From->getLocStart(),
- From->getSourceRange(),
+ From->getSourceRange(), 0,
IgnoreBaseAccess))
return true;
ImpCastExprToType(From, ToType.getNonReferenceType(),
@@ -1790,8 +1819,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
// FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue
// references.
ImpCastExprToType(From, ToType.getNonReferenceType(),
- CastExpr::CK_NoOp,
- ToType->isLValueReferenceType());
+ CastExpr::CK_NoOp, ToType->isLValueReferenceType());
if (SCS.DeprecatedStringLiteralToCharPtr)
Diag(From->getLocStart(), diag::warn_deprecated_string_literal_conversion)
@@ -1847,6 +1875,9 @@ QualType Sema::CheckPointerToMemberOperands(
QualType Class(MemPtr->getClass(), 0);
+ if (RequireCompleteType(Loc, Class, diag::err_memptr_rhs_to_incomplete))
+ return QualType();
+
// C++ 5.5p2
// [...] to its first operand, which shall be of class T or of a class of
// which T is an unambiguous and accessible base class. [p3: a pointer to
@@ -1864,7 +1895,12 @@ QualType Sema::CheckPointerToMemberOperands(
}
if (!Context.hasSameUnqualifiedType(Class, LType)) {
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+ // If we want to check the hierarchy, we need a complete type.
+ if (RequireCompleteType(Loc, LType, PDiag(diag::err_bad_memptr_lhs)
+ << OpSpelling << (int)isIndirect)) {
+ return QualType();
+ }
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/false);
// FIXME: Would it be useful to print full ambiguity paths, or is that
// overkill?
@@ -1877,7 +1913,11 @@ QualType Sema::CheckPointerToMemberOperands(
// Cast LHS to type of use.
QualType UseType = isIndirect ? Context.getPointerType(Class) : Class;
bool isLValue = !isIndirect && lex->isLvalue(Context) == Expr::LV_Valid;
- ImpCastExprToType(lex, UseType, CastExpr::CK_DerivedToBase, isLValue);
+
+ CXXBaseSpecifierArray BasePath;
+ BuildBasePathArray(Paths, BasePath);
+ ImpCastExprToType(lex, UseType, CastExpr::CK_DerivedToBase, isLValue,
+ BasePath);
}
if (isa<CXXZeroInitValueExpr>(rex->IgnoreParens())) {
@@ -2201,7 +2241,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// shall match the cv-qualification of either the second or the third
// operand. The result is of the common type.
bool NonStandardCompositeType = false;
- QualType Composite = FindCompositePointerType(LHS, RHS,
+ QualType Composite = FindCompositePointerType(QuestionLoc, LHS, RHS,
isSFINAEContext()? 0 : &NonStandardCompositeType);
if (!Composite.isNull()) {
if (NonStandardCompositeType)
@@ -2231,11 +2271,15 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
/// type and returns it.
/// It does not emit diagnostics.
///
+/// \param Loc The location of the operator requiring these two expressions to
+/// be converted to the composite pointer type.
+///
/// If \p NonStandardCompositeType is non-NULL, then we are permitted to find
/// a non-standard (but still sane) composite type to which both expressions
/// can be converted. When such a type is chosen, \c *NonStandardCompositeType
/// will be set true.
-QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2,
+QualType Sema::FindCompositePointerType(SourceLocation Loc,
+ Expr *&E1, Expr *&E2,
bool *NonStandardCompositeType) {
if (NonStandardCompositeType)
*NonStandardCompositeType = false;
@@ -2372,48 +2416,70 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2,
}
}
- ImplicitConversionSequence E1ToC1 =
- TryImplicitConversion(E1, Composite1,
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
- ImplicitConversionSequence E2ToC1 =
- TryImplicitConversion(E2, Composite1,
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
-
- bool ToC2Viable = false;
- ImplicitConversionSequence E1ToC2, E2ToC2;
- if (Context.getCanonicalType(Composite1) !=
- Context.getCanonicalType(Composite2)) {
- E1ToC2 = TryImplicitConversion(E1, Composite2,
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
- E2ToC2 = TryImplicitConversion(E2, Composite2,
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
- ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad();
- }
-
- bool ToC1Viable = !E1ToC1.isBad() && !E2ToC1.isBad();
- if (ToC1Viable && !ToC2Viable) {
- if (!PerformImplicitConversion(E1, Composite1, E1ToC1, Sema::AA_Converting) &&
- !PerformImplicitConversion(E2, Composite1, E2ToC1, Sema::AA_Converting))
- return Composite1;
- }
- if (ToC2Viable && !ToC1Viable) {
- if (!PerformImplicitConversion(E1, Composite2, E1ToC2, Sema::AA_Converting) &&
- !PerformImplicitConversion(E2, Composite2, E2ToC2, Sema::AA_Converting))
- return Composite2;
+ // Try to convert to the first composite pointer type.
+ InitializedEntity Entity1
+ = InitializedEntity::InitializeTemporary(Composite1);
+ InitializationKind Kind
+ = InitializationKind::CreateCopy(Loc, SourceLocation());
+ InitializationSequence E1ToC1(*this, Entity1, Kind, &E1, 1);
+ InitializationSequence E2ToC1(*this, Entity1, Kind, &E2, 1);
+
+ if (E1ToC1 && E2ToC1) {
+ // Conversion to Composite1 is viable.
+ if (!Context.hasSameType(Composite1, Composite2)) {
+ // Composite2 is a different type from Composite1. Check whether
+ // Composite2 is also viable.
+ InitializedEntity Entity2
+ = InitializedEntity::InitializeTemporary(Composite2);
+ InitializationSequence E1ToC2(*this, Entity2, Kind, &E1, 1);
+ InitializationSequence E2ToC2(*this, Entity2, Kind, &E2, 1);
+ if (E1ToC2 && E2ToC2) {
+ // Both Composite1 and Composite2 are viable and are different;
+ // this is an ambiguity.
+ return QualType();
+ }
+ }
+
+ // Convert E1 to Composite1
+ OwningExprResult E1Result
+ = E1ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,(void**)&E1,1));
+ if (E1Result.isInvalid())
+ return QualType();
+ E1 = E1Result.takeAs<Expr>();
+
+ // Convert E2 to Composite1
+ OwningExprResult E2Result
+ = E2ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,(void**)&E2,1));
+ if (E2Result.isInvalid())
+ return QualType();
+ E2 = E2Result.takeAs<Expr>();
+
+ return Composite1;
}
- return QualType();
+
+ // Check whether Composite2 is viable.
+ InitializedEntity Entity2
+ = InitializedEntity::InitializeTemporary(Composite2);
+ InitializationSequence E1ToC2(*this, Entity2, Kind, &E1, 1);
+ InitializationSequence E2ToC2(*this, Entity2, Kind, &E2, 1);
+ if (!E1ToC2 || !E2ToC2)
+ return QualType();
+
+ // Convert E1 to Composite2
+ OwningExprResult E1Result
+ = E1ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, (void**)&E1, 1));
+ if (E1Result.isInvalid())
+ return QualType();
+ E1 = E1Result.takeAs<Expr>();
+
+ // Convert E2 to Composite2
+ OwningExprResult E2Result
+ = E2ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, (void**)&E2, 1));
+ if (E2Result.isInvalid())
+ return QualType();
+ E2 = E2Result.takeAs<Expr>();
+
+ return Composite2;
}
Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
@@ -2450,8 +2516,12 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
RD->getDestructor(Context));
ExprTemporaries.push_back(Temp);
if (CXXDestructorDecl *Destructor =
- const_cast<CXXDestructorDecl*>(RD->getDestructor(Context)))
+ const_cast<CXXDestructorDecl*>(RD->getDestructor(Context))) {
MarkDeclarationReferenced(E->getExprLoc(), Destructor);
+ CheckDestructorAccess(E->getExprLoc(), Destructor,
+ PDiag(diag::err_access_dtor_temp)
+ << E->getType());
+ }
// FIXME: Add the temporary to the temporaries vector.
return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E));
}
@@ -2701,7 +2771,7 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base,
Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &FirstTypeName,
SourceLocation CCLoc,
SourceLocation TildeLoc,
@@ -2869,43 +2939,6 @@ CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
return CE;
}
-Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc,
- QualType Ty,
- CastExpr::CastKind Kind,
- CXXMethodDecl *Method,
- ExprArg Arg) {
- Expr *From = Arg.takeAs<Expr>();
-
- switch (Kind) {
- default: assert(0 && "Unhandled cast kind!");
- case CastExpr::CK_ConstructorConversion: {
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
-
- if (CompleteConstructorCall(cast<CXXConstructorDecl>(Method),
- MultiExprArg(*this, (void **)&From, 1),
- CastLoc, ConstructorArgs))
- return ExprError();
-
- OwningExprResult Result =
- BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
- move_arg(ConstructorArgs));
- if (Result.isInvalid())
- return ExprError();
-
- return MaybeBindToTemporary(Result.takeAs<Expr>());
- }
-
- case CastExpr::CK_UserDefinedConversion: {
- assert(!From->getType()->isPointerType() && "Arg can't have pointer type!");
-
- // Create an implicit call expr that calls it.
- // FIXME: pass the FoundDecl for the user-defined conversion here
- CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method, Method);
- return MaybeBindToTemporary(CE);
- }
- }
-}
-
Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
Expr *FullExpr = Arg.takeAs<Expr>();
if (FullExpr)
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index d5a22ca..db9a2e2 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -12,9 +12,12 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
+#include "SemaInit.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/TypeLoc.h"
#include "llvm/ADT/SmallString.h"
#include "clang/Lex/Preprocessor.h"
@@ -75,9 +78,25 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
QualType Ty = Context.getObjCConstantStringInterface();
if (!Ty.isNull()) {
Ty = Context.getObjCObjectPointerType(Ty);
+ } else if (getLangOptions().NoConstantCFStrings) {
+ IdentifierInfo *NSIdent = &Context.Idents.get("NSConstantString");
+ NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLocs[0],
+ LookupOrdinaryName);
+ if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
+ Context.setObjCConstantStringInterface(StrIF);
+ Ty = Context.getObjCConstantStringInterface();
+ Ty = Context.getObjCObjectPointerType(Ty);
+ } else {
+ // If there is no NSConstantString interface defined then treat this
+ // as error and recover from it.
+ Diag(S->getLocStart(), diag::err_no_nsconstant_string_class) << NSIdent
+ << S->getSourceRange();
+ Ty = Context.getObjCIdType();
+ }
} else {
IdentifierInfo *NSIdent = &Context.Idents.get("NSString");
- NamedDecl *IF = LookupSingleName(TUScope, NSIdent, LookupOrdinaryName);
+ NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLocs[0],
+ LookupOrdinaryName);
if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
Context.setObjCConstantStringInterface(StrIF);
Ty = Context.getObjCConstantStringInterface();
@@ -93,8 +112,9 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
}
Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
- QualType EncodedType,
+ TypeSourceInfo *EncodedTypeInfo,
SourceLocation RParenLoc) {
+ QualType EncodedType = EncodedTypeInfo->getType();
QualType StrTy;
if (EncodedType->isDependentType())
StrTy = Context.DependentTy;
@@ -112,7 +132,7 @@ Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
ArrayType::Normal, 0);
}
- return new (Context) ObjCEncodeExpr(StrTy, EncodedType, AtLoc, RParenLoc);
+ return new (Context) ObjCEncodeExpr(StrTy, EncodedTypeInfo, AtLoc, RParenLoc);
}
Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,
@@ -121,9 +141,13 @@ Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,
TypeTy *ty,
SourceLocation RParenLoc) {
// FIXME: Preserve type source info ?
- QualType EncodedType = GetTypeFromParser(ty);
+ TypeSourceInfo *TInfo;
+ QualType EncodedType = GetTypeFromParser(ty, &TInfo);
+ if (!TInfo)
+ TInfo = Context.getTrivialTypeSourceInfo(EncodedType,
+ PP.getLocForEndOfToken(LParenLoc));
- return BuildObjCEncodeExpression(AtLoc, EncodedType, RParenLoc);
+ return BuildObjCEncodeExpression(AtLoc, TInfo, RParenLoc);
}
Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
@@ -148,7 +172,7 @@ Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
SourceLocation ProtoLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc) {
- ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId);
+ ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId, ProtoLoc);
if (!PDecl) {
Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId;
return true;
@@ -168,8 +192,12 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
QualType &ReturnType) {
if (!Method) {
// Apply default argument promotion as for (C99 6.5.2.2p6).
- for (unsigned i = 0; i != NumArgs; i++)
+ for (unsigned i = 0; i != NumArgs; i++) {
+ if (Args[i]->isTypeDependent())
+ continue;
+
DefaultArgumentPromotion(Args[i]);
+ }
unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found :
diag::warn_inst_method_not_found;
@@ -179,50 +207,68 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
return false;
}
- ReturnType = Method->getResultType();
+ ReturnType = Method->getResultType().getNonReferenceType();
unsigned NumNamedArgs = Sel.getNumArgs();
- assert(NumArgs >= NumNamedArgs && "Too few arguments for selector!");
+ // Method might have more arguments than selector indicates. This is due
+ // to addition of c-style arguments in method.
+ if (Method->param_size() > Sel.getNumArgs())
+ NumNamedArgs = Method->param_size();
+ // FIXME. This need be cleaned up.
+ if (NumArgs < NumNamedArgs) {
+ Diag(lbrac, diag::err_typecheck_call_too_few_args) << 2
+ << NumNamedArgs << NumArgs;
+ return false;
+ }
bool IsError = false;
for (unsigned i = 0; i < NumNamedArgs; i++) {
- Expr *argExpr = Args[i];
- assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
+ // We can't do any type-checking on a type-dependent argument.
+ if (Args[i]->isTypeDependent())
+ continue;
- QualType lhsType = Method->param_begin()[i]->getType();
- QualType rhsType = argExpr->getType();
+ Expr *argExpr = Args[i];
- // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8].
- if (lhsType->isArrayType())
- lhsType = Context.getArrayDecayedType(lhsType);
- else if (lhsType->isFunctionType())
- lhsType = Context.getPointerType(lhsType);
+ ParmVarDecl *Param = Method->param_begin()[i];
+ assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
- AssignConvertType Result =
- CheckSingleAssignmentConstraints(lhsType, argExpr);
- if (Args[i] != argExpr) // The expression was converted.
- Args[i] = argExpr; // Make sure we store the converted expression.
+ if (RequireCompleteType(argExpr->getSourceRange().getBegin(),
+ Param->getType(),
+ PDiag(diag::err_call_incomplete_argument)
+ << argExpr->getSourceRange()))
+ return true;
- IsError |=
- DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType,
- argExpr, AA_Sending);
+ InitializedEntity Entity = InitializedEntity::InitializeParameter(Param);
+ OwningExprResult ArgE = PerformCopyInitialization(Entity,
+ SourceLocation(),
+ Owned(argExpr->Retain()));
+ if (ArgE.isInvalid())
+ IsError = true;
+ else
+ Args[i] = ArgE.takeAs<Expr>();
}
// Promote additional arguments to variadic methods.
if (Method->isVariadic()) {
- for (unsigned i = NumNamedArgs; i < NumArgs; ++i)
+ for (unsigned i = NumNamedArgs; i < NumArgs; ++i) {
+ if (Args[i]->isTypeDependent())
+ continue;
+
IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod);
+ }
} else {
// Check for extra arguments to non-variadic methods.
if (NumArgs != NumNamedArgs) {
Diag(Args[NumNamedArgs]->getLocStart(),
diag::err_typecheck_call_too_many_args)
- << 2 /*method*/ << Method->getSourceRange()
+ << 2 /*method*/ << NumNamedArgs << NumArgs
+ << Method->getSourceRange()
<< SourceRange(Args[NumNamedArgs]->getLocStart(),
Args[NumArgs-1]->getLocEnd());
}
}
+ DiagnoseSentinelCalls(Method, lbrac, Args, NumArgs);
return IsError;
}
@@ -281,20 +327,147 @@ ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel,
return Method;
}
-Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
- IdentifierInfo &receiverName,
- IdentifierInfo &propertyName,
- SourceLocation &receiverNameLoc,
- SourceLocation &propertyNameLoc) {
+/// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an
+/// objective C interface. This is a property reference expression.
+Action::OwningExprResult Sema::
+HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
+ Expr *BaseExpr, DeclarationName MemberName,
+ SourceLocation MemberLoc) {
+ const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
+ ObjCInterfaceDecl *IFace = IFaceT->getDecl();
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
- IdentifierInfo *receiverNamePtr = &receiverName;
- ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr);
- if (!IFace) {
- Diag(receiverNameLoc, diag::err_expected_ident_or_lparen);
+ // Search for a declared property first.
+ if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) {
+ // Check whether we can reference this property.
+ if (DiagnoseUseOfDecl(PD, MemberLoc))
+ return ExprError();
+ QualType ResTy = PD->getType();
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
+ ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
+ if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))
+ ResTy = Getter->getResultType();
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
+ MemberLoc, BaseExpr));
+ }
+ // Check protocols on qualified interfaces.
+ for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
+ E = OPT->qual_end(); I != E; ++I)
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
+ // Check whether we can reference this property.
+ if (DiagnoseUseOfDecl(PD, MemberLoc))
+ return ExprError();
+
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+ MemberLoc, BaseExpr));
+ }
+ // If that failed, look for an "implicit" property by seeing if the nullary
+ // selector is implemented.
+
+ // FIXME: The logic for looking up nullary and unary selectors should be
+ // shared with the code in ActOnInstanceMessage.
+
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
+ ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
+
+ // If this reference is in an @implementation, check for 'private' methods.
+ if (!Getter)
+ Getter = IFace->lookupPrivateInstanceMethod(Sel);
+
+ // Look through local category implementations associated with the class.
+ if (!Getter)
+ Getter = IFace->getCategoryInstanceMethod(Sel);
+ if (Getter) {
+ // Check if we can reference this property.
+ if (DiagnoseUseOfDecl(Getter, MemberLoc))
+ return ExprError();
+ }
+ // If we found a getter then this may be a valid dot-reference, we
+ // will look for the matching setter, in case it is needed.
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(), Member);
+ ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
+ if (!Setter) {
+ // If this reference is in an @implementation, also check for 'private'
+ // methods.
+ Setter = IFace->lookupPrivateInstanceMethod(SetterSel);
+ }
+ // Look through local category implementations associated with the class.
+ if (!Setter)
+ Setter = IFace->getCategoryInstanceMethod(SetterSel);
+
+ if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
return ExprError();
+
+ if (Getter) {
+ QualType PType;
+ PType = Getter->getResultType();
+ return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType,
+ Setter, MemberLoc, BaseExpr));
+ }
+
+ // Attempt to correct for typos in property names.
+ LookupResult Res(*this, MemberName, MemberLoc, LookupOrdinaryName);
+ if (CorrectTypo(Res, 0, 0, IFace, false, CTC_NoKeywords, OPT) &&
+ Res.getAsSingle<ObjCPropertyDecl>()) {
+ DeclarationName TypoResult = Res.getLookupName();
+ Diag(MemberLoc, diag::err_property_not_found_suggest)
+ << MemberName << QualType(OPT, 0) << TypoResult
+ << FixItHint::CreateReplacement(MemberLoc, TypoResult.getAsString());
+ ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>();
+ Diag(Property->getLocation(), diag::note_previous_decl)
+ << Property->getDeclName();
+ return HandleExprPropertyRefExpr(OPT, BaseExpr, TypoResult, MemberLoc);
+ }
+
+ Diag(MemberLoc, diag::err_property_not_found)
+ << MemberName << QualType(OPT, 0);
+ if (Setter && !Getter)
+ Diag(Setter->getLocation(), diag::note_getter_unavailable)
+ << MemberName << BaseExpr->getSourceRange();
+ return ExprError();
+}
+
+
+
+Action::OwningExprResult Sema::
+ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
+ IdentifierInfo &propertyName,
+ SourceLocation receiverNameLoc,
+ SourceLocation propertyNameLoc) {
+
+ IdentifierInfo *receiverNamePtr = &receiverName;
+ ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr,
+ receiverNameLoc);
+ if (IFace == 0) {
+ // If the "receiver" is 'super' in a method, handle it as an expression-like
+ // property reference.
+ if (ObjCMethodDecl *CurMethod = getCurMethodDecl())
+ if (receiverNamePtr->isStr("super")) {
+ if (CurMethod->isInstanceMethod()) {
+ QualType T =
+ Context.getObjCInterfaceType(CurMethod->getClassInterface());
+ T = Context.getObjCObjectPointerType(T);
+ Expr *SuperExpr = new (Context) ObjCSuperExpr(receiverNameLoc, T);
+
+ return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(),
+ SuperExpr, &propertyName,
+ propertyNameLoc);
+ }
+
+ // Otherwise, if this is a class method, try dispatching to our
+ // superclass.
+ IFace = CurMethod->getClassInterface()->getSuperClass();
+ }
+
+ if (IFace == 0) {
+ Diag(receiverNameLoc, diag::err_expected_ident_or_lparen);
+ return ExprError();
+ }
}
- // Search for a declared property first.
+ // Search for a declared property first.
Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName);
ObjCMethodDecl *Getter = IFace->lookupClassMethod(Sel);
@@ -351,329 +524,502 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
<< &propertyName << Context.getObjCInterfaceType(IFace));
}
+Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ bool IsSuper,
+ bool HasTrailingDot,
+ TypeTy *&ReceiverType) {
+ ReceiverType = 0;
+
+ // If the identifier is "super" and there is no trailing dot, we're
+ // messaging super.
+ if (IsSuper && !HasTrailingDot && S->isInObjcMethodScope())
+ return ObjCSuperMessage;
+
+ LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
+ LookupName(Result, S);
+
+ switch (Result.getResultKind()) {
+ case LookupResult::NotFound:
+ // Normal name lookup didn't find anything. If we're in an
+ // Objective-C method, look for ivars. If we find one, we're done!
+ // FIXME: This is a hack. Ivar lookup should be part of normal lookup.
+ if (ObjCMethodDecl *Method = getCurMethodDecl()) {
+ ObjCInterfaceDecl *ClassDeclared;
+ if (Method->getClassInterface()->lookupInstanceVariable(Name,
+ ClassDeclared))
+ return ObjCInstanceMessage;
+ }
+
+ // Break out; we'll perform typo correction below.
+ break;
+
+ case LookupResult::NotFoundInCurrentInstantiation:
+ case LookupResult::FoundOverloaded:
+ case LookupResult::FoundUnresolvedValue:
+ case LookupResult::Ambiguous:
+ Result.suppressDiagnostics();
+ return ObjCInstanceMessage;
+
+ case LookupResult::Found: {
+ // We found something. If it's a type, then we have a class
+ // message. Otherwise, it's an instance message.
+ NamedDecl *ND = Result.getFoundDecl();
+ QualType T;
+ if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND))
+ T = Context.getObjCInterfaceType(Class);
+ else if (TypeDecl *Type = dyn_cast<TypeDecl>(ND))
+ T = Context.getTypeDeclType(Type);
+ else
+ return ObjCInstanceMessage;
+
+ // We have a class message, and T is the type we're
+ // messaging. Build source-location information for it.
+ TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
+ ReceiverType = CreateLocInfoType(T, TSInfo).getAsOpaquePtr();
+ return ObjCClassMessage;
+ }
+ }
-// ActOnClassMessage - used for both unary and keyword messages.
-// ArgExprs is optional - if it is present, the number of expressions
-// is obtained from Sel.getNumArgs().
-Sema::ExprResult Sema::ActOnClassMessage(
- Scope *S,
- IdentifierInfo *receiverName, Selector Sel,
- SourceLocation lbrac, SourceLocation receiverLoc,
- SourceLocation selectorLoc, SourceLocation rbrac,
- ExprTy **Args, unsigned NumArgs) {
- assert(receiverName && "missing receiver class name");
-
- Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
- ObjCInterfaceDecl* ClassDecl = 0;
- bool isSuper = false;
-
- if (receiverName->isStr("super")) {
- if (getCurMethodDecl()) {
- isSuper = true;
- ObjCInterfaceDecl *OID = getCurMethodDecl()->getClassInterface();
- if (!OID)
- return Diag(lbrac, diag::error_no_super_class_message)
- << getCurMethodDecl()->getDeclName();
- ClassDecl = OID->getSuperClass();
- if (!ClassDecl)
- return Diag(lbrac, diag::error_no_super_class) << OID->getDeclName();
- if (getCurMethodDecl()->isInstanceMethod()) {
- QualType superTy = Context.getObjCInterfaceType(ClassDecl);
- superTy = Context.getObjCObjectPointerType(superTy);
- ExprResult ReceiverExpr = new (Context) ObjCSuperExpr(SourceLocation(),
- superTy);
- // We are really in an instance method, redirect.
- return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
- selectorLoc, rbrac, Args, NumArgs);
+ // Determine our typo-correction context.
+ CorrectTypoContext CTC = CTC_Expression;
+ if (ObjCMethodDecl *Method = getCurMethodDecl())
+ if (Method->getClassInterface() &&
+ Method->getClassInterface()->getSuperClass())
+ CTC = CTC_ObjCMessageReceiver;
+
+ if (DeclarationName Corrected = CorrectTypo(Result, S, 0, 0, false, CTC)) {
+ if (Result.isSingleResult()) {
+ // If we found a declaration, correct when it refers to an Objective-C
+ // class.
+ NamedDecl *ND = Result.getFoundDecl();
+ if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND)) {
+ Diag(NameLoc, diag::err_unknown_receiver_suggest)
+ << Name << Result.getLookupName()
+ << FixItHint::CreateReplacement(SourceRange(NameLoc),
+ ND->getNameAsString());
+ Diag(ND->getLocation(), diag::note_previous_decl)
+ << Corrected;
+
+ QualType T = Context.getObjCInterfaceType(Class);
+ TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
+ ReceiverType = CreateLocInfoType(T, TSInfo).getAsOpaquePtr();
+ return ObjCClassMessage;
}
- // We are sending a message to 'super' within a class method. Do nothing,
- // the receiver will pass through as 'super' (how convenient:-).
- } else {
- // 'super' has been used outside a method context. If a variable named
- // 'super' has been declared, redirect. If not, produce a diagnostic.
- NamedDecl *SuperDecl
- = LookupSingleName(S, receiverName, LookupOrdinaryName);
- ValueDecl *VD = dyn_cast_or_null<ValueDecl>(SuperDecl);
- if (VD) {
- ExprResult ReceiverExpr = new (Context) DeclRefExpr(VD, VD->getType(),
- receiverLoc);
- // We are really in an instance method, redirect.
- return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
- selectorLoc, rbrac, Args, NumArgs);
- }
- else if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(SuperDecl)) {
- const ObjCInterfaceType *OCIT;
- OCIT = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>();
- if (!OCIT) {
- Diag(receiverLoc, diag::err_invalid_receiver_to_message);
- return true;
- }
- ClassDecl = OCIT->getDecl();
- }
- else
- return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName;
- }
- } else
- ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc);
-
- // The following code allows for the following GCC-ism:
- //
- // typedef XCElementDisplayRect XCElementGraphicsRect;
- //
- // @implementation XCRASlice
- // - whatever { // Note that XCElementGraphicsRect is a typedef name.
- // _sGraphicsDelegate =[[XCElementGraphicsRect alloc] init];
- // }
- //
- // If necessary, the following lookup could move to getObjCInterfaceDecl().
- if (!ClassDecl) {
- NamedDecl *IDecl
- = LookupSingleName(TUScope, receiverName, LookupOrdinaryName);
- if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl))
- if (const ObjCInterfaceType *OCIT
- = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>())
- ClassDecl = OCIT->getDecl();
-
- if (!ClassDecl) {
- Diag(receiverLoc, diag::err_invalid_receiver_to_message);
- return true;
+ } else if (Result.empty() && Corrected.getAsIdentifierInfo() &&
+ Corrected.getAsIdentifierInfo()->isStr("super")) {
+ // If we've found the keyword "super", this is a send to super.
+ Diag(NameLoc, diag::err_unknown_receiver_suggest)
+ << Name << Corrected
+ << FixItHint::CreateReplacement(SourceRange(NameLoc), "super");
+ Name = Corrected.getAsIdentifierInfo();
+ return ObjCSuperMessage;
}
}
- assert(ClassDecl && "missing interface declaration");
- ObjCMethodDecl *Method = 0;
- QualType returnType;
- if (ClassDecl->isForwardDecl()) {
- // A forward class used in messaging is tread as a 'Class'
- Diag(lbrac, diag::warn_receiver_forward_class) << ClassDecl->getDeclName();
- Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac));
- if (Method)
- Diag(Method->getLocation(), diag::note_method_sent_forward_class)
- << Method->getDeclName();
+
+ // Fall back: let the parser try to parse it as an instance message.
+ return ObjCInstanceMessage;
+}
+
+Sema::OwningExprResult Sema::ActOnSuperMessage(Scope *S,
+ SourceLocation SuperLoc,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args) {
+ // Determine whether we are inside a method or not.
+ ObjCMethodDecl *Method = getCurMethodDecl();
+ if (!Method) {
+ Diag(SuperLoc, diag::err_invalid_receiver_to_message_super);
+ return ExprError();
}
- if (!Method)
- Method = ClassDecl->lookupClassMethod(Sel);
- // If we have an implementation in scope, check "private" methods.
- if (!Method)
- Method = LookupPrivateClassMethod(Sel, ClassDecl);
+ ObjCInterfaceDecl *Class = Method->getClassInterface();
+ if (!Class) {
+ Diag(SuperLoc, diag::error_no_super_class_message)
+ << Method->getDeclName();
+ return ExprError();
+ }
- if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
- return true;
+ ObjCInterfaceDecl *Super = Class->getSuperClass();
+ if (!Super) {
+ // The current class does not have a superclass.
+ Diag(SuperLoc, diag::error_no_super_class) << Class->getIdentifier();
+ return ExprError();
+ }
- if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, true,
- lbrac, rbrac, returnType))
- return true;
+ // We are in a method whose class has a superclass, so 'super'
+ // is acting as a keyword.
+ if (Method->isInstanceMethod()) {
+ // Since we are in an instance method, this is an instance
+ // message to the superclass instance.
+ QualType SuperTy = Context.getObjCInterfaceType(Super);
+ SuperTy = Context.getObjCObjectPointerType(SuperTy);
+ return BuildInstanceMessage(ExprArg(*this), SuperTy, SuperLoc,
+ Sel, /*Method=*/0, LBracLoc, RBracLoc,
+ move(Args));
+ }
+
+ // Since we are in a class method, this is a class message to
+ // the superclass.
+ return BuildClassMessage(/*ReceiverTypeInfo=*/0,
+ Context.getObjCInterfaceType(Super),
+ SuperLoc, Sel, /*Method=*/0, LBracLoc, RBracLoc,
+ move(Args));
+}
+
+/// \brief Build an Objective-C class message expression.
+///
+/// This routine takes care of both normal class messages and
+/// class messages to the superclass.
+///
+/// \param ReceiverTypeInfo Type source information that describes the
+/// receiver of this message. This may be NULL, in which case we are
+/// sending to the superclass and \p SuperLoc must be a valid source
+/// location.
+
+/// \param ReceiverType The type of the object receiving the
+/// message. When \p ReceiverTypeInfo is non-NULL, this is the same
+/// type as that refers to. For a superclass send, this is the type of
+/// the superclass.
+///
+/// \param SuperLoc The location of the "super" keyword in a
+/// superclass message.
+///
+/// \param Sel The selector to which the message is being sent.
+///
+/// \param Method The method that this class message is invoking, if
+/// already known.
+///
+/// \param LBracLoc The location of the opening square bracket ']'.
+///
+/// \param RBrac The location of the closing square bracket ']'.
+///
+/// \param Args The message arguments.
+Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
+ QualType ReceiverType,
+ SourceLocation SuperLoc,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ SourceLocation LBracLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg ArgsIn) {
+ if (ReceiverType->isDependentType()) {
+ // If the receiver type is dependent, we can't type-check anything
+ // at this point. Build a dependent expression.
+ unsigned NumArgs = ArgsIn.size();
+ Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
+ assert(SuperLoc.isInvalid() && "Message to super with dependent type");
+ return Owned(ObjCMessageExpr::Create(Context, ReceiverType, LBracLoc,
+ ReceiverTypeInfo, Sel, /*Method=*/0,
+ Args, NumArgs, RBracLoc));
+ }
+
+ SourceLocation Loc = SuperLoc.isValid()? SuperLoc
+ : ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin();
+
+ // Find the class to which we are sending this message.
+ ObjCInterfaceDecl *Class = 0;
+ if (const ObjCInterfaceType *ClassType
+ = ReceiverType->getAs<ObjCInterfaceType>())
+ Class = ClassType->getDecl();
+ else {
+ Diag(Loc, diag::err_invalid_receiver_class_message)
+ << ReceiverType;
+ return ExprError();
+ }
+ assert(Class && "We don't know which class we're messaging?");
+
+ // Find the method we are messaging.
+ if (!Method) {
+ if (Class->isForwardDecl()) {
+ // A forward class used in messaging is treated as a 'Class'
+ Diag(Loc, diag::warn_receiver_forward_class) << Class->getDeclName();
+ Method = LookupFactoryMethodInGlobalPool(Sel,
+ SourceRange(LBracLoc, RBracLoc));
+ if (Method)
+ Diag(Method->getLocation(), diag::note_method_sent_forward_class)
+ << Method->getDeclName();
+ }
+ if (!Method)
+ Method = Class->lookupClassMethod(Sel);
- returnType = returnType.getNonReferenceType();
-
- // If we have the ObjCInterfaceDecl* for the class that is receiving the
- // message, use that to construct the ObjCMessageExpr. Otherwise pass on the
- // IdentifierInfo* for the class.
- // FIXME: need to do a better job handling 'super' usage within a class. For
- // now, we simply pass the "super" identifier through (which isn't consistent
- // with instance methods.
- if (isSuper)
- return new (Context) ObjCMessageExpr(Context, receiverName, receiverLoc,
- Sel, returnType, Method, lbrac, rbrac,
- ArgExprs, NumArgs);
- else
- return new (Context) ObjCMessageExpr(Context, ClassDecl, receiverLoc,
- Sel, returnType, Method, lbrac, rbrac,
- ArgExprs, NumArgs);
+ // If we have an implementation in scope, check "private" methods.
+ if (!Method)
+ Method = LookupPrivateClassMethod(Sel, Class);
+
+ if (Method && DiagnoseUseOfDecl(Method, Loc))
+ return ExprError();
+ }
+
+ // Check the argument types and determine the result type.
+ QualType ReturnType;
+ unsigned NumArgs = ArgsIn.size();
+ Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
+ if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, true,
+ LBracLoc, RBracLoc, ReturnType)) {
+ for (unsigned I = 0; I != NumArgs; ++I)
+ Args[I]->Destroy(Context);
+ return ExprError();
+ }
+
+ // Construct the appropriate ObjCMessageExpr.
+ if (SuperLoc.isValid())
+ return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
+ SuperLoc, /*IsInstanceSuper=*/false,
+ ReceiverType, Sel, Method, Args,
+ NumArgs, RBracLoc));
+
+ return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
+ ReceiverTypeInfo, Sel, Method, Args,
+ NumArgs, RBracLoc));
}
-// ActOnInstanceMessage - used for both unary and keyword messages.
+// ActOnClassMessage - used for both unary and keyword messages.
// ArgExprs is optional - if it is present, the number of expressions
// is obtained from Sel.getNumArgs().
-Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
- SourceLocation lbrac,
- SourceLocation receiverLoc,
- SourceLocation rbrac,
- ExprTy **Args, unsigned NumArgs) {
- assert(receiver && "missing receiver expression");
-
- Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
- Expr *RExpr = static_cast<Expr *>(receiver);
-
- // If necessary, apply function/array conversion to the receiver.
- // C99 6.7.5.3p[7,8].
- DefaultFunctionArrayLvalueConversion(RExpr);
-
- QualType returnType;
- QualType ReceiverCType =
- Context.getCanonicalType(RExpr->getType()).getUnqualifiedType();
-
- // Handle messages to 'super'.
- if (isa<ObjCSuperExpr>(RExpr)) {
- ObjCMethodDecl *Method = 0;
- if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
- // If we have an interface in scope, check 'super' methods.
- if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
- if (ObjCInterfaceDecl *SuperDecl = ClassDecl->getSuperClass()) {
- Method = SuperDecl->lookupInstanceMethod(Sel);
+Sema::OwningExprResult Sema::ActOnClassMessage(Scope *S,
+ TypeTy *Receiver,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args) {
+ TypeSourceInfo *ReceiverTypeInfo;
+ QualType ReceiverType = GetTypeFromParser(Receiver, &ReceiverTypeInfo);
+ if (ReceiverType.isNull())
+ return ExprError();
- if (!Method)
- // If we have implementations in scope, check "private" methods.
- Method = LookupPrivateInstanceMethod(Sel, SuperDecl);
- }
- }
- if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
- return true;
+ if (!ReceiverTypeInfo)
+ ReceiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType, LBracLoc);
- if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
- lbrac, rbrac, returnType))
- return true;
+ return BuildClassMessage(ReceiverTypeInfo, ReceiverType,
+ /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0,
+ LBracLoc, RBracLoc, move(Args));
+}
- returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType,
- Method, lbrac, rbrac,
- ArgExprs, NumArgs);
- }
+/// \brief Build an Objective-C instance message expression.
+///
+/// This routine takes care of both normal instance messages and
+/// instance messages to the superclass instance.
+///
+/// \param Receiver The expression that computes the object that will
+/// receive this message. This may be empty, in which case we are
+/// sending to the superclass instance and \p SuperLoc must be a valid
+/// source location.
+///
+/// \param ReceiverType The (static) type of the object receiving the
+/// message. When a \p Receiver expression is provided, this is the
+/// same type as that expression. For a superclass instance send, this
+/// is a pointer to the type of the superclass.
+///
+/// \param SuperLoc The location of the "super" keyword in a
+/// superclass instance message.
+///
+/// \param Sel The selector to which the message is being sent.
+///
+/// \param Method The method that this instance message is invoking, if
+/// already known.
+///
+/// \param LBracLoc The location of the opening square bracket ']'.
+///
+/// \param RBrac The location of the closing square bracket ']'.
+///
+/// \param Args The message arguments.
+Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE,
+ QualType ReceiverType,
+ SourceLocation SuperLoc,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ SourceLocation LBracLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg ArgsIn) {
+ // If we have a receiver expression, perform appropriate promotions
+ // and determine receiver type.
+ Expr *Receiver = ReceiverE.takeAs<Expr>();
+ if (Receiver) {
+ if (Receiver->isTypeDependent()) {
+ // If the receiver is type-dependent, we can't type-check anything
+ // at this point. Build a dependent expression.
+ unsigned NumArgs = ArgsIn.size();
+ Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
+ assert(SuperLoc.isInvalid() && "Message to super with dependent type");
+ return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy,
+ LBracLoc, Receiver, Sel,
+ /*Method=*/0, Args, NumArgs,
+ RBracLoc));
+ }
- // Handle messages to id.
- if (ReceiverCType->isObjCIdType() || ReceiverCType->isBlockPointerType() ||
- Context.isObjCNSObjectType(RExpr->getType())) {
- ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(
- Sel, SourceRange(lbrac,rbrac));
- if (!Method)
- Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac, rbrac));
- if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
- lbrac, rbrac, returnType))
- return true;
- returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType,
- Method, lbrac, rbrac,
- ArgExprs, NumArgs);
+ // If necessary, apply function/array conversion to the receiver.
+ // C99 6.7.5.3p[7,8].
+ DefaultFunctionArrayLvalueConversion(Receiver);
+ ReceiverType = Receiver->getType();
}
- // Handle messages to Class.
- if (ReceiverCType->isObjCClassType() ||
- ReceiverCType->isObjCQualifiedClassType()) {
- ObjCMethodDecl *Method = 0;
+ // The location of the receiver.
+ SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart();
- if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
- if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) {
- // First check the public methods in the class interface.
- Method = ClassDecl->lookupClassMethod(Sel);
+ if (!Method) {
+ // Handle messages to id.
+ if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType() ||
+ (Receiver && Context.isObjCNSObjectType(Receiver->getType()))) {
+ Method = LookupInstanceMethodInGlobalPool(Sel,
+ SourceRange(LBracLoc, RBracLoc));
+ if (!Method)
+ Method = LookupFactoryMethodInGlobalPool(Sel,
+ SourceRange(LBracLoc, RBracLoc));
+ } else if (ReceiverType->isObjCClassType() ||
+ ReceiverType->isObjCQualifiedClassType()) {
+ // Handle messages to Class.
+ if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
+ if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) {
+ // First check the public methods in the class interface.
+ Method = ClassDecl->lookupClassMethod(Sel);
- if (!Method)
- Method = LookupPrivateClassMethod(Sel, ClassDecl);
+ if (!Method)
+ Method = LookupPrivateClassMethod(Sel, ClassDecl);
- // FIXME: if we still haven't found a method, we need to look in
- // protocols (if we have qualifiers).
+ // FIXME: if we still haven't found a method, we need to look in
+ // protocols (if we have qualifiers).
+ }
+ if (Method && DiagnoseUseOfDecl(Method, Loc))
+ return ExprError();
}
- if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
- return true;
- }
- if (!Method) {
- // If not messaging 'self', look for any factory method named 'Sel'.
- if (!isSelfExpr(RExpr)) {
- Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac));
- if (!Method) {
- // If no class (factory) method was found, check if an _instance_
- // method of the same name exists in the root class only.
- Method = LookupInstanceMethodInGlobalPool(
- Sel, SourceRange(lbrac,rbrac));
- if (Method)
- if (const ObjCInterfaceDecl *ID =
- dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) {
- if (ID->getSuperClass())
- Diag(lbrac, diag::warn_root_inst_method_not_found)
- << Sel << SourceRange(lbrac, rbrac);
- }
+ if (!Method) {
+ // If not messaging 'self', look for any factory method named 'Sel'.
+ if (!Receiver || !isSelfExpr(Receiver)) {
+ Method = LookupFactoryMethodInGlobalPool(Sel,
+ SourceRange(LBracLoc, RBracLoc));
+ if (!Method) {
+ // If no class (factory) method was found, check if an _instance_
+ // method of the same name exists in the root class only.
+ Method = LookupInstanceMethodInGlobalPool(Sel,
+ SourceRange(LBracLoc, RBracLoc));
+ if (Method)
+ if (const ObjCInterfaceDecl *ID =
+ dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) {
+ if (ID->getSuperClass())
+ Diag(Loc, diag::warn_root_inst_method_not_found)
+ << Sel << SourceRange(LBracLoc, RBracLoc);
+ }
+ }
}
}
- }
- if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
- lbrac, rbrac, returnType))
- return true;
- returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType,
- Method, lbrac, rbrac,
- ArgExprs, NumArgs);
- }
+ } else {
+ ObjCInterfaceDecl* ClassDecl = 0;
+
+ // We allow sending a message to a qualified ID ("id<foo>"), which is ok as
+ // long as one of the protocols implements the selector (if not, warn).
+ if (const ObjCObjectPointerType *QIdTy
+ = ReceiverType->getAsObjCQualifiedIdType()) {
+ // Search protocols for instance methods.
+ for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
+ E = QIdTy->qual_end(); I != E; ++I) {
+ ObjCProtocolDecl *PDecl = *I;
+ if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel)))
+ break;
+ // Since we aren't supporting "Class<foo>", look for a class method.
+ if (PDecl && (Method = PDecl->lookupClassMethod(Sel)))
+ break;
+ }
+ } else if (const ObjCObjectPointerType *OCIType
+ = ReceiverType->getAsObjCInterfacePointerType()) {
+ // We allow sending a message to a pointer to an interface (an object).
+ ClassDecl = OCIType->getInterfaceDecl();
+ // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
+ // faster than the following method (which can do *many* linear searches).
+ // The idea is to add class info to InstanceMethodPool.
+ Method = ClassDecl->lookupInstanceMethod(Sel);
- ObjCMethodDecl *Method = 0;
- ObjCInterfaceDecl* ClassDecl = 0;
-
- // We allow sending a message to a qualified ID ("id<foo>"), which is ok as
- // long as one of the protocols implements the selector (if not, warn).
- if (const ObjCObjectPointerType *QIdTy =
- ReceiverCType->getAsObjCQualifiedIdType()) {
- // Search protocols for instance methods.
- for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
- E = QIdTy->qual_end(); I != E; ++I) {
- ObjCProtocolDecl *PDecl = *I;
- if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel)))
- break;
- // Since we aren't supporting "Class<foo>", look for a class method.
- if (PDecl && (Method = PDecl->lookupClassMethod(Sel)))
- break;
- }
- } else if (const ObjCObjectPointerType *OCIType =
- ReceiverCType->getAsObjCInterfacePointerType()) {
- // We allow sending a message to a pointer to an interface (an object).
-
- ClassDecl = OCIType->getInterfaceDecl();
- // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
- // faster than the following method (which can do *many* linear searches).
- // The idea is to add class info to InstanceMethodPool.
- Method = ClassDecl->lookupInstanceMethod(Sel);
-
- if (!Method) {
- // Search protocol qualifiers.
- for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(),
- E = OCIType->qual_end(); QI != E; ++QI) {
- if ((Method = (*QI)->lookupInstanceMethod(Sel)))
- break;
- }
- }
- if (!Method) {
- // If we have implementations in scope, check "private" methods.
- Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
-
- if (!Method && !isSelfExpr(RExpr)) {
- // If we still haven't found a method, look in the global pool. This
- // behavior isn't very desirable, however we need it for GCC
- // compatibility. FIXME: should we deviate??
- if (OCIType->qual_empty()) {
- Method = LookupInstanceMethodInGlobalPool(
- Sel, SourceRange(lbrac,rbrac));
- if (Method && !OCIType->getInterfaceDecl()->isForwardDecl())
- Diag(lbrac, diag::warn_maynot_respond)
- << OCIType->getInterfaceDecl()->getIdentifier()->getName() << Sel;
+ if (!Method) {
+ // Search protocol qualifiers.
+ for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(),
+ E = OCIType->qual_end(); QI != E; ++QI) {
+ if ((Method = (*QI)->lookupInstanceMethod(Sel)))
+ break;
+ }
}
+ if (!Method) {
+ // If we have implementations in scope, check "private" methods.
+ Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
+
+ if (!Method && (!Receiver || !isSelfExpr(Receiver))) {
+ // If we still haven't found a method, look in the global pool. This
+ // behavior isn't very desirable, however we need it for GCC
+ // compatibility. FIXME: should we deviate??
+ if (OCIType->qual_empty()) {
+ Method = LookupInstanceMethodInGlobalPool(Sel,
+ SourceRange(LBracLoc, RBracLoc));
+ if (Method && !OCIType->getInterfaceDecl()->isForwardDecl())
+ Diag(Loc, diag::warn_maynot_respond)
+ << OCIType->getInterfaceDecl()->getIdentifier() << Sel;
+ }
+ }
+ }
+ if (Method && DiagnoseUseOfDecl(Method, Loc))
+ return ExprError();
+ } else if (!Context.getObjCIdType().isNull() &&
+ (ReceiverType->isPointerType() ||
+ (ReceiverType->isIntegerType() &&
+ ReceiverType->isScalarType()))) {
+ // Implicitly convert integers and pointers to 'id' but emit a warning.
+ Diag(Loc, diag::warn_bad_receiver_type)
+ << ReceiverType
+ << Receiver->getSourceRange();
+ if (ReceiverType->isPointerType())
+ ImpCastExprToType(Receiver, Context.getObjCIdType(),
+ CastExpr::CK_BitCast);
+ else
+ ImpCastExprToType(Receiver, Context.getObjCIdType(),
+ CastExpr::CK_IntegralToPointer);
+ ReceiverType = Receiver->getType();
+ } else {
+ // Reject other random receiver types (e.g. structs).
+ Diag(Loc, diag::err_bad_receiver_type)
+ << ReceiverType << Receiver->getSourceRange();
+ return ExprError();
}
}
- if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
- return true;
- } else if (!Context.getObjCIdType().isNull() &&
- (ReceiverCType->isPointerType() ||
- (ReceiverCType->isIntegerType() &&
- ReceiverCType->isScalarType()))) {
- // Implicitly convert integers and pointers to 'id' but emit a warning.
- Diag(lbrac, diag::warn_bad_receiver_type)
- << RExpr->getType() << RExpr->getSourceRange();
- if (ReceiverCType->isPointerType())
- ImpCastExprToType(RExpr, Context.getObjCIdType(), CastExpr::CK_BitCast);
- else
- ImpCastExprToType(RExpr, Context.getObjCIdType(),
- CastExpr::CK_IntegralToPointer);
- } else {
- // Reject other random receiver types (e.g. structs).
- Diag(lbrac, diag::err_bad_receiver_type)
- << RExpr->getType() << RExpr->getSourceRange();
- return true;
}
- if (Method)
- DiagnoseSentinelCalls(Method, receiverLoc, ArgExprs, NumArgs);
- if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
- lbrac, rbrac, returnType))
- return true;
- returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, Method,
- lbrac, rbrac, ArgExprs, NumArgs);
+ // Check the message arguments.
+ unsigned NumArgs = ArgsIn.size();
+ Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
+ QualType ReturnType;
+ if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, false,
+ LBracLoc, RBracLoc, ReturnType))
+ return ExprError();
+
+ // Construct the appropriate ObjCMessageExpr instance.
+ if (SuperLoc.isValid())
+ return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
+ SuperLoc, /*IsInstanceSuper=*/true,
+ ReceiverType, Sel, Method,
+ Args, NumArgs, RBracLoc));
+
+ return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver,
+ Sel, Method, Args, NumArgs, RBracLoc));
+}
+
+// ActOnInstanceMessage - used for both unary and keyword messages.
+// ArgExprs is optional - if it is present, the number of expressions
+// is obtained from Sel.getNumArgs().
+Sema::OwningExprResult Sema::ActOnInstanceMessage(Scope *S,
+ ExprArg ReceiverE,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args) {
+ Expr *Receiver = static_cast<Expr *>(ReceiverE.get());
+ if (!Receiver)
+ return ExprError();
+
+ return BuildInstanceMessage(move(ReceiverE), Receiver->getType(),
+ /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0,
+ LBracLoc, RBracLoc, move(Args));
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 1d0575c..0aa3446 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -281,7 +281,7 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
// through the initializer list.
- ILE->updateInit(Init, MemberInit.takeAs<Expr>());
+ ILE->updateInit(SemaRef.Context, Init, MemberInit.takeAs<Expr>());
RequiresSecondPass = true;
}
} else if (InitListExpr *InnerILE
@@ -391,7 +391,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
// through the initializer list.
- ILE->updateInit(Init, ElementInit.takeAs<Expr>());
+ ILE->updateInit(SemaRef.Context, Init, ElementInit.takeAs<Expr>());
RequiresSecondPass = true;
}
} else if (InitListExpr *InnerILE
@@ -458,7 +458,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
if (T->isArrayType())
maxElements = numArrayElements(T);
- else if (T->isStructureType() || T->isUnionType())
+ else if (T->isRecordType())
maxElements = numStructUnionElements(T);
else if (T->isVectorType())
maxElements = T->getAs<VectorType>()->getNumElements();
@@ -624,10 +624,14 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
} else if (DeclType->isReferenceType()) {
CheckReferenceType(Entity, IList, DeclType, Index,
StructuredList, StructuredIndex);
+ } else if (DeclType->isObjCInterfaceType()) {
+ SemaRef.Diag(IList->getLocStart(), diag::err_init_objc_class)
+ << DeclType;
+ hadError = true;
} else {
- // In C, all types are either scalars or aggregates, but
- // additional handling is needed here for C++ (and possibly others?).
- assert(0 && "Unsupported initializer type");
+ SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type)
+ << DeclType;
+ hadError = true;
}
}
@@ -884,9 +888,9 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
}
}
- // OpenCL & AltiVec require all elements to be initialized.
+ // OpenCL requires all elements to be initialized.
if (numEltsInit != maxElements)
- if (SemaRef.getLangOptions().OpenCL || SemaRef.getLangOptions().AltiVec)
+ if (SemaRef.getLangOptions().OpenCL)
SemaRef.Diag(IList->getSourceRange().getBegin(),
diag::err_vector_incorrect_num_initializers)
<< (numEltsInit < maxElements) << maxElements << numEltsInit;
@@ -1354,7 +1358,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// was a typo for another field name.
LookupResult R(SemaRef, FieldName, D->getFieldLoc(),
Sema::LookupMemberName);
- if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl()) &&
+ if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl(), false,
+ Sema::CTC_NoKeywords) &&
(ReplacementField = R.getAsSingle<FieldDecl>()) &&
ReplacementField->getDeclContext()->getLookupContext()
->Equals(RT->getDecl())) {
@@ -1702,7 +1707,8 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
}
InitListExpr *Result
- = new (SemaRef.Context) InitListExpr(InitRange.getBegin(), 0, 0,
+ = new (SemaRef.Context) InitListExpr(SemaRef.Context,
+ InitRange.getBegin(), 0, 0,
InitRange.getEnd());
Result->setType(CurrentObjectType.getNonReferenceType());
@@ -1740,12 +1746,12 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
if (NumElements < NumInits)
NumElements = IList->getNumInits();
- Result->reserveInits(NumElements);
+ Result->reserveInits(SemaRef.Context, NumElements);
// Link this new initializer list into the structured initializer
// lists.
if (StructuredList)
- StructuredList->updateInit(StructuredIndex, Result);
+ StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result);
else {
Result->setSyntacticForm(IList);
SyntacticToSemantic[IList] = Result;
@@ -1763,7 +1769,8 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
if (!StructuredList)
return;
- if (Expr *PrevInit = StructuredList->updateInit(StructuredIndex, expr)) {
+ if (Expr *PrevInit = StructuredList->updateInit(SemaRef.Context,
+ StructuredIndex, expr)) {
// This initializer overwrites a previous initializer. Warn.
SemaRef.Diag(expr->getSourceRange().getBegin(),
diag::warn_initializer_overrides)
@@ -1918,11 +1925,15 @@ InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index,
}
InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context,
- CXXBaseSpecifier *Base)
+ CXXBaseSpecifier *Base,
+ bool IsInheritedVirtualBase)
{
InitializedEntity Result;
Result.Kind = EK_Base;
- Result.Base = Base;
+ Result.Base = reinterpret_cast<uintptr_t>(Base);
+ if (IsInheritedVirtualBase)
+ Result.Base |= 0x01;
+
Result.Type = Base->getType();
return Result;
}
@@ -1984,6 +1995,7 @@ void InitializationSequence::Step::Destroy() {
case SK_CastDerivedToBaseLValue:
case SK_BindReference:
case SK_BindReferenceToTemporary:
+ case SK_ExtraneousCopyToTemporary:
case SK_UserConversion:
case SK_QualificationConversionRValue:
case SK_QualificationConversionLValue:
@@ -2033,6 +2045,10 @@ bool InitializationSequence::isAmbiguous() const {
return false;
}
+bool InitializationSequence::isConstructorInitialization() const {
+ return !Steps.empty() && Steps.back().Kind == SK_ConstructorInitialization;
+}
+
void InitializationSequence::AddAddressOverloadResolutionStep(
FunctionDecl *Function,
DeclAccessPair Found) {
@@ -2060,6 +2076,13 @@ void InitializationSequence::AddReferenceBindingStep(QualType T,
Steps.push_back(S);
}
+void InitializationSequence::AddExtraneousCopyToTemporary(QualType T) {
+ Step S;
+ S.Kind = SK_ExtraneousCopyToTemporary;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
void InitializationSequence::AddUserConversionStep(FunctionDecl *Function,
DeclAccessPair FoundDecl,
QualType T) {
@@ -2388,15 +2411,11 @@ static void TryReferenceInitialization(Sema &S,
T2 = cv2T2.getUnqualifiedType();
}
- // FIXME: Rvalue references
- bool ForceRValue = false;
-
// Compute some basic properties of the types and the initializer.
bool isLValueRef = DestType->isLValueReferenceType();
bool isRValueRef = !isLValueRef;
bool DerivedToBase = false;
- Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression :
- Initializer->isLvalue(S.Context);
+ Expr::isLvalueResult InitLvalue = Initializer->isLvalue(S.Context);
Sema::ReferenceCompareResult RefRelationship
= S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase);
@@ -2480,6 +2499,18 @@ static void TryReferenceInitialization(Sema &S,
// reference-compatible with "cv2 T2", or
if (InitLvalue != Expr::LV_Valid &&
RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
+ // The corresponding bullet in C++03 [dcl.init.ref]p5 gives the
+ // compiler the freedom to perform a copy here or bind to the
+ // object, while C++0x requires that we bind directly to the
+ // object. Hence, we always bind to the object without making an
+ // extra copy. However, in C++03 requires that we check for the
+ // presence of a suitable copy constructor:
+ //
+ // The constructor that would be used to make the copy shall
+ // be callable whether or not the copy is actually done.
+ if (!S.getLangOptions().CPlusPlus0x)
+ Sequence.AddExtraneousCopyToTemporary(cv2T2);
+
if (DerivedToBase)
Sequence.AddDerivedToBaseCastStep(
S.Context.getQualifiedType(T1, T2Quals),
@@ -2528,9 +2559,7 @@ static void TryReferenceInitialization(Sema &S,
ImplicitConversionSequence ICS
= S.TryImplicitConversion(Initializer, cv1T1,
/*SuppressUserConversions=*/false, AllowExplicit,
- /*ForceRValue=*/false,
- /*FIXME:InOverloadResolution=*/false,
- /*UserCast=*/Kind.isExplicitCast());
+ /*FIXME:InOverloadResolution=*/false);
if (ICS.isBad()) {
// FIXME: Use the conversion function set stored in ICS to turn
@@ -2595,6 +2624,12 @@ static void TryConstructorInitialization(Sema &S,
bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct ||
Kind.getKind() == InitializationKind::IK_Value ||
Kind.getKind() == InitializationKind::IK_Default);
+
+ // The type we're constructing needs to be complete.
+ if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
+ Sequence.SetFailed(InitializationSequence::FK_ConversionFailed);
+ return;
+ }
// The type we're converting to is a class type. Enumerate its constructors
// to see if one is suitable.
@@ -2611,25 +2646,36 @@ static void TryConstructorInitialization(Sema &S,
Con != ConEnd; ++Con) {
NamedDecl *D = *Con;
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
-
+ bool SuppressUserConversions = false;
+
// Find the constructor (which may be a template).
CXXConstructorDecl *Constructor = 0;
FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D);
if (ConstructorTmpl)
Constructor = cast<CXXConstructorDecl>(
ConstructorTmpl->getTemplatedDecl());
- else
+ else {
Constructor = cast<CXXConstructorDecl>(D);
+
+ // If we're performing copy initialization using a copy constructor, we
+ // suppress user-defined conversions on the arguments.
+ // FIXME: Move constructors?
+ if (Kind.getKind() == InitializationKind::IK_Copy &&
+ Constructor->isCopyConstructor())
+ SuppressUserConversions = true;
+ }
if (!Constructor->isInvalidDecl() &&
(AllowExplicit || !Constructor->isExplicit())) {
if (ConstructorTmpl)
S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
- Args, NumArgs, CandidateSet);
+ Args, NumArgs, CandidateSet,
+ SuppressUserConversions);
else
S.AddOverloadCandidate(Constructor, FoundDecl,
- Args, NumArgs, CandidateSet);
+ Args, NumArgs, CandidateSet,
+ SuppressUserConversions);
}
}
@@ -2770,36 +2816,51 @@ static void TryUserDefinedConversion(Sema &S,
CXXRecordDecl *DestRecordDecl
= cast<CXXRecordDecl>(DestRecordType->getDecl());
- DeclarationName ConstructorName
- = S.Context.DeclarationNames.getCXXConstructorName(
+ // Try to complete the type we're converting to.
+ if (!S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
+ DeclarationName ConstructorName
+ = S.Context.DeclarationNames.getCXXConstructorName(
S.Context.getCanonicalType(DestType).getUnqualifiedType());
- DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName);
- Con != ConEnd; ++Con) {
- NamedDecl *D = *Con;
- DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
-
- // Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = 0;
- FunctionTemplateDecl *ConstructorTmpl
- = dyn_cast<FunctionTemplateDecl>(D);
- if (ConstructorTmpl)
- Constructor = cast<CXXConstructorDecl>(
- ConstructorTmpl->getTemplatedDecl());
- else
- Constructor = cast<CXXConstructorDecl>(D);
-
- if (!Constructor->isInvalidDecl() &&
- Constructor->isConvertingConstructor(AllowExplicit)) {
+ DeclContext::lookup_iterator Con, ConEnd;
+ for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName);
+ Con != ConEnd; ++Con) {
+ NamedDecl *D = *Con;
+ DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
+ bool SuppressUserConversions = false;
+
+ // Find the constructor (which may be a template).
+ CXXConstructorDecl *Constructor = 0;
+ FunctionTemplateDecl *ConstructorTmpl
+ = dyn_cast<FunctionTemplateDecl>(D);
if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ 0,
- &Initializer, 1, CandidateSet);
- else
- S.AddOverloadCandidate(Constructor, FoundDecl,
- &Initializer, 1, CandidateSet);
- }
- }
+ Constructor = cast<CXXConstructorDecl>(
+ ConstructorTmpl->getTemplatedDecl());
+ else {
+ Constructor = cast<CXXConstructorDecl>(D);
+
+ // If we're performing copy initialization using a copy constructor,
+ // we suppress user-defined conversions on the arguments.
+ // FIXME: Move constructors?
+ if (Kind.getKind() == InitializationKind::IK_Copy &&
+ Constructor->isCopyConstructor())
+ SuppressUserConversions = true;
+
+ }
+
+ if (!Constructor->isInvalidDecl() &&
+ Constructor->isConvertingConstructor(AllowExplicit)) {
+ if (ConstructorTmpl)
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
+ /*ExplicitArgs*/ 0,
+ &Initializer, 1, CandidateSet,
+ SuppressUserConversions);
+ else
+ S.AddOverloadCandidate(Constructor, FoundDecl,
+ &Initializer, 1, CandidateSet,
+ SuppressUserConversions);
+ }
+ }
+ }
}
SourceLocation DeclLoc = Initializer->getLocStart();
@@ -2865,10 +2926,21 @@ static void TryUserDefinedConversion(Sema &S,
// Add the user-defined conversion step that calls the conversion function.
QualType ConvType = Function->getResultType().getNonReferenceType();
- Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType);
+ if (ConvType->getAs<RecordType>()) {
+ // If we're converting to a class type, there may be an copy if
+ // the resulting temporary object (possible to create an object of
+ // a base class type). That copy is not a separate conversion, so
+ // we just make a note of the actual destination type (possibly a
+ // base class of the type returned by the conversion function) and
+ // let the user-defined conversion step handle the conversion.
+ Sequence.AddUserConversionStep(Function, Best->FoundDecl, DestType);
+ return;
+ }
- // If the conversion following the call to the conversion function is
- // interesting, add it as a separate step.
+ Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType);
+
+ // If the conversion following the call to the conversion function
+ // is interesting, add it as a separate step.
if (Best->FinalConversion.First || Best->FinalConversion.Second ||
Best->FinalConversion.Third) {
ImplicitConversionSequence ICS;
@@ -2889,9 +2961,7 @@ static void TryImplicitConversion(Sema &S,
= S.TryImplicitConversion(Initializer, Entity.getType(),
/*SuppressUserConversions=*/true,
/*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*FIXME:InOverloadResolution=*/false,
- /*UserCast=*/Kind.isExplicitCast());
+ /*InOverloadResolution=*/false);
if (ICS.isBad()) {
Sequence.SetFailed(InitializationSequence::FK_ConversionFailed);
@@ -3054,7 +3124,10 @@ getAssignmentAction(const InitializedEntity &Entity) {
return Sema::AA_Initializing;
case InitializedEntity::EK_Parameter:
- // FIXME: Can we tell when we're sending vs. passing?
+ if (Entity.getDecl() &&
+ isa<ObjCMethodDecl>(Entity.getDecl()->getDeclContext()))
+ return Sema::AA_Sending;
+
return Sema::AA_Passing;
case InitializedEntity::EK_Result:
@@ -3078,6 +3151,8 @@ getAssignmentAction(const InitializedEntity &Entity) {
return Sema::AA_Converting;
}
+/// \brief Whether we should binding a created object as a temporary when
+/// initializing the given entity.
static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
switch (Entity.getKind()) {
case InitializedEntity::EK_ArrayElement:
@@ -3098,14 +3173,57 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
llvm_unreachable("missed an InitializedEntity kind?");
}
+/// \brief Whether the given entity, when initialized with an object
+/// created for that initialization, requires destruction.
+static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
+ switch (Entity.getKind()) {
+ case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_Result:
+ case InitializedEntity::EK_New:
+ case InitializedEntity::EK_Base:
+ case InitializedEntity::EK_VectorElement:
+ return false;
+
+ case InitializedEntity::EK_Variable:
+ case InitializedEntity::EK_Parameter:
+ case InitializedEntity::EK_Temporary:
+ case InitializedEntity::EK_ArrayElement:
+ case InitializedEntity::EK_Exception:
+ return true;
+ }
+
+ llvm_unreachable("missed an InitializedEntity kind?");
+}
+
+/// \brief Make a (potentially elidable) temporary copy of the object
+/// provided by the given initializer by calling the appropriate copy
+/// constructor.
+///
+/// \param S The Sema object used for type-checking.
+///
+/// \param T The type of the temporary object, which must either by
+/// the type of the initializer expression or a superclass thereof.
+///
+/// \param Enter The entity being initialized.
+///
+/// \param CurInit The initializer expression.
+///
+/// \param IsExtraneousCopy Whether this is an "extraneous" copy that
+/// is permitted in C++03 (but not C++0x) when binding a reference to
+/// an rvalue.
+///
+/// \returns An expression that copies the initializer expression into
+/// a temporary object, or an error expression if a copy could not be
+/// created.
static Sema::OwningExprResult CopyObject(Sema &S,
+ QualType T,
const InitializedEntity &Entity,
- const InitializationKind &Kind,
- Sema::OwningExprResult CurInit) {
- // Determine which class type we're copying.
+ Sema::OwningExprResult CurInit,
+ bool IsExtraneousCopy) {
+ // Determine which class type we're copying to.
Expr *CurInitExpr = (Expr *)CurInit.get();
CXXRecordDecl *Class = 0;
- if (const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>())
+ if (const RecordType *Record = T->getAs<RecordType>())
Class = cast<CXXRecordDecl>(Record->getDecl());
if (!Class)
return move(CurInit);
@@ -3126,7 +3244,7 @@ static Sema::OwningExprResult CopyObject(Sema &S,
// not yet) handled as part of constructor initialization, while
// copy elision for exception handlers is handled by the run-time.
bool Elidable = CurInitExpr->isTemporaryObject() &&
- S.Context.hasSameUnqualifiedType(Entity.getType(), CurInitExpr->getType());
+ S.Context.hasSameUnqualifiedType(T, CurInitExpr->getType());
SourceLocation Loc;
switch (Entity.getKind()) {
case InitializedEntity::EK_Result:
@@ -3151,7 +3269,11 @@ static Sema::OwningExprResult CopyObject(Sema &S,
Loc = CurInitExpr->getLocStart();
break;
}
-
+
+ // Make sure that the type we are copying is complete.
+ if (S.RequireCompleteType(Loc, T, S.PDiag(diag::err_temp_copy_incomplete)))
+ return move(CurInit);
+
// Perform overload resolution using the class's copy constructors.
DeclarationName ConstructorName
= S.Context.DeclarationNames.getCXXConstructorName(
@@ -3163,7 +3285,8 @@ static Sema::OwningExprResult CopyObject(Sema &S,
// Only consider copy constructors.
CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(*Con);
if (!Constructor || Constructor->isInvalidDecl() ||
- !Constructor->isCopyConstructor())
+ !Constructor->isCopyConstructor() ||
+ !Constructor->isConvertingConstructor(/*AllowExplicit=*/false))
continue;
DeclAccessPair FoundDecl
@@ -3202,16 +3325,71 @@ static Sema::OwningExprResult CopyObject(Sema &S,
return S.ExprError();
}
- S.CheckConstructorAccess(Loc,
- cast<CXXConstructorDecl>(Best->Function),
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
+ CurInit.release(); // Ownership transferred into MultiExprArg, below.
+
+ S.CheckConstructorAccess(Loc, Constructor, Entity,
Best->FoundDecl.getAccess());
- CurInit.release();
- return S.BuildCXXConstructExpr(Loc, Entity.getType().getNonReferenceType(),
- cast<CXXConstructorDecl>(Best->Function),
- Elidable,
- Sema::MultiExprArg(S,
- (void**)&CurInitExpr, 1));
+ if (IsExtraneousCopy) {
+ // If this is a totally extraneous copy for C++03 reference
+ // binding purposes, just return the original initialization
+ // expression. We don't generate an (elided) copy operation here
+ // because doing so would require us to pass down a flag to avoid
+ // infinite recursion, where each step adds another extraneous,
+ // elidable copy.
+
+ // Instantiate the default arguments of any extra parameters in
+ // the selected copy constructor, as if we were going to create a
+ // proper call to the copy constructor.
+ for (unsigned I = 1, N = Constructor->getNumParams(); I != N; ++I) {
+ ParmVarDecl *Parm = Constructor->getParamDecl(I);
+ if (S.RequireCompleteType(Loc, Parm->getType(),
+ S.PDiag(diag::err_call_incomplete_argument)))
+ break;
+
+ // Build the default argument expression; we don't actually care
+ // if this succeeds or not, because this routine will complain
+ // if there was a problem.
+ S.BuildCXXDefaultArgExpr(Loc, Constructor, Parm);
+ }
+
+ return S.Owned(CurInitExpr);
+ }
+
+ // Determine the arguments required to actually perform the
+ // constructor call (we might have derived-to-base conversions, or
+ // the copy constructor may have default arguments).
+ if (S.CompleteConstructorCall(Constructor,
+ Sema::MultiExprArg(S,
+ (void **)&CurInitExpr,
+ 1),
+ Loc, ConstructorArgs))
+ return S.ExprError();
+
+ // Actually perform the constructor call.
+ CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable,
+ move_arg(ConstructorArgs));
+
+ // If we're supposed to bind temporaries, do so.
+ if (!CurInit.isInvalid() && shouldBindAsTemporary(Entity))
+ CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+ return move(CurInit);
+}
+
+void InitializationSequence::PrintInitLocationNote(Sema &S,
+ const InitializedEntity &Entity) {
+ if (Entity.getKind() == InitializedEntity::EK_Parameter && Entity.getDecl()) {
+ if (Entity.getDecl()->getLocation().isInvalid())
+ return;
+
+ if (Entity.getDecl()->getDeclName())
+ S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_named_here)
+ << Entity.getDecl()->getDeclName();
+ else
+ S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_here);
+ }
}
Action::OwningExprResult
@@ -3304,6 +3482,7 @@ InitializationSequence::Perform(Sema &S,
case SK_CastDerivedToBaseLValue:
case SK_BindReference:
case SK_BindReferenceToTemporary:
+ case SK_ExtraneousCopyToTemporary:
case SK_UserConversion:
case SK_QualificationConversionLValue:
case SK_QualificationConversionRValue:
@@ -3348,17 +3527,20 @@ InitializationSequence::Perform(Sema &S,
// We have a derived-to-base cast that produces either an rvalue or an
// lvalue. Perform that cast.
+ CXXBaseSpecifierArray BasePath;
+
// Casts to inaccessible base classes are allowed with C-style casts.
bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast();
if (S.CheckDerivedToBaseConversion(SourceType, Step->Type,
CurInitExpr->getLocStart(),
- CurInitExpr->getSourceRange(),
- IgnoreBaseAccess))
+ CurInitExpr->getSourceRange(),
+ &BasePath, IgnoreBaseAccess))
return S.ExprError();
CurInit = S.Owned(new (S.Context) ImplicitCastExpr(Step->Type,
CastExpr::CK_DerivedToBase,
- (Expr*)CurInit.release(),
+ (Expr*)CurInit.release(),
+ BasePath,
Step->Kind == SK_CastDerivedToBaseLValue));
break;
}
@@ -3379,6 +3561,7 @@ InitializationSequence::Perform(Sema &S,
S.Diag(Kind.getLocation(), diag::err_reference_bind_to_vector_element)
<< Entity.getType().isVolatileQualified()
<< CurInitExpr->getSourceRange();
+ PrintInitLocationNote(S, Entity);
return S.ExprError();
}
@@ -3399,6 +3582,11 @@ InitializationSequence::Perform(Sema &S,
break;
+ case SK_ExtraneousCopyToTemporary:
+ CurInit = CopyObject(S, Step->Type, Entity, move(CurInit),
+ /*IsExtraneousCopy=*/true);
+ break;
+
case SK_UserConversion: {
// We have a user-defined conversion that invokes either a constructor
// or a conversion function.
@@ -3406,6 +3594,7 @@ InitializationSequence::Perform(Sema &S,
bool IsCopy = false;
FunctionDecl *Fn = Step->Function.Function;
DeclAccessPair FoundFn = Step->Function.FoundDecl;
+ bool CreatedObject = false;
bool IsLvalue = false;
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) {
// Build a call to the selected constructor.
@@ -3428,7 +3617,7 @@ InitializationSequence::Perform(Sema &S,
if (CurInit.isInvalid())
return S.ExprError();
- S.CheckConstructorAccess(Kind.getLocation(), Constructor,
+ S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity,
FoundFn.getAccess());
CastKind = CastExpr::CK_ConstructorConversion;
@@ -3436,6 +3625,8 @@ InitializationSequence::Perform(Sema &S,
if (S.Context.hasSameUnqualifiedType(SourceType, Class) ||
S.IsDerivedFrom(SourceType, Class))
IsCopy = true;
+
+ CreatedObject = true;
} else {
// Build a call to the conversion function.
CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn);
@@ -3461,21 +3652,37 @@ InitializationSequence::Perform(Sema &S,
return S.ExprError();
CastKind = CastExpr::CK_UserDefinedConversion;
+
+ CreatedObject = Conversion->getResultType()->isRecordType();
}
bool RequiresCopy = !IsCopy &&
getKind() != InitializationSequence::ReferenceBinding;
if (RequiresCopy || shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
-
+ else if (CreatedObject && shouldDestroyTemporary(Entity)) {
+ CurInitExpr = static_cast<Expr *>(CurInit.get());
+ QualType T = CurInitExpr->getType();
+ if (const RecordType *Record = T->getAs<RecordType>()) {
+ CXXDestructorDecl *Destructor
+ = cast<CXXRecordDecl>(Record->getDecl())->getDestructor(S.Context);
+ S.CheckDestructorAccess(CurInitExpr->getLocStart(), Destructor,
+ S.PDiag(diag::err_access_dtor_temp) << T);
+ S.MarkDeclarationReferenced(CurInitExpr->getLocStart(), Destructor);
+ }
+ }
+
CurInitExpr = CurInit.takeAs<Expr>();
CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(),
CastKind,
CurInitExpr,
+ CXXBaseSpecifierArray(),
IsLvalue));
if (RequiresCopy)
- CurInit = CopyObject(S, Entity, Kind, move(CurInit));
+ CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity,
+ move(CurInit), /*IsExtraneousCopy=*/false);
+
break;
}
@@ -3483,21 +3690,24 @@ InitializationSequence::Perform(Sema &S,
case SK_QualificationConversionRValue:
// Perform a qualification conversion; these can never go wrong.
S.ImpCastExprToType(CurInitExpr, Step->Type,
- CastExpr::CK_NoOp,
+ CastExpr::CK_NoOp,
Step->Kind == SK_QualificationConversionLValue);
CurInit.release();
CurInit = S.Owned(CurInitExpr);
break;
- case SK_ConversionSequence:
- if (S.PerformImplicitConversion(CurInitExpr, Step->Type, Sema::AA_Converting,
- false, false, *Step->ICS))
+ case SK_ConversionSequence: {
+ bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast();
+
+ if (S.PerformImplicitConversion(CurInitExpr, Step->Type, *Step->ICS,
+ Sema::AA_Converting, IgnoreBaseAccess))
return S.ExprError();
CurInit.release();
- CurInit = S.Owned(CurInitExpr);
+ CurInit = S.Owned(CurInitExpr);
break;
-
+ }
+
case SK_ListInitialization: {
InitListExpr *InitList = cast<InitListExpr>(CurInitExpr);
QualType Ty = Step->Type;
@@ -3510,6 +3720,7 @@ InitializationSequence::Perform(Sema &S,
}
case SK_ConstructorInitialization: {
+ unsigned NumArgs = Args.size();
CXXConstructorDecl *Constructor
= cast<CXXConstructorDecl>(Step->Function.Function);
@@ -3523,8 +3734,9 @@ InitializationSequence::Perform(Sema &S,
Loc, ConstructorArgs))
return S.ExprError();
- // Build the an expression that constructs a temporary.
+ // Build the expression that constructs a temporary.
if (Entity.getKind() == InitializedEntity::EK_Temporary &&
+ NumArgs != 1 && // FIXME: Hack to work around cast weirdness
(Kind.getKind() == InitializationKind::IK_Direct ||
Kind.getKind() == InitializationKind::IK_Value)) {
// An explicitly-constructed temporary, e.g., X(1, 2).
@@ -3537,23 +3749,33 @@ InitializationSequence::Perform(Sema &S,
Kind.getLocation(),
Exprs,
NumExprs,
- Kind.getParenRange().getEnd()));
- } else
+ Kind.getParenRange().getEnd(),
+ ConstructorInitRequiresZeroInit));
+ } else {
+ CXXConstructExpr::ConstructionKind ConstructKind =
+ CXXConstructExpr::CK_Complete;
+
+ if (Entity.getKind() == InitializedEntity::EK_Base) {
+ ConstructKind = Entity.getBaseSpecifier()->isVirtual() ?
+ CXXConstructExpr::CK_VirtualBase :
+ CXXConstructExpr::CK_NonVirtualBase;
+ }
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
Constructor,
move_arg(ConstructorArgs),
ConstructorInitRequiresZeroInit,
- Entity.getKind() == InitializedEntity::EK_Base);
+ ConstructKind);
+ }
if (CurInit.isInvalid())
return S.ExprError();
// Only check access if all of that succeeded.
- S.CheckConstructorAccess(Loc, Constructor,
+ S.CheckConstructorAccess(Loc, Constructor, Entity,
Step->Function.FoundDecl.getAccess());
if (shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
-
+
break;
}
@@ -3589,10 +3811,16 @@ InitializationSequence::Perform(Sema &S,
== Sema::Compatible)
ConvTy = Sema::Compatible;
+ bool Complained;
if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(),
Step->Type, SourceType,
- CurInitExpr, getAssignmentAction(Entity)))
+ CurInitExpr,
+ getAssignmentAction(Entity),
+ &Complained)) {
+ PrintInitLocationNote(S, Entity);
return S.ExprError();
+ } else if (Complained)
+ PrintInitLocationNote(S, Entity);
CurInit.release();
CurInit = S.Owned(CurInitExpr);
@@ -3866,6 +4094,7 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
}
+ PrintInitLocationNote(S, Entity);
return true;
}
@@ -4013,9 +4242,12 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
OS << "bind reference to a temporary";
break;
+ case SK_ExtraneousCopyToTemporary:
+ OS << "extraneous C++03 copy to temporary";
+ break;
+
case SK_UserConversion:
- OS << "user-defined conversion via "
- << S->Function.Function->getNameAsString();
+ OS << "user-defined conversion via " << S->Function.Function;
break;
case SK_QualificationConversionRValue:
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index 7c6327f..5f2592f 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -92,11 +92,12 @@ private:
unsigned Location;
/// \brief When Kind == EK_Base, the base specifier that provides the
- /// base class.
- CXXBaseSpecifier *Base;
+ /// base class. The lower bit specifies whether the base is an inherited
+ /// virtual base.
+ uintptr_t Base;
- /// \brief When Kind = EK_ArrayElement or EK_VectorElement, the
- /// index of the array or vector element being initialized.
+ /// \brief When Kind == EK_ArrayElement or EK_VectorElement, the
+ /// index of the array or vector element being initialized.
unsigned Index;
};
@@ -141,7 +142,12 @@ public:
/// \brief Create the initialization entity for a parameter that is
/// only known by its type.
static InitializedEntity InitializeParameter(QualType Type) {
- return InitializedEntity(EK_Parameter, SourceLocation(), Type);
+ InitializedEntity Entity;
+ Entity.Kind = EK_Parameter;
+ Entity.Type = Type;
+ Entity.Parent = 0;
+ Entity.VariableOrMember = 0;
+ return Entity;
}
/// \brief Create the initialization entity for the result of a function.
@@ -168,7 +174,8 @@ public:
/// \brief Create the initialization entity for a base class subobject.
static InitializedEntity InitializeBase(ASTContext &Context,
- CXXBaseSpecifier *Base);
+ CXXBaseSpecifier *Base,
+ bool IsInheritedVirtualBase);
/// \brief Create the initialization entity for a member subobject.
static InitializedEntity InitializeMember(FieldDecl *Member,
@@ -204,7 +211,13 @@ public:
/// \brief Retrieve the base specifier.
CXXBaseSpecifier *getBaseSpecifier() const {
assert(getKind() == EK_Base && "Not a base specifier");
- return Base;
+ return reinterpret_cast<CXXBaseSpecifier *>(Base & ~0x1);
+ }
+
+ /// \brief Return whether the base is an inherited virtual base.
+ bool isInheritedVirtualBase() const {
+ assert(getKind() == EK_Base && "Not a base specifier");
+ return Base & 0x1;
}
/// \brief Determine the location of the 'return' keyword when initializing
@@ -416,6 +429,10 @@ public:
SK_BindReference,
/// \brief Reference binding to a temporary.
SK_BindReferenceToTemporary,
+ /// \brief An optional copy of a temporary object to another
+ /// temporary object, which is permitted (but not required) by
+ /// C++98/03 but not C++0x.
+ SK_ExtraneousCopyToTemporary,
/// \brief Perform a user-defined conversion, either via a conversion
/// function or via a constructor.
SK_UserConversion,
@@ -525,7 +542,11 @@ private:
/// \brief The candidate set created when initialization failed.
OverloadCandidateSet FailedCandidateSet;
-
+
+ /// \brief Prints a follow-up note that highlights the location of
+ /// the initialized entity, if it's remote.
+ void PrintInitLocationNote(Sema &S, const InitializedEntity &Entity);
+
public:
/// \brief Try to perform initialization of the given entity, creating a
/// record of the steps required to perform the initialization.
@@ -606,6 +627,10 @@ public:
/// \brief Determine whether this initialization failed due to an ambiguity.
bool isAmbiguous() const;
+ /// \brief Determine whether this initialization is direct call to a
+ /// constructor.
+ bool isConstructorInitialization() const;
+
/// \brief Add a new step in the initialization that resolves the address
/// of an overloaded function to a specific function declaration.
///
@@ -625,11 +650,26 @@ public:
/// \brief Add a new step binding a reference to an object.
///
- /// \param BindingTemporary true if we are binding a reference to a temporary
+ /// \param BindingTemporary True if we are binding a reference to a temporary
/// object (thereby extending its lifetime); false if we are binding to an
/// lvalue or an lvalue treated as an rvalue.
+ ///
+ /// \param UnnecessaryCopy True if we should check for a copy
+ /// constructor for a completely unnecessary but
void AddReferenceBindingStep(QualType T, bool BindingTemporary);
-
+
+ /// \brief Add a new step that makes an extraneous copy of the input
+ /// to a temporary of the same class type.
+ ///
+ /// This extraneous copy only occurs during reference binding in
+ /// C++98/03, where we are permitted (but not required) to introduce
+ /// an extra copy. At a bare minimum, we must check that we could
+ /// call the copy constructor, and produce a diagnostic if the copy
+ /// constructor is inaccessible or no copy constructor matches.
+ //
+ /// \param T The type of the temporary being created.
+ void AddExtraneousCopyToTemporary(QualType T);
+
/// \brief Add a new step invoking a conversion function, which is either
/// a constructor or a conversion function.
void AddUserConversionStep(FunctionDecl *Function,
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index a29c4d4..337a4a3 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -193,62 +193,6 @@ namespace {
};
}
-static bool IsAcceptableIDNS(NamedDecl *D, unsigned IDNS) {
- return D->isInIdentifierNamespace(IDNS);
-}
-
-static bool IsAcceptableOperatorName(NamedDecl *D, unsigned IDNS) {
- return D->isInIdentifierNamespace(IDNS) &&
- !D->getDeclContext()->isRecord();
-}
-
-static bool IsAcceptableNestedNameSpecifierName(NamedDecl *D, unsigned IDNS) {
- // This lookup ignores everything that isn't a type.
-
- // This is a fast check for the far most common case.
- if (D->isInIdentifierNamespace(Decl::IDNS_Tag))
- return true;
-
- if (isa<UsingShadowDecl>(D))
- D = cast<UsingShadowDecl>(D)->getTargetDecl();
-
- return isa<TypeDecl>(D);
-}
-
-static bool IsAcceptableNamespaceName(NamedDecl *D, unsigned IDNS) {
- // We don't need to look through using decls here because
- // using decls aren't allowed to name namespaces.
-
- return isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D);
-}
-
-/// Gets the default result filter for the given lookup.
-static inline
-LookupResult::ResultFilter getResultFilter(Sema::LookupNameKind NameKind) {
- switch (NameKind) {
- case Sema::LookupOrdinaryName:
- case Sema::LookupTagName:
- case Sema::LookupMemberName:
- case Sema::LookupRedeclarationWithLinkage: // FIXME: check linkage, scoping
- case Sema::LookupUsingDeclName:
- case Sema::LookupObjCProtocolName:
- case Sema::LookupObjCImplementationName:
- return &IsAcceptableIDNS;
-
- case Sema::LookupOperatorName:
- return &IsAcceptableOperatorName;
-
- case Sema::LookupNestedNameSpecifierName:
- return &IsAcceptableNestedNameSpecifierName;
-
- case Sema::LookupNamespaceName:
- return &IsAcceptableNamespaceName;
- }
-
- llvm_unreachable("unkknown lookup kind");
- return 0;
-}
-
// Retrieve the set of identifier namespaces that correspond to a
// specific kind of name lookup.
static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
@@ -257,19 +201,35 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
unsigned IDNS = 0;
switch (NameKind) {
case Sema::LookupOrdinaryName:
- case Sema::LookupOperatorName:
case Sema::LookupRedeclarationWithLinkage:
IDNS = Decl::IDNS_Ordinary;
if (CPlusPlus) {
- IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member;
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Namespace;
if (Redeclaration) IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend;
}
break;
+ case Sema::LookupOperatorName:
+ // Operator lookup is its own crazy thing; it is not the same
+ // as (e.g.) looking up an operator name for redeclaration.
+ assert(!Redeclaration && "cannot do redeclaration operator lookup");
+ IDNS = Decl::IDNS_NonMemberOperator;
+ break;
+
case Sema::LookupTagName:
- IDNS = Decl::IDNS_Tag;
- if (CPlusPlus && Redeclaration)
- IDNS |= Decl::IDNS_TagFriend;
+ if (CPlusPlus) {
+ IDNS = Decl::IDNS_Type;
+
+ // When looking for a redeclaration of a tag name, we add:
+ // 1) TagFriend to find undeclared friend decls
+ // 2) Namespace because they can't "overload" with tag decls.
+ // 3) Tag because it includes class templates, which can't
+ // "overload" with tag decls.
+ if (Redeclaration)
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_TagFriend | Decl::IDNS_Namespace;
+ } else {
+ IDNS = Decl::IDNS_Tag;
+ }
break;
case Sema::LookupMemberName:
@@ -279,8 +239,11 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
break;
case Sema::LookupNestedNameSpecifierName:
+ IDNS = Decl::IDNS_Type | Decl::IDNS_Namespace;
+ break;
+
case Sema::LookupNamespaceName:
- IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member;
+ IDNS = Decl::IDNS_Namespace;
break;
case Sema::LookupUsingDeclName:
@@ -291,10 +254,6 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
case Sema::LookupObjCProtocolName:
IDNS = Decl::IDNS_ObjCProtocol;
break;
-
- case Sema::LookupObjCImplementationName:
- IDNS = Decl::IDNS_ObjCImplementation;
- break;
}
return IDNS;
}
@@ -303,7 +262,6 @@ void LookupResult::configure() {
IDNS = getIDNS(LookupKind,
SemaRef.getLangOptions().CPlusPlus,
isForRedeclaration());
- IsAcceptableFn = getResultFilter(LookupKind);
// If we're looking for one of the allocation or deallocation
// operators, make sure that the implicitly-declared new and delete
@@ -341,9 +299,10 @@ void LookupResult::resolveKind() {
// If there's a single decl, we need to examine it to decide what
// kind of lookup this is.
if (N == 1) {
- if (isa<FunctionTemplateDecl>(*Decls.begin()))
+ NamedDecl *D = (*Decls.begin())->getUnderlyingDecl();
+ if (isa<FunctionTemplateDecl>(D))
ResultKind = FoundOverloaded;
- else if (isa<UnresolvedUsingValueDecl>(*Decls.begin()))
+ else if (isa<UnresolvedUsingValueDecl>(D))
ResultKind = FoundUnresolvedValue;
return;
}
@@ -1169,7 +1128,6 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
case LookupOperatorName:
case LookupNamespaceName:
case LookupObjCProtocolName:
- case LookupObjCImplementationName:
// These lookups will never find a member in a C++ class (or base class).
return false;
@@ -1291,7 +1249,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
/// context of the scope-specifier SS (if present).
///
/// @returns True if any decls were found (but possibly ambiguous)
-bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
+bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
bool AllowBuiltinCreation, bool EnteringContext) {
if (SS && SS->isInvalid()) {
// When the scope specifier is invalid, don't even look for
@@ -1303,7 +1261,7 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) {
// We have resolved the scope specifier to a particular declaration
// contex, and will perform name lookup in that context.
- if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS))
+ if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS, DC))
return false;
R.setContextRange(SS->getRange());
@@ -1428,10 +1386,18 @@ addAssociatedClassesAndNamespaces(QualType T,
Sema::AssociatedNamespaceSet &AssociatedNamespaces,
Sema::AssociatedClassSet &AssociatedClasses);
-static void CollectNamespace(Sema::AssociatedNamespaceSet &Namespaces,
- DeclContext *Ctx) {
+static void CollectEnclosingNamespace(Sema::AssociatedNamespaceSet &Namespaces,
+ DeclContext *Ctx) {
+ // Add the associated namespace for this class.
+
+ // We don't use DeclContext::getEnclosingNamespaceContext() as this may
+ // be a locally scoped record.
+
+ while (Ctx->isRecord() || Ctx->isTransparentContext())
+ Ctx = Ctx->getParent();
+
if (Ctx->isFileContext())
- Namespaces.insert(Ctx);
+ Namespaces.insert(Ctx->getPrimaryContext());
}
// \brief Add the associated classes and namespaces for argument-dependent
@@ -1467,9 +1433,7 @@ addAssociatedClassesAndNamespaces(const TemplateArgument &Arg,
if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
AssociatedClasses.insert(EnclosingClass);
// Add the associated namespace for this class.
- while (Ctx->isRecord())
- Ctx = Ctx->getParent();
- CollectNamespace(AssociatedNamespaces, Ctx);
+ CollectEnclosingNamespace(AssociatedNamespaces, Ctx);
}
break;
}
@@ -1513,9 +1477,7 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
AssociatedClasses.insert(EnclosingClass);
// Add the associated namespace for this class.
- while (Ctx->isRecord())
- Ctx = Ctx->getParent();
- CollectNamespace(AssociatedNamespaces, Ctx);
+ CollectEnclosingNamespace(AssociatedNamespaces, Ctx);
// Add the class itself. If we've already seen this class, we don't
// need to visit base classes.
@@ -1537,9 +1499,7 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
AssociatedClasses.insert(EnclosingClass);
// Add the associated namespace for this class.
- while (Ctx->isRecord())
- Ctx = Ctx->getParent();
- CollectNamespace(AssociatedNamespaces, Ctx);
+ CollectEnclosingNamespace(AssociatedNamespaces, Ctx);
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
@@ -1580,9 +1540,7 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
if (AssociatedClasses.insert(BaseDecl)) {
// Find the associated namespace for this base class.
DeclContext *BaseCtx = BaseDecl->getDeclContext();
- while (BaseCtx->isRecord())
- BaseCtx = BaseCtx->getParent();
- CollectNamespace(AssociatedNamespaces, BaseCtx);
+ CollectEnclosingNamespace(AssociatedNamespaces, BaseCtx);
// Make sure we visit the bases of this base class.
if (BaseDecl->bases_begin() != BaseDecl->bases_end())
@@ -1657,9 +1615,7 @@ addAssociatedClassesAndNamespaces(QualType T,
AssociatedClasses.insert(EnclosingClass);
// Add the associated namespace for this class.
- while (Ctx->isRecord())
- Ctx = Ctx->getParent();
- CollectNamespace(AssociatedNamespaces, Ctx);
+ CollectEnclosingNamespace(AssociatedNamespaces, Ctx);
return;
}
@@ -1825,16 +1781,19 @@ IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
}
NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name,
+ SourceLocation Loc,
LookupNameKind NameKind,
RedeclarationKind Redecl) {
- LookupResult R(*this, Name, SourceLocation(), NameKind, Redecl);
+ LookupResult R(*this, Name, Loc, NameKind, Redecl);
LookupName(R, S);
return R.getAsSingle<NamedDecl>();
}
/// \brief Find the protocol with the given name, if any.
-ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) {
- Decl *D = LookupSingleName(TUScope, II, LookupObjCProtocolName);
+ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II,
+ SourceLocation IdLoc) {
+ Decl *D = LookupSingleName(TUScope, II, IdLoc,
+ LookupObjCProtocolName);
return cast_or_null<ObjCProtocolDecl>(D);
}
@@ -1864,16 +1823,17 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
for (LookupResult::iterator Op = Operators.begin(), OpEnd = Operators.end();
Op != OpEnd; ++Op) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Op)) {
+ NamedDecl *Found = (*Op)->getUnderlyingDecl();
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Found)) {
if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
- Functions.addDecl(FD, Op.getAccess()); // FIXME: canonical FD
+ Functions.addDecl(*Op, Op.getAccess()); // FIXME: canonical FD
} else if (FunctionTemplateDecl *FunTmpl
- = dyn_cast<FunctionTemplateDecl>(*Op)) {
+ = dyn_cast<FunctionTemplateDecl>(Found)) {
// FIXME: friend operators?
// FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate,
// later?
if (!FunTmpl->getDeclContext()->isRecord())
- Functions.addDecl(FunTmpl, Op.getAccess());
+ Functions.addDecl(*Op, Op.getAccess());
}
}
}
@@ -2137,7 +2097,7 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
IEnd = Pos->second.end();
I != IEnd; ++I) {
// A tag declaration does not hide a non-tag declaration.
- if ((*I)->getIdentifierNamespace() == Decl::IDNS_Tag &&
+ if ((*I)->hasTagIdentifierNamespace() &&
(IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
Decl::IDNS_ObjCProtocol)))
continue;
@@ -2276,6 +2236,14 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup,
true, Consumer, Visited);
}
+
+ // If there is an implementation, traverse it. We do this to find
+ // synthesized ivars.
+ if (IFace->getImplementation()) {
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(IFace->getImplementation(), 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) {
@@ -2290,6 +2258,13 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
Visited);
}
+
+ // If there is an implementation, traverse it.
+ if (Category->getImplementation()) {
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(Category->getImplementation(), Result,
+ QualifiedNameLookup, true, Consumer, Visited);
+ }
}
}
@@ -2421,6 +2396,9 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer {
/// found (so far) with the typo name.
llvm::SmallVector<NamedDecl *, 4> BestResults;
+ /// \brief The keywords that have the smallest edit distance.
+ llvm::SmallVector<IdentifierInfo *, 4> BestKeywords;
+
/// \brief The best edit distance found so far.
unsigned BestEditDistance;
@@ -2429,13 +2407,23 @@ public:
: Typo(Typo->getName()) { }
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass);
+ void addKeywordResult(ASTContext &Context, llvm::StringRef Keyword);
typedef llvm::SmallVector<NamedDecl *, 4>::const_iterator iterator;
iterator begin() const { return BestResults.begin(); }
iterator end() const { return BestResults.end(); }
- bool empty() const { return BestResults.empty(); }
-
- unsigned getBestEditDistance() const { return BestEditDistance; }
+ void clear_decls() { BestResults.clear(); }
+
+ bool empty() const { return BestResults.empty() && BestKeywords.empty(); }
+
+ typedef llvm::SmallVector<IdentifierInfo *, 4>::const_iterator
+ keyword_iterator;
+ keyword_iterator keyword_begin() const { return BestKeywords.begin(); }
+ keyword_iterator keyword_end() const { return BestKeywords.end(); }
+ bool keyword_empty() const { return BestKeywords.empty(); }
+ unsigned keyword_size() const { return BestKeywords.size(); }
+
+ unsigned getBestEditDistance() const { return BestEditDistance; }
};
}
@@ -2457,11 +2445,12 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
// entity. If this edit distance is not worse than the best edit
// distance we've seen so far, add it to the list of results.
unsigned ED = Typo.edit_distance(Name->getName());
- if (!BestResults.empty()) {
+ if (!BestResults.empty() || !BestKeywords.empty()) {
if (ED < BestEditDistance) {
// This result is better than any we've seen before; clear out
// the previous results.
BestResults.clear();
+ BestKeywords.clear();
BestEditDistance = ED;
} else if (ED > BestEditDistance) {
// This result is worse than the best results we've seen so far;
@@ -2474,6 +2463,28 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
BestResults.push_back(ND);
}
+void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context,
+ llvm::StringRef Keyword) {
+ // Compute the edit distance between the typo and this keyword.
+ // If this edit distance is not worse than the best edit
+ // distance we've seen so far, add it to the list of results.
+ unsigned ED = Typo.edit_distance(Keyword);
+ if (!BestResults.empty() || !BestKeywords.empty()) {
+ if (ED < BestEditDistance) {
+ BestResults.clear();
+ BestKeywords.clear();
+ BestEditDistance = ED;
+ } else if (ED > BestEditDistance) {
+ // This result is worse than the best results we've seen so far;
+ // ignore it.
+ return;
+ }
+ } else
+ BestEditDistance = ED;
+
+ BestKeywords.push_back(&Context.Idents.get(Keyword));
+}
+
/// \brief Try to "correct" a typo in the source code by finding
/// visible declarations whose names are similar to the name that was
/// present in the source code.
@@ -2494,42 +2505,50 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
/// \param EnteringContext whether we're entering the context described by
/// the nested-name-specifier SS.
///
+/// \param CTC The context in which typo correction occurs, which impacts the
+/// set of keywords permitted.
+///
/// \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,
- const ObjCObjectPointerType *OPT) {
+/// \returns the corrected name if the typo was corrected, otherwise returns an
+/// empty \c DeclarationName. When a typo was corrected, the result structure
+/// may contain the results of name lookup for the correct name or it may be
+/// empty.
+DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
+ DeclContext *MemberContext,
+ bool EnteringContext,
+ CorrectTypoContext CTC,
+ const ObjCObjectPointerType *OPT) {
if (Diags.hasFatalErrorOccurred())
- return false;
+ return DeclarationName();
// Provide a stop gap for files that are just seriously broken. Trying
// to correct all typos can turn into a HUGE performance penalty, causing
// some files to take minutes to get rejected by the parser.
// FIXME: Is this the right solution?
if (TyposCorrected == 20)
- return false;
+ return DeclarationName();
++TyposCorrected;
// We only attempt to correct typos for identifiers.
IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo();
if (!Typo)
- return false;
+ return DeclarationName();
// If the scope specifier itself was invalid, don't try to correct
// typos.
if (SS && SS->isInvalid())
- return false;
+ return DeclarationName();
// Never try to correct typos during template deduction or
// instantiation.
if (!ActiveTemplateInstantiations.empty())
- return false;
-
+ return DeclarationName();
+
TypoCorrectionConsumer Consumer(Typo);
+
+ // Perform name lookup to find visible, similarly-named entities.
if (MemberContext) {
LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer);
@@ -2543,45 +2562,239 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
} else if (SS && SS->isSet()) {
DeclContext *DC = computeDeclContext(*SS, EnteringContext);
if (!DC)
- return false;
+ return DeclarationName();
LookupVisibleDecls(DC, Res.getLookupKind(), Consumer);
} else {
LookupVisibleDecls(S, Res.getLookupKind(), Consumer);
}
+ // Add context-dependent keywords.
+ bool WantTypeSpecifiers = false;
+ bool WantExpressionKeywords = false;
+ bool WantCXXNamedCasts = false;
+ bool WantRemainingKeywords = false;
+ switch (CTC) {
+ case CTC_Unknown:
+ WantTypeSpecifiers = true;
+ WantExpressionKeywords = true;
+ WantCXXNamedCasts = true;
+ WantRemainingKeywords = true;
+ break;
+
+ case CTC_NoKeywords:
+ break;
+
+ case CTC_Type:
+ WantTypeSpecifiers = true;
+ break;
+
+ case CTC_ObjCMessageReceiver:
+ Consumer.addKeywordResult(Context, "super");
+ // Fall through to handle message receivers like expressions.
+
+ case CTC_Expression:
+ if (getLangOptions().CPlusPlus)
+ WantTypeSpecifiers = true;
+ WantExpressionKeywords = true;
+ // Fall through to get C++ named casts.
+
+ case CTC_CXXCasts:
+ WantCXXNamedCasts = true;
+ break;
+
+ case CTC_MemberLookup:
+ if (getLangOptions().CPlusPlus)
+ Consumer.addKeywordResult(Context, "template");
+ break;
+ }
+
+ if (WantTypeSpecifiers) {
+ // Add type-specifier keywords to the set of results.
+ const char *CTypeSpecs[] = {
+ "char", "const", "double", "enum", "float", "int", "long", "short",
+ "signed", "struct", "union", "unsigned", "void", "volatile", "_Bool",
+ "_Complex", "_Imaginary",
+ // storage-specifiers as well
+ "extern", "inline", "static", "typedef"
+ };
+
+ const unsigned NumCTypeSpecs = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]);
+ for (unsigned I = 0; I != NumCTypeSpecs; ++I)
+ Consumer.addKeywordResult(Context, CTypeSpecs[I]);
+
+ if (getLangOptions().C99)
+ Consumer.addKeywordResult(Context, "restrict");
+ if (getLangOptions().Bool || getLangOptions().CPlusPlus)
+ Consumer.addKeywordResult(Context, "bool");
+
+ if (getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult(Context, "class");
+ Consumer.addKeywordResult(Context, "typename");
+ Consumer.addKeywordResult(Context, "wchar_t");
+
+ if (getLangOptions().CPlusPlus0x) {
+ Consumer.addKeywordResult(Context, "char16_t");
+ Consumer.addKeywordResult(Context, "char32_t");
+ Consumer.addKeywordResult(Context, "constexpr");
+ Consumer.addKeywordResult(Context, "decltype");
+ Consumer.addKeywordResult(Context, "thread_local");
+ }
+ }
+
+ if (getLangOptions().GNUMode)
+ Consumer.addKeywordResult(Context, "typeof");
+ }
+
+ if (WantCXXNamedCasts) {
+ Consumer.addKeywordResult(Context, "const_cast");
+ Consumer.addKeywordResult(Context, "dynamic_cast");
+ Consumer.addKeywordResult(Context, "reinterpret_cast");
+ Consumer.addKeywordResult(Context, "static_cast");
+ }
+
+ if (WantExpressionKeywords) {
+ Consumer.addKeywordResult(Context, "sizeof");
+ if (getLangOptions().Bool || getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult(Context, "false");
+ Consumer.addKeywordResult(Context, "true");
+ }
+
+ if (getLangOptions().CPlusPlus) {
+ const char *CXXExprs[] = {
+ "delete", "new", "operator", "throw", "typeid"
+ };
+ const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]);
+ for (unsigned I = 0; I != NumCXXExprs; ++I)
+ Consumer.addKeywordResult(Context, CXXExprs[I]);
+
+ if (isa<CXXMethodDecl>(CurContext) &&
+ cast<CXXMethodDecl>(CurContext)->isInstance())
+ Consumer.addKeywordResult(Context, "this");
+
+ if (getLangOptions().CPlusPlus0x) {
+ Consumer.addKeywordResult(Context, "alignof");
+ Consumer.addKeywordResult(Context, "nullptr");
+ }
+ }
+ }
+
+ if (WantRemainingKeywords) {
+ if (getCurFunctionOrMethodDecl() || getCurBlock()) {
+ // Statements.
+ const char *CStmts[] = {
+ "do", "else", "for", "goto", "if", "return", "switch", "while" };
+ const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]);
+ for (unsigned I = 0; I != NumCStmts; ++I)
+ Consumer.addKeywordResult(Context, CStmts[I]);
+
+ if (getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult(Context, "catch");
+ Consumer.addKeywordResult(Context, "try");
+ }
+
+ if (S && S->getBreakParent())
+ Consumer.addKeywordResult(Context, "break");
+
+ if (S && S->getContinueParent())
+ Consumer.addKeywordResult(Context, "continue");
+
+ if (!getSwitchStack().empty()) {
+ Consumer.addKeywordResult(Context, "case");
+ Consumer.addKeywordResult(Context, "default");
+ }
+ } else {
+ if (getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult(Context, "namespace");
+ Consumer.addKeywordResult(Context, "template");
+ }
+
+ if (S && S->isClassScope()) {
+ Consumer.addKeywordResult(Context, "explicit");
+ Consumer.addKeywordResult(Context, "friend");
+ Consumer.addKeywordResult(Context, "mutable");
+ Consumer.addKeywordResult(Context, "private");
+ Consumer.addKeywordResult(Context, "protected");
+ Consumer.addKeywordResult(Context, "public");
+ Consumer.addKeywordResult(Context, "virtual");
+ }
+ }
+
+ if (getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult(Context, "using");
+
+ if (getLangOptions().CPlusPlus0x)
+ Consumer.addKeywordResult(Context, "static_assert");
+ }
+ }
+
+ // If we haven't found anything, we're done.
if (Consumer.empty())
- return false;
+ return DeclarationName();
// Only allow a single, closest name in the result set (it's okay to
// have overloads of that name, though).
- TypoCorrectionConsumer::iterator I = Consumer.begin();
- DeclarationName BestName = (*I)->getDeclName();
-
- // 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;
+ DeclarationName BestName;
+ NamedDecl *BestIvarOrPropertyDecl = 0;
+ bool FoundIvarOrPropertyDecl = false;
+
+ // Check all of the declaration results to find the best name so far.
+ for (TypoCorrectionConsumer::iterator I = Consumer.begin(),
+ IEnd = Consumer.end();
+ I != IEnd; ++I) {
+ if (!BestName)
+ BestName = (*I)->getDeclName();
+ else if (BestName != (*I)->getDeclName())
+ return DeclarationName();
+
+ // \brief Keep track of either an Objective-C ivar or a property, but not
+ // both.
+ if (isa<ObjCIvarDecl>(*I) || isa<ObjCPropertyDecl>(*I)) {
+ if (FoundIvarOrPropertyDecl)
+ BestIvarOrPropertyDecl = 0;
+ else {
+ BestIvarOrPropertyDecl = *I;
+ FoundIvarOrPropertyDecl = true;
+ }
+ }
}
+ // Now check all of the keyword results to find the best name.
+ switch (Consumer.keyword_size()) {
+ case 0:
+ // No keywords matched.
+ break;
+
+ case 1:
+ // If we already have a name
+ if (!BestName) {
+ // We did not have anything previously,
+ BestName = *Consumer.keyword_begin();
+ } else if (BestName.getAsIdentifierInfo() == *Consumer.keyword_begin()) {
+ // We have a declaration with the same name as a context-sensitive
+ // keyword. The keyword takes precedence.
+ BestIvarOrPropertyDecl = 0;
+ FoundIvarOrPropertyDecl = false;
+ Consumer.clear_decls();
+ } else {
+ // Name collision; we will not correct typos.
+ return DeclarationName();
+ }
+ break;
+
+ default:
+ // Name collision; we will not correct typos.
+ return DeclarationName();
+ }
+
// BestName is the closest viable name to what the user
// typed. However, to make sure that we don't pick something that's
// way off, make sure that the user typed at least 3 characters for
// each correction.
unsigned ED = Consumer.getBestEditDistance();
- if (ED == 0 || (BestName.getAsIdentifierInfo()->getName().size() / ED) < 3)
- return false;
+ if (ED == 0 || !BestName.getAsIdentifierInfo() ||
+ (BestName.getAsIdentifierInfo()->getName().size() / ED) < 3)
+ return DeclarationName();
// Perform name lookup again with the name we chose, and declare
// success if we found something that was not ambiguous.
@@ -2590,11 +2803,14 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
// If we found an ivar or property, add that result; no further
// lookup is required.
- if (FoundBest)
- Res.addDecl(FoundBest);
+ if (BestIvarOrPropertyDecl)
+ Res.addDecl(BestIvarOrPropertyDecl);
// If we're looking into the context of a member, perform qualified
// name lookup on the best name.
- else if (MemberContext)
+ else if (!Consumer.keyword_empty()) {
+ // The best match was a keyword. Return it.
+ return BestName;
+ } else if (MemberContext)
LookupQualifiedName(Res, MemberContext);
// Perform lookup as if we had just parsed the best name.
else
@@ -2603,8 +2819,11 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
if (Res.isAmbiguous()) {
Res.suppressDiagnostics();
- return false;
+ return DeclarationName();
}
- return Res.getResultKind() != LookupResult::NotFound;
+ if (Res.getResultKind() != LookupResult::NotFound)
+ return BestName;
+
+ return DeclarationName();
}
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index cda1f0b..b73739f 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -204,7 +204,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
ObjCInterfaceDecl *IDecl = OIT->getDecl();
if (IDecl)
if (ObjCProtocolDecl* PNSCopying =
- LookupProtocol(&Context.Idents.get("NSCopying")))
+ LookupProtocol(&Context.Idents.get("NSCopying"), AtLoc))
if (IDecl->ClassImplementsProtocol(PNSCopying, true))
Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;
}
@@ -356,7 +356,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
if (!Ivar) {
Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, PropertyLoc,
PropertyIvar, PropType, /*Dinfo=*/0,
- ObjCIvarDecl::Public,
+ ObjCIvarDecl::Protected,
(Expr *)0);
ClassImpDecl->addDecl(Ivar);
IDecl->makeDeclVisibleInContext(Ivar, false);
@@ -719,7 +719,10 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
// scan through class's protocols.
for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
E = IDecl->protocol_end(); PI != E; ++PI)
- CollectImmediateProperties((*PI), PropMap);
+ // Exclude property for protocols which conform to class's super-class,
+ // as super-class has to implement the property.
+ if (!ProtocolConformsToSuperClass(IDecl, (*PI)))
+ CollectImmediateProperties((*PI), PropMap);
}
if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
if (!CATDecl->IsClassExtension())
@@ -748,6 +751,33 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
}
}
+/// ProtocolConformsToSuperClass - Returns true if class's given protocol
+/// conforms to one of its super class's protocols.
+bool Sema::ProtocolConformsToSuperClass(const ObjCInterfaceDecl *IDecl,
+ const ObjCProtocolDecl *PDecl) {
+ if (const ObjCInterfaceDecl *CDecl = IDecl->getSuperClass()) {
+ for (ObjCInterfaceDecl::protocol_iterator PI = CDecl->protocol_begin(),
+ E = CDecl->protocol_end(); PI != E; ++PI) {
+ if (ProtocolConformsToProtocol((*PI), PDecl))
+ return true;
+ return ProtocolConformsToSuperClass(CDecl, PDecl);
+ }
+ }
+ return false;
+}
+
+bool Sema::ProtocolConformsToProtocol(const ObjCProtocolDecl *NestedProtocol,
+ const ObjCProtocolDecl *PDecl) {
+ if (PDecl->getIdentifier() == NestedProtocol->getIdentifier())
+ return true;
+ // scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI)
+ if (ProtocolConformsToProtocol(NestedProtocol, (*PI)))
+ return true;
+ return false;
+}
+
/// LookupPropertyDecl - Looks up a property in the current class and all
/// its protocols.
ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
@@ -810,9 +840,9 @@ void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
PropImplMap.count(Prop))
continue;
- if (LangOpts.ObjCNonFragileABI2) {
+ if (LangOpts.ObjCNonFragileABI2 && !isa<ObjCCategoryImplDecl>(IMPDecl)) {
ActOnPropertyImplDecl(IMPDecl->getLocation(),
- SourceLocation(),
+ IMPDecl->getLocation(),
true, DeclPtrTy::make(IMPDecl),
Prop->getIdentifier(),
Prop->getIdentifier());
@@ -953,8 +983,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
property->getType(),
/*TInfo=*/0,
VarDecl::None,
+ VarDecl::None,
0);
- SetterMethod->setMethodParams(Context, &Argument, 1);
+ SetterMethod->setMethodParams(Context, &Argument, 1, 1);
CD->addDecl(SetterMethod);
} else
// A user declared setter will be synthesize when @synthesize of
@@ -1066,21 +1097,3 @@ void Sema::CheckObjCPropertyAttributes(DeclPtrTy PropertyPtrTy,
&& PropertyTy->isBlockPointerType())
Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
}
-
-ObjCIvarDecl*
-Sema::SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl,
- IdentifierInfo *NameII) {
- ObjCIvarDecl *Ivar = 0;
- ObjCPropertyDecl *Prop = LookupPropertyDecl(IDecl, NameII);
- if (Prop && !Prop->isInvalidDecl()) {
- QualType PropType = Context.getCanonicalType(Prop->getType());
- Ivar = ObjCIvarDecl::Create(Context, IDecl, Prop->getLocation(), NameII,
- PropType, /*Dinfo=*/0,
- ObjCIvarDecl::Public, (Expr *)0);
- Ivar->setLexicalDeclContext(IDecl);
- IDecl->addDecl(Ivar);
- Prop->setPropertyIvarDecl(Ivar);
- }
- return Ivar;
-}
-
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index bc10a58..21f2a51 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -226,7 +226,7 @@ void UserDefinedConversionSequence::DebugPrint() const {
Before.DebugPrint();
OS << " -> ";
}
- OS << "'" << ConversionFunction->getNameAsString() << "'";
+ OS << '\'' << ConversionFunction << '\'';
if (After.First || After.Second || After.Third) {
OS << " -> ";
After.DebugPrint();
@@ -374,8 +374,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old) {
if (OldQType != NewQType &&
(OldType->getNumArgs() != NewType->getNumArgs() ||
OldType->isVariadic() != NewType->isVariadic() ||
- !std::equal(OldType->arg_type_begin(), OldType->arg_type_end(),
- NewType->arg_type_begin())))
+ !FunctionArgTypesAreEqual(OldType, NewType)))
return true;
// C++ [temp.over.link]p4:
@@ -436,16 +435,11 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old) {
/// not permitted.
/// If @p AllowExplicit, then explicit user-defined conversions are
/// permitted.
-/// If @p ForceRValue, then overloading is performed as if From was an rvalue,
-/// no matter its actual lvalueness.
-/// If @p UserCast, the implicit conversion is being done for a user-specified
-/// cast.
ImplicitConversionSequence
Sema::TryImplicitConversion(Expr* From, QualType ToType,
bool SuppressUserConversions,
- bool AllowExplicit, bool ForceRValue,
- bool InOverloadResolution,
- bool UserCast) {
+ bool AllowExplicit,
+ bool InOverloadResolution) {
ImplicitConversionSequence ICS;
if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard)) {
ICS.setStandard();
@@ -457,11 +451,47 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
return ICS;
}
+ if (SuppressUserConversions) {
+ // 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
+ // expression of class type to a base class of that type is
+ // given Conversion rank, in spite of the fact that a copy/move
+ // constructor (i.e., a user-defined conversion function) is
+ // called for those cases.
+ QualType FromType = From->getType();
+ if (!ToType->getAs<RecordType>() || !FromType->getAs<RecordType>() ||
+ !(Context.hasSameUnqualifiedType(FromType, ToType) ||
+ IsDerivedFrom(FromType, ToType))) {
+ // We're not in the case above, so there is no conversion that
+ // we can perform.
+ ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
+ return ICS;
+ }
+
+ ICS.setStandard();
+ ICS.Standard.setAsIdentityConversion();
+ ICS.Standard.setFromType(FromType);
+ ICS.Standard.setAllToTypes(ToType);
+
+ // We don't actually check at this point whether there is a valid
+ // copy/move constructor, since overloading just assumes that it
+ // exists. When we actually perform initialization, we'll find the
+ // appropriate constructor to copy the returned object, if needed.
+ ICS.Standard.CopyConstructor = 0;
+
+ // Determine whether this is considered a derived-to-base conversion.
+ if (!Context.hasSameUnqualifiedType(FromType, ToType))
+ ICS.Standard.Second = ICK_Derived_To_Base;
+
+ return ICS;
+ }
+
+ // Attempt user-defined conversion.
OverloadCandidateSet Conversions(From->getExprLoc());
OverloadingResult UserDefResult
= IsUserDefinedConversion(From, ToType, ICS.UserDefined, Conversions,
- !SuppressUserConversions, AllowExplicit,
- ForceRValue, UserCast);
+ AllowExplicit);
if (UserDefResult == OR_Success) {
ICS.setUserDefined();
@@ -516,6 +546,30 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
return ICS;
}
+/// PerformImplicitConversion - Perform an implicit conversion of the
+/// expression From to the type ToType. Returns true if there was an
+/// error, false otherwise. The expression From is replaced with the
+/// converted expression. Flavor is the kind of conversion we're
+/// performing, used in the error message. If @p AllowExplicit,
+/// explicit user-defined conversions are permitted.
+bool
+Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+ AssignmentAction Action, bool AllowExplicit) {
+ ImplicitConversionSequence ICS;
+ return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS);
+}
+
+bool
+Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+ AssignmentAction Action, bool AllowExplicit,
+ ImplicitConversionSequence& ICS) {
+ ICS = TryImplicitConversion(From, ToType,
+ /*SuppressUserConversions=*/false,
+ AllowExplicit,
+ /*InOverloadResolution=*/false);
+ return PerformImplicitConversion(From, ToType, ICS, Action);
+}
+
/// \brief Determine whether the conversion from FromType to ToType is a valid
/// conversion that strips "noreturn" off the nested function type.
static bool IsNoReturnConversion(ASTContext &Context, QualType FromType,
@@ -567,8 +621,36 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// array-to-pointer conversion, or function-to-pointer conversion
// (C++ 4p1).
- DeclAccessPair AccessPair;
-
+ if (FromType == Context.OverloadTy) {
+ DeclAccessPair AccessPair;
+ if (FunctionDecl *Fn
+ = ResolveAddressOfOverloadedFunction(From, ToType, false,
+ AccessPair)) {
+ // We were able to resolve the address of the overloaded function,
+ // so we can convert to the type of that function.
+ FromType = Fn->getType();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
+ if (!Method->isStatic()) {
+ Type *ClassType
+ = Context.getTypeDeclType(Method->getParent()).getTypePtr();
+ FromType = Context.getMemberPointerType(FromType, ClassType);
+ }
+ }
+
+ // If the "from" expression takes the address of the overloaded
+ // function, update the type of the resulting expression accordingly.
+ if (FromType->getAs<FunctionType>())
+ if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(From->IgnoreParens()))
+ if (UnOp->getOpcode() == UnaryOperator::AddrOf)
+ FromType = Context.getPointerType(FromType);
+
+ // Check that we've computed the proper type after overload resolution.
+ assert(Context.hasSameType(FromType,
+ FixOverloadedFunctionReference(From, AccessPair, Fn)->getType()));
+ } else {
+ return false;
+ }
+ }
// Lvalue-to-rvalue conversion (C++ 4.1):
// An lvalue (3.10) of a non-function, non-array type T can be
// converted to an rvalue.
@@ -613,31 +695,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// type "pointer to T." The result is a pointer to the
// function. (C++ 4.3p1).
FromType = Context.getPointerType(FromType);
- } else if (FunctionDecl *Fn
- = ResolveAddressOfOverloadedFunction(From, ToType, false,
- AccessPair)) {
- // Address of overloaded function (C++ [over.over]).
- SCS.First = ICK_Function_To_Pointer;
-
- // We were able to resolve the address of the overloaded function,
- // so we can convert to the type of that function.
- FromType = Fn->getType();
- if (ToType->isLValueReferenceType())
- FromType = Context.getLValueReferenceType(FromType);
- else if (ToType->isRValueReferenceType())
- FromType = Context.getRValueReferenceType(FromType);
- else if (ToType->isMemberPointerType()) {
- // Resolve address only succeeds if both sides are member pointers,
- // but it doesn't have to be the same class. See DR 247.
- // Note that this means that the type of &Derived::fn can be
- // Ret (Base::*)(Args) if the fn overload actually found is from the
- // base class, even if it was brought into the derived class via a
- // using declaration. The standard isn't clear on this issue at all.
- CXXMethodDecl *M = cast<CXXMethodDecl>(Fn);
- FromType = Context.getMemberPointerType(FromType,
- Context.getTypeDeclType(M->getParent()).getTypePtr());
- } else
- FromType = Context.getPointerType(FromType);
} else {
// We don't require any conversions for the first step.
SCS.First = ICK_Identity;
@@ -1274,6 +1331,47 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
return false;
}
+
+/// FunctionArgTypesAreEqual - This routine checks two function proto types
+/// for equlity of their argument types. Caller has already checked that
+/// they have same number of arguments. This routine assumes that Objective-C
+/// pointer types which only differ in their protocol qualifiers are equal.
+bool Sema::FunctionArgTypesAreEqual(FunctionProtoType* OldType,
+ FunctionProtoType* NewType){
+ if (!getLangOptions().ObjC1)
+ return std::equal(OldType->arg_type_begin(), OldType->arg_type_end(),
+ NewType->arg_type_begin());
+
+ for (FunctionProtoType::arg_type_iterator O = OldType->arg_type_begin(),
+ N = NewType->arg_type_begin(),
+ E = OldType->arg_type_end(); O && (O != E); ++O, ++N) {
+ QualType ToType = (*O);
+ QualType FromType = (*N);
+ if (ToType != FromType) {
+ if (const PointerType *PTTo = ToType->getAs<PointerType>()) {
+ if (const PointerType *PTFr = FromType->getAs<PointerType>())
+ if (PTTo->getPointeeType()->isObjCQualifiedIdType() &&
+ PTFr->getPointeeType()->isObjCQualifiedIdType() ||
+ PTTo->getPointeeType()->isObjCQualifiedClassType() &&
+ PTFr->getPointeeType()->isObjCQualifiedClassType())
+ continue;
+ }
+ else if (ToType->isObjCObjectPointerType() &&
+ FromType->isObjCObjectPointerType()) {
+ QualType ToInterfaceTy = ToType->getPointeeType();
+ QualType FromInterfaceTy = FromType->getPointeeType();
+ if (const ObjCInterfaceType *OITTo =
+ ToInterfaceTy->getAs<ObjCInterfaceType>())
+ if (const ObjCInterfaceType *OITFr =
+ FromInterfaceTy->getAs<ObjCInterfaceType>())
+ if (OITTo->getDecl() == OITFr->getDecl())
+ continue;
+ }
+ return false;
+ }
+ }
+ return true;
+}
/// CheckPointerConversion - Check the pointer conversion from the
/// expression From to the type ToType. This routine checks for
@@ -1283,6 +1381,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
/// error, or returns false otherwise.
bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray& BasePath,
bool IgnoreBaseAccess) {
QualType FromType = From->getType();
@@ -1297,7 +1396,7 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
// ambiguous or inaccessible conversion.
if (CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType,
From->getExprLoc(),
- From->getSourceRange(),
+ From->getSourceRange(), &BasePath,
IgnoreBaseAccess))
return true;
@@ -1368,6 +1467,7 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType,
/// otherwise.
bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath,
bool IgnoreBaseAccess) {
QualType FromType = From->getType();
const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>();
@@ -1391,7 +1491,7 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
assert(FromClass->isRecordType() && "Pointer into non-class.");
assert(ToClass->isRecordType() && "Pointer into non-class.");
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/ true,
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths);
assert(DerivationOkay &&
@@ -1419,6 +1519,7 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
diag::err_downcast_from_inaccessible_base);
// Must be a base to derived member conversion.
+ BuildBasePathArray(Paths, BasePath);
Kind = CastExpr::CK_BaseToDerivedMemberPointer;
return false;
}
@@ -1482,48 +1583,39 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) {
/// and this routine will return true. Otherwise, this routine returns
/// false and User is unspecified.
///
-/// \param AllowConversionFunctions true if the conversion should
-/// consider conversion functions at all. If false, only constructors
-/// will be considered.
-///
/// \param AllowExplicit true if the conversion should consider C++0x
/// "explicit" conversion functions as well as non-explicit conversion
/// functions (C++0x [class.conv.fct]p2).
-///
-/// \param ForceRValue true if the expression should be treated as an rvalue
-/// for overload resolution.
-/// \param UserCast true if looking for user defined conversion for a static
-/// cast.
OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
- OverloadCandidateSet& CandidateSet,
- bool AllowConversionFunctions,
- bool AllowExplicit,
- bool ForceRValue,
- bool UserCast) {
+ OverloadCandidateSet& CandidateSet,
+ bool AllowExplicit) {
+ // Whether we will only visit constructors.
+ bool ConstructorsOnly = false;
+
+ // If the type we are conversion to is a class type, enumerate its
+ // constructors.
if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) {
+ // C++ [over.match.ctor]p1:
+ // When objects of class type are direct-initialized (8.5), or
+ // copy-initialized from an expression of the same or a
+ // derived class type (8.5), overload resolution selects the
+ // constructor. [...] For copy-initialization, the candidate
+ // functions are all the converting constructors (12.3.1) of
+ // that class. The argument list is the expression-list within
+ // the parentheses of the initializer.
+ if (Context.hasSameUnqualifiedType(ToType, From->getType()) ||
+ (From->getType()->getAs<RecordType>() &&
+ IsDerivedFrom(From->getType(), ToType)))
+ ConstructorsOnly = true;
+
if (RequireCompleteType(From->getLocStart(), ToType, PDiag())) {
// We're not going to find any constructors.
} else if (CXXRecordDecl *ToRecordDecl
= dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) {
- // C++ [over.match.ctor]p1:
- // When objects of class type are direct-initialized (8.5), or
- // copy-initialized from an expression of the same or a
- // derived class type (8.5), overload resolution selects the
- // constructor. [...] For copy-initialization, the candidate
- // functions are all the converting constructors (12.3.1) of
- // that class. The argument list is the expression-list within
- // the parentheses of the initializer.
- bool SuppressUserConversions = !UserCast;
- if (Context.hasSameUnqualifiedType(ToType, From->getType()) ||
- IsDerivedFrom(From->getType(), ToType)) {
- SuppressUserConversions = false;
- AllowConversionFunctions = false;
- }
-
DeclarationName ConstructorName
= Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(ToType).getUnqualifiedType());
+ Context.getCanonicalType(ToType).getUnqualifiedType());
DeclContext::lookup_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd)
= ToRecordDecl->lookup(ConstructorName);
@@ -1547,26 +1639,25 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
&From, 1, CandidateSet,
- SuppressUserConversions, ForceRValue);
+ /*SuppressUserConversions=*/!ConstructorsOnly);
else
// Allow one user-defined conversion when user specifies a
// From->ToType conversion via an static cast (c-style, etc).
AddOverloadCandidate(Constructor, FoundDecl,
&From, 1, CandidateSet,
- SuppressUserConversions, ForceRValue);
+ /*SuppressUserConversions=*/!ConstructorsOnly);
}
}
}
}
- if (!AllowConversionFunctions) {
- // Don't allow any conversion functions to enter the overload set.
+ // Enumerate conversion functions, if we're allowed to.
+ if (ConstructorsOnly) {
} else if (RequireCompleteType(From->getLocStart(), From->getType(),
- PDiag(0)
- << From->getSourceRange())) {
+ PDiag(0) << From->getSourceRange())) {
// No conversion functions from incomplete types.
} else if (const RecordType *FromRecordType
- = From->getType()->getAs<RecordType>()) {
+ = From->getType()->getAs<RecordType>()) {
if (CXXRecordDecl *FromRecordDecl
= dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) {
// Add all of the conversion functions as candidates.
@@ -1672,7 +1763,7 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
OverloadCandidateSet CandidateSet(From->getExprLoc());
OverloadingResult OvResult =
IsUserDefinedConversion(From, ToType, ICS.UserDefined,
- CandidateSet, true, false, false);
+ CandidateSet, false);
if (OvResult == OR_Ambiguous)
Diag(From->getSourceRange().getBegin(),
diag::err_typecheck_ambiguous_condition)
@@ -1708,15 +1799,14 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
// 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.getKindRank() < ICS2.getKindRank())
+ return ImplicitConversionSequence::Better;
+ else if (ICS2.getKindRank() < ICS1.getKindRank())
+ return ImplicitConversionSequence::Worse;
- if (ICS1.isAmbiguous() || ICS2.isAmbiguous())
+ // The following checks require both conversion sequences to be of
+ // the same kind.
+ if (ICS1.getKind() != ICS2.getKind())
return ImplicitConversionSequence::Indistinguishable;
// Two implicit conversion sequences of the same form are
@@ -2143,9 +2233,7 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
}
}
- if ((SCS1.ReferenceBinding || SCS1.CopyConstructor) &&
- (SCS2.ReferenceBinding || SCS2.CopyConstructor) &&
- SCS1.Second == ICK_Derived_To_Base) {
+ if (SCS1.Second == ICK_Derived_To_Base) {
// -- conversion of C to B is better than conversion of C to A,
// -- binding of an expression of type C to a reference of type
// B& is better than binding an expression of type C to a
@@ -2174,34 +2262,353 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
return ImplicitConversionSequence::Indistinguishable;
}
+/// CompareReferenceRelationship - Compare the two types T1 and T2 to
+/// determine whether they are reference-related,
+/// reference-compatible, reference-compatible with added
+/// qualification, or incompatible, for use in C++ initialization by
+/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference
+/// type, and the first type (T1) is the pointee type of the reference
+/// type being initialized.
+Sema::ReferenceCompareResult
+Sema::CompareReferenceRelationship(SourceLocation Loc,
+ QualType OrigT1, QualType OrigT2,
+ bool& DerivedToBase) {
+ assert(!OrigT1->isReferenceType() &&
+ "T1 must be the pointee type of the reference type");
+ assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
+
+ QualType T1 = Context.getCanonicalType(OrigT1);
+ QualType T2 = Context.getCanonicalType(OrigT2);
+ Qualifiers T1Quals, T2Quals;
+ QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
+ QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
+
+ // C++ [dcl.init.ref]p4:
+ // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
+ // reference-related to "cv2 T2" if T1 is the same type as T2, or
+ // T1 is a base class of T2.
+ if (UnqualT1 == UnqualT2)
+ DerivedToBase = false;
+ else if (!RequireCompleteType(Loc, OrigT1, PDiag()) &&
+ !RequireCompleteType(Loc, OrigT2, PDiag()) &&
+ IsDerivedFrom(UnqualT2, UnqualT1))
+ DerivedToBase = true;
+ else
+ return Ref_Incompatible;
+
+ // At this point, we know that T1 and T2 are reference-related (at
+ // least).
+
+ // If the type is an array type, promote the element qualifiers to the type
+ // for comparison.
+ if (isa<ArrayType>(T1) && T1Quals)
+ T1 = Context.getQualifiedType(UnqualT1, T1Quals);
+ if (isa<ArrayType>(T2) && T2Quals)
+ T2 = Context.getQualifiedType(UnqualT2, T2Quals);
+
+ // C++ [dcl.init.ref]p4:
+ // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is
+ // reference-related to T2 and cv1 is the same cv-qualification
+ // as, or greater cv-qualification than, cv2. For purposes of
+ // overload resolution, cases for which cv1 is greater
+ // cv-qualification than cv2 are identified as
+ // reference-compatible with added qualification (see 13.3.3.2).
+ if (T1Quals.getCVRQualifiers() == T2Quals.getCVRQualifiers())
+ return Ref_Compatible;
+ else if (T1.isMoreQualifiedThan(T2))
+ return Ref_Compatible_With_Added_Qualification;
+ else
+ return Ref_Related;
+}
+
+/// \brief Compute an implicit conversion sequence for reference
+/// initialization.
+static ImplicitConversionSequence
+TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
+ SourceLocation DeclLoc,
+ bool SuppressUserConversions,
+ bool AllowExplicit) {
+ assert(DeclType->isReferenceType() && "Reference init needs a reference");
+
+ // Most paths end in a failed conversion.
+ ImplicitConversionSequence ICS;
+ ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType);
+
+ QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType();
+ QualType T2 = Init->getType();
+
+ // If the initializer is the address of an overloaded function, try
+ // to resolve the overloaded function. If all goes well, T2 is the
+ // type of the resulting function.
+ if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) {
+ DeclAccessPair Found;
+ if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Init, DeclType,
+ false, Found))
+ T2 = Fn->getType();
+ }
+
+ // Compute some basic properties of the types and the initializer.
+ bool isRValRef = DeclType->isRValueReferenceType();
+ bool DerivedToBase = false;
+ Expr::isLvalueResult InitLvalue = Init->isLvalue(S.Context);
+ Sema::ReferenceCompareResult RefRelationship
+ = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase);
+
+
+ // C++ [over.ics.ref]p3:
+ // Except for an implicit object parameter, for which see 13.3.1,
+ // a standard conversion sequence cannot be formed if it requires
+ // binding an lvalue reference to non-const to an rvalue or
+ // binding an rvalue reference to an lvalue.
+ //
+ // FIXME: DPG doesn't trust this code. It seems far too early to
+ // abort because of a binding of an rvalue reference to an lvalue.
+ if (isRValRef && InitLvalue == Expr::LV_Valid)
+ return ICS;
+
+ // C++0x [dcl.init.ref]p16:
+ // A reference to type "cv1 T1" is initialized by an expression
+ // of type "cv2 T2" as follows:
+
+ // -- If the initializer expression
+ // -- is an lvalue (but is not a bit-field), and "cv1 T1" is
+ // reference-compatible with "cv2 T2," or
+ //
+ // Per C++ [over.ics.ref]p4, we don't check the bit-field property here.
+ if (InitLvalue == Expr::LV_Valid &&
+ RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
+ // C++ [over.ics.ref]p1:
+ // When a parameter of reference type binds directly (8.5.3)
+ // to an argument expression, the implicit conversion sequence
+ // is the identity conversion, unless the argument expression
+ // 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.setStandard();
+ ICS.Standard.First = ICK_Identity;
+ ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
+ ICS.Standard.Third = ICK_Identity;
+ ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
+ ICS.Standard.setToType(0, T2);
+ ICS.Standard.setToType(1, T1);
+ ICS.Standard.setToType(2, T1);
+ ICS.Standard.ReferenceBinding = true;
+ ICS.Standard.DirectBinding = true;
+ ICS.Standard.RRefBinding = false;
+ ICS.Standard.CopyConstructor = 0;
+
+ // Nothing more to do: the inaccessibility/ambiguity check for
+ // derived-to-base conversions is suppressed when we're
+ // computing the implicit conversion sequence (C++
+ // [over.best.ics]p2).
+ return ICS;
+ }
+
+ // -- has a class type (i.e., T2 is a class type), where T1 is
+ // not reference-related to T2, and can be implicitly
+ // converted to an lvalue of type "cv3 T3," where "cv1 T1"
+ // is reference-compatible with "cv3 T3" 92) (this
+ // conversion is selected by enumerating the applicable
+ // conversion functions (13.3.1.6) and choosing the best
+ // one through overload resolution (13.3)),
+ if (!isRValRef && !SuppressUserConversions && T2->isRecordType() &&
+ !S.RequireCompleteType(DeclLoc, T2, 0) &&
+ RefRelationship == Sema::Ref_Incompatible) {
+ CXXRecordDecl *T2RecordDecl
+ = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
+
+ OverloadCandidateSet CandidateSet(DeclLoc);
+ const UnresolvedSetImpl *Conversions
+ = T2RecordDecl->getVisibleConversionFunctions();
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
+ E = Conversions->end(); I != E; ++I) {
+ NamedDecl *D = *I;
+ CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+ FunctionTemplateDecl *ConvTemplate
+ = dyn_cast<FunctionTemplateDecl>(D);
+ CXXConversionDecl *Conv;
+ if (ConvTemplate)
+ Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ else
+ Conv = cast<CXXConversionDecl>(D);
+
+ // If the conversion function doesn't return a reference type,
+ // it can't be considered for this conversion.
+ if (Conv->getConversionType()->isLValueReferenceType() &&
+ (AllowExplicit || !Conv->isExplicit())) {
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC,
+ Init, DeclType, CandidateSet);
+ else
+ S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init,
+ DeclType, CandidateSet);
+ }
+ }
+
+ OverloadCandidateSet::iterator Best;
+ switch (S.BestViableFunction(CandidateSet, DeclLoc, Best)) {
+ case OR_Success:
+ // C++ [over.ics.ref]p1:
+ //
+ // [...] If the parameter binds directly to the result of
+ // applying a conversion function to the argument
+ // expression, the implicit conversion sequence is a
+ // user-defined conversion sequence (13.3.3.1.2), with the
+ // second standard conversion sequence either an identity
+ // 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.
+ if (!Best->FinalConversion.DirectBinding)
+ break;
+
+ ICS.setUserDefined();
+ ICS.UserDefined.Before = Best->Conversions[0].Standard;
+ ICS.UserDefined.After = Best->FinalConversion;
+ ICS.UserDefined.ConversionFunction = Best->Function;
+ ICS.UserDefined.EllipsisConversion = false;
+ assert(ICS.UserDefined.After.ReferenceBinding &&
+ ICS.UserDefined.After.DirectBinding &&
+ "Expected a direct reference binding!");
+ return ICS;
+
+ case OR_Ambiguous:
+ ICS.setAmbiguous();
+ for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
+ Cand != CandidateSet.end(); ++Cand)
+ if (Cand->Viable)
+ ICS.Ambiguous.addConversion(Cand->Function);
+ return ICS;
+
+ case OR_No_Viable_Function:
+ case OR_Deleted:
+ // There was no suitable conversion, or we found a deleted
+ // conversion; continue with other checks.
+ break;
+ }
+ }
+
+ // -- Otherwise, the reference shall be to a 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.
+ //
+ // We actually handle one oddity of C++ [over.ics.ref] at this
+ // point, which is that, due to p2 (which short-circuits reference
+ // binding by only attempting a simple conversion for non-direct
+ // bindings) and p3's strange wording, we allow a const volatile
+ // reference to bind to an rvalue. Hence the check for the presence
+ // of "const" rather than checking for "const" being the only
+ // qualifier.
+ if (!isRValRef && !T1.isConstQualified())
+ return ICS;
+
+ // -- if T2 is a class type and
+ // -- the initializer expression is an rvalue and "cv1 T1"
+ // is reference-compatible with "cv2 T2," or
+ //
+ // -- T1 is not reference-related to T2 and the initializer
+ // expression can be implicitly converted to an rvalue
+ // of type "cv3 T3" (this conversion is selected by
+ // enumerating the applicable conversion functions
+ // (13.3.1.6) and choosing the best one through overload
+ // resolution (13.3)),
+ //
+ // then the reference is bound to the initializer
+ // expression rvalue in the first case and to the object
+ // that is the result of the conversion in the second case
+ // (or, in either case, to the appropriate base class
+ // subobject of the object).
+ //
+ // We're only checking the first case here, which is a direct
+ // binding in C++0x but not in C++03.
+ if (InitLvalue != Expr::LV_Valid && T2->isRecordType() &&
+ RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
+ ICS.setStandard();
+ ICS.Standard.First = ICK_Identity;
+ ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
+ ICS.Standard.Third = ICK_Identity;
+ ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
+ ICS.Standard.setToType(0, T2);
+ ICS.Standard.setToType(1, T1);
+ ICS.Standard.setToType(2, T1);
+ ICS.Standard.ReferenceBinding = true;
+ ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x;
+ ICS.Standard.RRefBinding = isRValRef;
+ ICS.Standard.CopyConstructor = 0;
+ return ICS;
+ }
+
+ // -- Otherwise, a temporary of type "cv1 T1" is created and
+ // initialized from the initializer expression using the
+ // rules for a non-reference copy initialization (8.5). The
+ // reference is then bound to the temporary. 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.
+ if (RefRelationship == Sema::Ref_Related) {
+ // If cv1 == cv2 or cv1 is a greater cv-qualified than cv2, then
+ // we would be reference-compatible or reference-compatible with
+ // added qualification. But that wasn't the case, so the reference
+ // initialization fails.
+ return ICS;
+ }
+
+ // If at least one of the types is a class type, the types are not
+ // related, and we aren't allowed any user conversions, the
+ // reference binding fails. This case is important for breaking
+ // recursion, since TryImplicitConversion below will attempt to
+ // create a temporary through the use of a copy constructor.
+ if (SuppressUserConversions && RefRelationship == Sema::Ref_Incompatible &&
+ (T1->isRecordType() || T2->isRecordType()))
+ return ICS;
+
+ // C++ [over.ics.ref]p2:
+ // When a parameter of reference type is not bound directly to
+ // an argument expression, the conversion sequence is the one
+ // required to convert the argument expression to the
+ // underlying type of the reference according to
+ // 13.3.3.1. Conceptually, this conversion sequence corresponds
+ // to copy-initializing a temporary of the underlying type with
+ // the argument expression. Any difference in top-level
+ // cv-qualification is subsumed by the initialization itself
+ // and does not constitute a conversion.
+ ICS = S.TryImplicitConversion(Init, T1, SuppressUserConversions,
+ /*AllowExplicit=*/false,
+ /*InOverloadResolution=*/false);
+
+ // Of course, that's still a reference binding.
+ if (ICS.isStandard()) {
+ ICS.Standard.ReferenceBinding = true;
+ ICS.Standard.RRefBinding = isRValRef;
+ } else if (ICS.isUserDefined()) {
+ ICS.UserDefined.After.ReferenceBinding = true;
+ ICS.UserDefined.After.RRefBinding = isRValRef;
+ }
+ return ICS;
+}
+
/// TryCopyInitialization - Try to copy-initialize a value of type
/// ToType from the expression From. Return the implicit conversion
/// sequence required to pass this argument, which may be a bad
/// conversion sequence (meaning that the argument cannot be passed to
/// a parameter of this type). If @p SuppressUserConversions, then we
-/// do not permit any user-defined conversion sequences. If @p ForceRValue,
-/// then we treat @p From as an rvalue, even if it is an lvalue.
-ImplicitConversionSequence
-Sema::TryCopyInitialization(Expr *From, QualType ToType,
- bool SuppressUserConversions, bool ForceRValue,
- bool InOverloadResolution) {
- if (ToType->isReferenceType()) {
- ImplicitConversionSequence ICS;
- ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
- CheckReferenceInit(From, ToType,
- /*FIXME:*/From->getLocStart(),
- SuppressUserConversions,
- /*AllowExplicit=*/false,
- ForceRValue,
- &ICS);
- return ICS;
- } else {
- return TryImplicitConversion(From, ToType,
+/// do not permit any user-defined conversion sequences.
+static ImplicitConversionSequence
+TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
+ bool SuppressUserConversions,
+ bool InOverloadResolution) {
+ if (ToType->isReferenceType())
+ return TryReferenceInit(S, From, ToType,
+ /*FIXME:*/From->getLocStart(),
+ SuppressUserConversions,
+ /*AllowExplicit=*/false);
+
+ return S.TryImplicitConversion(From, ToType,
SuppressUserConversions,
/*AllowExplicit=*/false,
- ForceRValue,
InOverloadResolution);
- }
}
/// TryObjectArgumentInitialization - Try to initialize the object
@@ -2310,7 +2717,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From,
if (!Context.hasSameType(From->getType(), DestType))
ImpCastExprToType(From, DestType, CastExpr::CK_NoOp,
- /*isLvalue=*/!From->getType()->getAs<PointerType>());
+ /*isLvalue=*/!From->getType()->isPointerType());
return false;
}
@@ -2321,7 +2728,6 @@ ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) {
// FIXME: Are these flags correct?
/*SuppressUserConversions=*/false,
/*AllowExplicit=*/true,
- /*ForceRValue=*/false,
/*InOverloadResolution=*/false);
}
@@ -2343,9 +2749,6 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
/// candidate functions, using the given function call arguments. If
/// @p SuppressUserConversions, then don't allow user-defined
/// conversions via constructors or conversion operators.
-/// If @p ForceRValue, treat all arguments as rvalues. This is a slightly
-/// hacky way to implement the overloading rules for elidable copy
-/// initialization in C++0x (C++0x 12.8p15).
///
/// \para PartialOverloading true if we are performing "partial" overloading
/// based on an incomplete set of function arguments. This feature is used by
@@ -2356,7 +2759,6 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
- bool ForceRValue,
bool PartialOverloading) {
const FunctionProtoType* Proto
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
@@ -2375,7 +2777,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// is irrelevant.
AddMethodCandidate(Method, FoundDecl, Method->getParent(),
QualType(), Args, NumArgs, CandidateSet,
- SuppressUserConversions, ForceRValue);
+ SuppressUserConversions);
return;
}
// We treat a constructor like a non-member function, since its object
@@ -2445,8 +2847,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// parameter of F.
QualType ParamType = Proto->getArgType(ArgIdx);
Candidate.Conversions[ArgIdx]
- = TryCopyInitialization(Args[ArgIdx], ParamType,
- SuppressUserConversions, ForceRValue,
+ = TryCopyInitialization(*this, Args[ArgIdx], ParamType,
+ SuppressUserConversions,
/*InOverloadResolution=*/true);
if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
@@ -2504,7 +2906,7 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions, bool ForceRValue) {
+ bool SuppressUserConversions) {
NamedDecl *Decl = FoundDecl.getDecl();
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext());
@@ -2518,12 +2920,11 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
/*ExplicitArgs*/ 0,
ObjectType, Args, NumArgs,
CandidateSet,
- SuppressUserConversions,
- ForceRValue);
+ SuppressUserConversions);
} else {
AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext,
ObjectType, Args, NumArgs,
- CandidateSet, SuppressUserConversions, ForceRValue);
+ CandidateSet, SuppressUserConversions);
}
}
@@ -2533,15 +2934,13 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
/// @c o.f(a1,a2), @c Object will contain @c o and @c Args will contain
/// both @c a1 and @c a2. If @p SuppressUserConversions, then don't
/// allow user-defined conversions via constructors or conversion
-/// operators. If @p ForceRValue, treat all arguments as rvalues. This is
-/// a slightly hacky way to implement the overloading rules for elidable copy
-/// initialization in C++0x (C++0x 12.8p15).
+/// operators.
void
Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions, bool ForceRValue) {
+ bool SuppressUserConversions) {
const FunctionProtoType* Proto
= dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
assert(Proto && "Methods without a prototype cannot be overloaded");
@@ -2614,8 +3013,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// parameter of F.
QualType ParamType = Proto->getArgType(ArgIdx);
Candidate.Conversions[ArgIdx + 1]
- = TryCopyInitialization(Args[ArgIdx], ParamType,
- SuppressUserConversions, ForceRValue,
+ = TryCopyInitialization(*this, Args[ArgIdx], ParamType,
+ SuppressUserConversions,
/*InOverloadResolution=*/true);
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
@@ -2642,8 +3041,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions,
- bool ForceRValue) {
+ bool SuppressUserConversions) {
if (!CandidateSet.isNewCandidate(MethodTmpl))
return;
@@ -2674,7 +3072,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
"Specialization is not a member function?");
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
ActingContext, ObjectType, Args, NumArgs,
- CandidateSet, SuppressUserConversions, ForceRValue);
+ CandidateSet, SuppressUserConversions);
}
/// \brief Add a C++ function template specialization as a candidate
@@ -2686,8 +3084,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions,
- bool ForceRValue) {
+ bool SuppressUserConversions) {
if (!CandidateSet.isNewCandidate(FunctionTemplate))
return;
@@ -2724,7 +3121,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
// deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
AddOverloadCandidate(Specialization, FoundDecl, Args, NumArgs, CandidateSet,
- SuppressUserConversions, ForceRValue);
+ SuppressUserConversions);
}
/// AddConversionCandidate - Add a C++ conversion function as a
@@ -2741,7 +3138,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
OverloadCandidateSet& CandidateSet) {
assert(!Conversion->getDescribedFunctionTemplate() &&
"Conversion function templates use AddTemplateConversionCandidate");
-
+ QualType ConvType = Conversion->getConversionType().getNonReferenceType();
if (!CandidateSet.isNewCandidate(Conversion))
return;
@@ -2756,7 +3153,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.FinalConversion.setAsIdentityConversion();
- Candidate.FinalConversion.setFromType(Conversion->getConversionType());
+ Candidate.FinalConversion.setFromType(ConvType);
Candidate.FinalConversion.setAllToTypes(ToType);
// Determine the implicit conversion sequence for the implicit
@@ -2789,7 +3186,6 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
return;
}
-
// To determine what the conversion from the result of calling the
// conversion function to the type we're eventually trying to
// convert to (ToType), we need to synthesize a call to the
@@ -2802,7 +3198,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
From->getLocStart());
ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()),
CastExpr::CK_FunctionToPointerDecay,
- &ConversionRef, false);
+ &ConversionRef, CXXBaseSpecifierArray(), false);
// Note that it is safe to allocate CallExpr on the stack here because
// there are 0 arguments (i.e., nothing is allocated using ASTContext's
@@ -2811,14 +3207,24 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Conversion->getConversionType().getNonReferenceType(),
From->getLocStart());
ImplicitConversionSequence ICS =
- TryCopyInitialization(&Call, ToType,
+ TryCopyInitialization(*this, &Call, ToType,
/*SuppressUserConversions=*/true,
- /*ForceRValue=*/false,
/*InOverloadResolution=*/false);
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
Candidate.FinalConversion = ICS.Standard;
+
+ // C++ [over.ics.user]p3:
+ // If the user-defined conversion is specified by a specialization of a
+ // conversion function template, the second standard conversion sequence
+ // shall have exact match rank.
+ if (Conversion->getPrimaryTemplate() &&
+ GetConversionRank(ICS.Standard.Second) != ICR_Exact_Match) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_final_conversion_not_exact;
+ }
+
break;
case ImplicitConversionSequence::BadConversion:
@@ -2948,9 +3354,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// parameter of F.
QualType ParamType = Proto->getArgType(ArgIdx);
Candidate.Conversions[ArgIdx + 1]
- = TryCopyInitialization(Args[ArgIdx], ParamType,
+ = TryCopyInitialization(*this, Args[ArgIdx], ParamType,
/*SuppressUserConversions=*/false,
- /*ForceRValue=*/false,
/*InOverloadResolution=*/false);
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
@@ -2966,31 +3371,6 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
}
}
-// FIXME: This will eventually be removed, once we've migrated all of the
-// operator overloading logic over to the scheme used by binary operators, which
-// works for template instantiation.
-void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
- SourceLocation OpLoc,
- Expr **Args, unsigned NumArgs,
- OverloadCandidateSet& CandidateSet,
- SourceRange OpRange) {
- UnresolvedSet<16> Fns;
-
- QualType T1 = Args[0]->getType();
- QualType T2;
- if (NumArgs > 1)
- T2 = Args[1]->getType();
-
- DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
- if (S)
- LookupOverloadedOperatorName(Op, S, T1, T2, Fns);
- AddFunctionCandidates(Fns, Args, NumArgs, CandidateSet, false);
- AddArgumentDependentLookupCandidates(OpName, false, Args, NumArgs, 0,
- CandidateSet);
- AddMemberOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet, OpRange);
- AddBuiltinOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet);
-}
-
/// \brief Add overload candidates for overloaded operators that are
/// member functions.
///
@@ -3092,9 +3472,8 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
Candidate.Conversions[ArgIdx] = TryContextuallyConvertToBool(Args[ArgIdx]);
} else {
Candidate.Conversions[ArgIdx]
- = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx],
+ = TryCopyInitialization(*this, Args[ArgIdx], ParamTys[ArgIdx],
ArgIdx == 0 && IsAssignmentOperator,
- /*ForceRValue=*/false,
/*InOverloadResolution=*/false);
}
if (Candidate.Conversions[ArgIdx].isBad()) {
@@ -3362,7 +3741,7 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
const RecordType *TyRec;
if (const MemberPointerType *RHSMPType =
ArgExpr->getType()->getAs<MemberPointerType>())
- TyRec = cast<RecordType>(RHSMPType->getClass());
+ TyRec = RHSMPType->getClass()->getAs<RecordType>();
else
TyRec = ArgExpr->getType()->getAs<RecordType>();
if (!TyRec) {
@@ -4161,7 +4540,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
continue;
AddOverloadCandidate(FD, FoundDecl, Args, NumArgs, CandidateSet,
- false, false, PartialOverloading);
+ false, PartialOverloading);
} else
AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I),
FoundDecl, ExplicitTemplateArgs,
@@ -4628,6 +5007,7 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_trivial_conversion:
case ovl_fail_bad_final_conversion:
+ case ovl_fail_final_conversion_not_exact:
return S.NoteOverloadCandidate(Fn);
case ovl_fail_bad_conversion: {
@@ -4823,10 +5203,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
assert(!Cand->Conversions[ConvIdx].isInitialized() &&
"remaining conversion is initialized?");
- // FIXME: these should probably be preserved from the overload
+ // FIXME: this should probably be preserved from the overload
// operation somehow.
bool SuppressUserConversions = false;
- bool ForceRValue = false;
const FunctionProtoType* Proto;
unsigned ArgIdx = ConvIdx;
@@ -4848,10 +5227,10 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
assert(ConvCount <= 3);
for (; ConvIdx != ConvCount; ++ConvIdx)
Cand->Conversions[ConvIdx]
- = S.TryCopyInitialization(Args[ConvIdx],
- Cand->BuiltinTypes.ParamTypes[ConvIdx],
- SuppressUserConversions, ForceRValue,
- /*InOverloadResolution*/ true);
+ = TryCopyInitialization(S, Args[ConvIdx],
+ Cand->BuiltinTypes.ParamTypes[ConvIdx],
+ SuppressUserConversions,
+ /*InOverloadResolution*/ true);
return;
}
@@ -4860,9 +5239,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) {
if (ArgIdx < NumArgsInProto)
Cand->Conversions[ConvIdx]
- = S.TryCopyInitialization(Args[ArgIdx], Proto->getArgType(ArgIdx),
- SuppressUserConversions, ForceRValue,
- /*InOverloadResolution=*/true);
+ = TryCopyInitialization(S, Args[ArgIdx], Proto->getArgType(ArgIdx),
+ SuppressUserConversions,
+ /*InOverloadResolution=*/true);
else
Cand->Conversions[ConvIdx].setEllipsis();
}
@@ -4966,15 +5345,6 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
IsMember = true;
}
- // We only look at pointers or references to functions.
- FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType();
- if (!FunctionType->isFunctionType())
- return 0;
-
- // Find the actual overloaded function declaration.
- if (From->getType() != Context.OverloadTy)
- return 0;
-
// C++ [over.over]p1:
// [...] [Note: any redundant set of parentheses surrounding the
// overloaded function name is ignored (5.1). ]
@@ -4987,6 +5357,18 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer);
ExplicitTemplateArgs = &ETABuffer;
}
+
+ // We expect a pointer or reference to function, or a function pointer.
+ FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType();
+ if (!FunctionType->isFunctionType()) {
+ if (Complain)
+ Diag(From->getLocStart(), diag::err_addr_ovl_not_func_ptrref)
+ << OvlExpr->getName() << ToType;
+
+ return 0;
+ }
+
+ assert(From->getType() == Context.OverloadTy);
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
@@ -5068,9 +5450,19 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
}
// If there were 0 or 1 matches, we're done.
- if (Matches.empty())
+ if (Matches.empty()) {
+ if (Complain) {
+ Diag(From->getLocStart(), diag::err_addr_ovl_no_viable)
+ << OvlExpr->getName() << FunctionType;
+ for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
+ E = OvlExpr->decls_end();
+ I != E; ++I)
+ if (FunctionDecl *F = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()))
+ NoteOverloadCandidate(F);
+ }
+
return 0;
- else if (Matches.size() == 1) {
+ } else if (Matches.size() == 1) {
FunctionDecl *Result = Matches[0].second;
FoundResult = Matches[0].first;
MarkDeclarationReferenced(From->getLocStart(), Result);
@@ -5223,7 +5615,7 @@ static void AddOverloadedCallCandidate(Sema &S,
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) {
assert(!ExplicitTemplateArgs && "Explicit template arguments?");
S.AddOverloadCandidate(Func, FoundDecl, Args, NumArgs, CandidateSet,
- false, false, PartialOverloading);
+ false, PartialOverloading);
return;
}
@@ -5310,7 +5702,7 @@ static Sema::OwningExprResult Destroy(Sema &SemaRef, Expr *Fn,
///
/// Returns true if new candidates were found.
static Sema::OwningExprResult
-BuildRecoveryCallExpr(Sema &SemaRef, Expr *Fn,
+BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
@@ -5332,7 +5724,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Expr *Fn,
LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
Sema::LookupOrdinaryName);
- if (SemaRef.DiagnoseEmptyLookup(/*Scope=*/0, SS, R))
+ if (SemaRef.DiagnoseEmptyLookup(S, SS, R))
return Destroy(SemaRef, Fn, Args, NumArgs);
assert(!R.empty() && "lookup results empty despite recovery");
@@ -5368,7 +5760,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Expr *Fn,
/// resolution. Otherwise, emits diagnostics, deletes all of the
/// arguments and Fn, and returns NULL.
Sema::OwningExprResult
-Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
+Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation *CommaLocs,
@@ -5401,7 +5793,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
// AddRecoveryCallCandidates diagnoses the error itself, so we just
// bailout out if it fails.
if (CandidateSet.empty())
- return BuildRecoveryCallExpr(*this, Fn, ULE, LParenLoc, Args, NumArgs,
+ return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc);
OverloadCandidateSet::iterator Best;
@@ -6003,7 +6395,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
MemberExpr *MemExpr;
CXXMethodDecl *Method = 0;
- NamedDecl *FoundDecl = 0;
+ DeclAccessPair FoundDecl = DeclAccessPair::make(0, AS_public);
NestedNameSpecifier *Qualifier = 0;
if (isa<MemberExpr>(NakedMemExpr)) {
MemExpr = cast<MemberExpr>(NakedMemExpr);
@@ -6281,7 +6673,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc,
MultiExprArg(*this, (ExprTy**)Args, NumArgs),
- CommaLocs, RParenLoc).release();
+ CommaLocs, RParenLoc).result();
}
CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl);
@@ -6385,7 +6777,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
if (CheckFunctionCall(Method, TheCall.get()))
return true;
- return MaybeBindToTemporary(TheCall.release()).release();
+ return MaybeBindToTemporary(TheCall.release()).result();
}
/// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator->
@@ -6486,7 +6878,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
/// perhaps a '&' around it). We have resolved the overloaded function
/// to the function declaration Fn, so patch up the expression E to
/// refer (possibly indirectly) to Fn. Returns the new expr.
-Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found,
+Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
FunctionDecl *Fn) {
if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(),
@@ -6508,7 +6900,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found,
return new (Context) ImplicitCastExpr(ICE->getType(),
ICE->getCastKind(),
- SubExpr,
+ SubExpr, CXXBaseSpecifierArray(),
ICE->isLvalueCast());
}
@@ -6619,7 +7011,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found,
}
Sema::OwningExprResult Sema::FixOverloadedFunctionReference(OwningExprResult E,
- NamedDecl *Found,
+ DeclAccessPair Found,
FunctionDecl *Fn) {
return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Found, Fn));
}
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index cff4774..5e61111 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -34,7 +34,7 @@ namespace clang {
OR_Success, ///< Overload resolution succeeded.
OR_No_Viable_Function, ///< No viable function found.
OR_Ambiguous, ///< Ambiguous candidates found.
- OR_Deleted ///< Overload resoltuion refers to a deleted function.
+ OR_Deleted ///< Succeeded, but refers to a deleted function.
};
/// ImplicitConversionKind - The kind of implicit conversion used to
@@ -381,6 +381,33 @@ namespace clang {
assert(isInitialized() && "querying uninitialized conversion");
return Kind(ConversionKind);
}
+
+ /// \brief Return a ranking of the implicit conversion sequence
+ /// kind, where smaller ranks represent better conversion
+ /// sequences.
+ ///
+ /// In particular, this routine gives user-defined conversion
+ /// sequences and ambiguous conversion sequences the same rank,
+ /// per C++ [over.best.ics]p10.
+ unsigned getKindRank() const {
+ switch (getKind()) {
+ case StandardConversion:
+ return 0;
+
+ case UserDefinedConversion:
+ case AmbiguousConversion:
+ return 1;
+
+ case EllipsisConversion:
+ return 2;
+
+ case BadConversion:
+ return 3;
+ }
+
+ return 3;
+ }
+
bool isBad() const { return getKind() == BadConversion; }
bool isStandard() const { return getKind() == StandardConversion; }
bool isEllipsis() const { return getKind() == EllipsisConversion; }
@@ -440,7 +467,11 @@ namespace clang {
/// This conversion candidate is not viable because its result
/// type is not implicitly convertible to the desired type.
- ovl_fail_bad_final_conversion
+ ovl_fail_bad_final_conversion,
+
+ /// This conversion function template specialization candidate is not
+ /// viable because the final conversion was not an exact match.
+ ovl_fail_final_conversion_not_exact
};
/// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 791de8c..9d6132d 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/STLExtras.h"
@@ -125,7 +126,27 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result";
return;
}
+ } else if (const CXXFunctionalCastExpr *FC
+ = dyn_cast<CXXFunctionalCastExpr>(E)) {
+ if (isa<CXXConstructExpr>(FC->getSubExpr()) ||
+ isa<CXXTemporaryObjectExpr>(FC->getSubExpr()))
+ return;
+ }
+ // Diagnose "(void*) blah" as a typo for "(void) blah".
+ else if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(E)) {
+ TypeSourceInfo *TI = CE->getTypeInfoAsWritten();
+ QualType T = TI->getType();
+
+ // We really do want to use the non-canonical type here.
+ if (T == Context.VoidPtrTy) {
+ PointerTypeLoc TL = cast<PointerTypeLoc>(TI->getTypeLoc());
+
+ Diag(Loc, diag::warn_unused_voidptr)
+ << FixItHint::CreateRemoval(TL.getStarLoc());
+ return;
+ }
}
+
Diag(Loc, DiagID) << R1 << R2;
}
@@ -572,7 +593,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
return StmtError();
}
- if (CondTypeBeforePromotion->isBooleanType()) {
+ if (CondExpr->isKnownToHaveBooleanValue()) {
// switch(bool_expr) {...} is often a programmer error, e.g.
// switch(n && mask) { ... } // Doh - should be "n & mask".
// One can always use an if statement instead of switch(bool_expr).
@@ -967,19 +988,22 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
return StmtError(Diag(VD->getLocation(),
diag::err_non_variable_decl_in_for));
} else {
- if (cast<Expr>(First)->isLvalue(Context) != Expr::LV_Valid)
+ Expr *FirstE = cast<Expr>(First);
+ if (!FirstE->isTypeDependent() &&
+ FirstE->isLvalue(Context) != Expr::LV_Valid)
return StmtError(Diag(First->getLocStart(),
diag::err_selector_element_not_lvalue)
<< First->getSourceRange());
FirstType = static_cast<Expr*>(First)->getType();
}
- if (!FirstType->isObjCObjectPointerType() &&
+ if (!FirstType->isDependentType() &&
+ !FirstType->isObjCObjectPointerType() &&
!FirstType->isBlockPointerType())
Diag(ForLoc, diag::err_selector_element_type)
<< FirstType << First->getSourceRange();
}
- if (Second) {
+ if (Second && !Second->isTypeDependent()) {
DefaultFunctionArrayLvalueConversion(Second);
QualType SecondType = Second->getType();
if (!SecondType->isObjCObjectPointerType())
@@ -1422,53 +1446,72 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
if (Context.hasSameType(InTy, OutTy))
continue; // All types can be tied to themselves.
- // Int/ptr operands have some special cases that we allow.
- if ((OutTy->isIntegerType() || OutTy->isPointerType()) &&
- (InTy->isIntegerType() || InTy->isPointerType())) {
-
- // They are ok if they are the same size. Tying void* to int is ok if
- // they are the same size, for example. This also allows tying void* to
- // int*.
- uint64_t OutSize = Context.getTypeSize(OutTy);
- uint64_t InSize = Context.getTypeSize(InTy);
- if (OutSize == InSize)
- continue;
-
- // If the smaller input/output operand is not mentioned in the asm string,
- // then we can promote it and the asm string won't notice. Check this
- // case now.
- bool SmallerValueMentioned = false;
- for (unsigned p = 0, e = Pieces.size(); p != e; ++p) {
- AsmStmt::AsmStringPiece &Piece = Pieces[p];
- if (!Piece.isOperand()) continue;
-
- // If this is a reference to the input and if the input was the smaller
- // one, then we have to reject this asm.
- if (Piece.getOperandNo() == i+NumOutputs) {
- if (InSize < OutSize) {
- SmallerValueMentioned = true;
- break;
- }
- }
+ // Decide if the input and output are in the same domain (integer/ptr or
+ // floating point.
+ enum AsmDomain {
+ AD_Int, AD_FP, AD_Other
+ } InputDomain, OutputDomain;
+
+ if (InTy->isIntegerType() || InTy->isPointerType())
+ InputDomain = AD_Int;
+ else if (InTy->isFloatingType())
+ InputDomain = AD_FP;
+ else
+ InputDomain = AD_Other;
- // If this is a reference to the input and if the input was the smaller
- // one, then we have to reject this asm.
- if (Piece.getOperandNo() == TiedTo) {
- if (InSize > OutSize) {
- SmallerValueMentioned = true;
- break;
- }
+ if (OutTy->isIntegerType() || OutTy->isPointerType())
+ OutputDomain = AD_Int;
+ else if (OutTy->isFloatingType())
+ OutputDomain = AD_FP;
+ else
+ OutputDomain = AD_Other;
+
+ // They are ok if they are the same size and in the same domain. This
+ // allows tying things like:
+ // void* to int*
+ // void* to int if they are the same size.
+ // double to long double if they are the same size.
+ //
+ uint64_t OutSize = Context.getTypeSize(OutTy);
+ uint64_t InSize = Context.getTypeSize(InTy);
+ if (OutSize == InSize && InputDomain == OutputDomain &&
+ InputDomain != AD_Other)
+ continue;
+
+ // If the smaller input/output operand is not mentioned in the asm string,
+ // then we can promote it and the asm string won't notice. Check this
+ // case now.
+ bool SmallerValueMentioned = false;
+ for (unsigned p = 0, e = Pieces.size(); p != e; ++p) {
+ AsmStmt::AsmStringPiece &Piece = Pieces[p];
+ if (!Piece.isOperand()) continue;
+
+ // If this is a reference to the input and if the input was the smaller
+ // one, then we have to reject this asm.
+ if (Piece.getOperandNo() == i+NumOutputs) {
+ if (InSize < OutSize) {
+ SmallerValueMentioned = true;
+ break;
}
}
- // If the smaller value wasn't mentioned in the asm string, and if the
- // output was a register, just extend the shorter one to the size of the
- // larger one.
- if (!SmallerValueMentioned &&
- OutputConstraintInfos[TiedTo].allowsRegister())
- continue;
+ // If this is a reference to the input and if the input was the smaller
+ // one, then we have to reject this asm.
+ if (Piece.getOperandNo() == TiedTo) {
+ if (InSize > OutSize) {
+ SmallerValueMentioned = true;
+ break;
+ }
+ }
}
+ // If the smaller value wasn't mentioned in the asm string, and if the
+ // output was a register, just extend the shorter one to the size of the
+ // larger one.
+ if (!SmallerValueMentioned && InputDomain != AD_Other &&
+ OutputConstraintInfos[TiedTo].allowsRegister())
+ continue;
+
Diag(InputExpr->getLocStart(),
diag::err_asm_tying_incompatible_types)
<< InTy << OutTy << OutputExpr->getSourceRange()
@@ -1483,27 +1526,13 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
Action::OwningStmtResult
Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
SourceLocation RParen, DeclPtrTy Parm,
- StmtArg Body, StmtArg catchList) {
- Stmt *CatchList = catchList.takeAs<Stmt>();
- ParmVarDecl *PVD = cast_or_null<ParmVarDecl>(Parm.getAs<Decl>());
-
- // PVD == 0 implies @catch(...).
- if (PVD) {
- // If we already know the decl is invalid, reject it.
- if (PVD->isInvalidDecl())
- return StmtError();
-
- if (!PVD->getType()->isObjCObjectPointerType())
- return StmtError(Diag(PVD->getLocation(),
- diag::err_catch_param_not_objc_type));
- if (PVD->getType()->isObjCQualifiedIdType())
- return StmtError(Diag(PVD->getLocation(),
- diag::err_illegal_qualifiers_on_catch_parm));
- }
-
- ObjCAtCatchStmt *CS = new (Context) ObjCAtCatchStmt(AtLoc, RParen,
- PVD, Body.takeAs<Stmt>(), CatchList);
- return Owned(CatchList ? CatchList : CS);
+ StmtArg Body) {
+ VarDecl *Var = cast_or_null<VarDecl>(Parm.getAs<Decl>());
+ if (Var && Var->isInvalidDecl())
+ return StmtError();
+
+ return Owned(new (Context) ObjCAtCatchStmt(AtLoc, RParen, Var,
+ Body.takeAs<Stmt>()));
}
Action::OwningStmtResult
@@ -1513,18 +1542,38 @@ Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body) {
}
Action::OwningStmtResult
-Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc,
- StmtArg Try, StmtArg Catch, StmtArg Finally) {
+Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, StmtArg Try,
+ MultiStmtArg CatchStmts, StmtArg Finally) {
FunctionNeedsScopeChecking() = true;
- return Owned(new (Context) ObjCAtTryStmt(AtLoc, Try.takeAs<Stmt>(),
- Catch.takeAs<Stmt>(),
- Finally.takeAs<Stmt>()));
+ unsigned NumCatchStmts = CatchStmts.size();
+ return Owned(ObjCAtTryStmt::Create(Context, AtLoc, Try.takeAs<Stmt>(),
+ (Stmt **)CatchStmts.release(),
+ NumCatchStmts,
+ Finally.takeAs<Stmt>()));
+}
+
+Sema::OwningStmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc,
+ ExprArg ThrowE) {
+ Expr *Throw = static_cast<Expr *>(ThrowE.get());
+ if (Throw) {
+ QualType ThrowType = Throw->getType();
+ // Make sure the expression type is an ObjC pointer or "void *".
+ if (!ThrowType->isDependentType() &&
+ !ThrowType->isObjCObjectPointerType()) {
+ const PointerType *PT = ThrowType->getAs<PointerType>();
+ if (!PT || !PT->getPointeeType()->isVoidType())
+ return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object)
+ << Throw->getType() << Throw->getSourceRange());
+ }
+ }
+
+ return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowE.takeAs<Expr>()));
}
Action::OwningStmtResult
-Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) {
- Expr *ThrowExpr = expr.takeAs<Expr>();
- if (!ThrowExpr) {
+Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg Throw,
+ Scope *CurScope) {
+ if (!Throw.get()) {
// @throw without an expression designates a rethrow (which much occur
// in the context of an @catch clause).
Scope *AtCatchParent = CurScope;
@@ -1532,17 +1581,9 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) {
AtCatchParent = AtCatchParent->getParent();
if (!AtCatchParent)
return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch));
- } else {
- QualType ThrowType = ThrowExpr->getType();
- // Make sure the expression type is an ObjC pointer or "void *".
- if (!ThrowType->isObjCObjectPointerType()) {
- const PointerType *PT = ThrowType->getAs<PointerType>();
- if (!PT || !PT->getPointeeType()->isVoidType())
- return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object)
- << ThrowExpr->getType() << ThrowExpr->getSourceRange());
- }
- }
- return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowExpr));
+ }
+
+ return BuildObjCAtThrowStmt(AtLoc, move(Throw));
}
Action::OwningStmtResult
@@ -1552,7 +1593,8 @@ Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr,
// Make sure the expression type is an ObjC pointer or "void *".
Expr *SyncExpr = static_cast<Expr*>(SynchExpr.get());
- if (!SyncExpr->getType()->isObjCObjectPointerType()) {
+ if (!SyncExpr->getType()->isDependentType() &&
+ !SyncExpr->getType()->isObjCObjectPointerType()) {
const PointerType *PT = SyncExpr->getType()->getAs<PointerType>();
if (!PT || !PT->getPointeeType()->isVoidType())
return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object)
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 40ec4bcb..694b21c 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -63,20 +63,40 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) {
}
static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) {
+ // The set of class templates we've already seen.
+ llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates;
LookupResult::Filter filter = R.makeFilter();
while (filter.hasNext()) {
NamedDecl *Orig = filter.next();
NamedDecl *Repl = isAcceptableTemplateName(C, Orig->getUnderlyingDecl());
if (!Repl)
filter.erase();
- else if (Repl != Orig)
+ else if (Repl != Orig) {
+
+ // C++ [temp.local]p3:
+ // A lookup that finds an injected-class-name (10.2) can result in an
+ // ambiguity in certain cases (for example, if it is found in more than
+ // one base class). If all of the injected-class-names that are found
+ // refer to specializations of the same class template, and if the name
+ // is followed by a template-argument-list, the reference refers to the
+ // class template itself and not a specialization thereof, and is not
+ // ambiguous.
+ //
+ // FIXME: Will we eventually have to do the same for alias templates?
+ if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl))
+ if (!ClassTemplates.insert(ClassTmpl)) {
+ filter.erase();
+ continue;
+ }
+
filter.replace(Repl);
+ }
}
filter.done();
}
TemplateNameKind Sema::isTemplateName(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectTypePtr,
bool EnteringContext,
@@ -109,7 +129,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
LookupOrdinaryName);
R.suppressDiagnostics();
LookupTemplateName(R, S, SS, ObjectType, EnteringContext);
- if (R.empty())
+ if (R.empty() || R.isAmbiguous())
return TNK_Non_template;
TemplateName Template;
@@ -169,7 +189,7 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
}
void Sema::LookupTemplateName(LookupResult &Found,
- Scope *S, const CXXScopeSpec &SS,
+ Scope *S, CXXScopeSpec &SS,
QualType ObjectType,
bool EnteringContext) {
// Determine where to perform name lookup
@@ -190,7 +210,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
isDependent = isDependentScopeSpecifier(SS);
// The declaration context must be complete.
- if (LookupCtx && RequireCompleteDeclContext(SS))
+ if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx))
return;
}
@@ -227,14 +247,11 @@ void Sema::LookupTemplateName(LookupResult &Found,
LookupName(Found, S);
}
- // FIXME: Cope with ambiguous name-lookup results.
- assert(!Found.isAmbiguous() &&
- "Cannot handle template name-lookup ambiguities");
-
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)) {
+ if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx,
+ false, CTC_CXXCasts)) {
FilterAcceptableTemplateNames(Context, Found);
if (!Found.empty() && isa<TemplateDecl>(*Found.begin())) {
if (LookupCtx)
@@ -271,8 +288,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
LookupOrdinaryName);
LookupName(FoundOuter, S);
FilterAcceptableTemplateNames(Context, FoundOuter);
- // FIXME: Handle ambiguities in this lookup better
-
+
if (FoundOuter.empty()) {
// - if the name is not found, the name found in the class of the
// object expression is used, otherwise
@@ -439,7 +455,9 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
bool Invalid = false;
if (ParamName) {
- NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName);
+ NamedDecl *PrevDecl = LookupSingleName(S, ParamName, ParamNameLoc,
+ LookupOrdinaryName,
+ ForRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter())
Invalid = Invalid || DiagnoseTemplateParameterShadow(ParamNameLoc,
PrevDecl);
@@ -560,7 +578,9 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
IdentifierInfo *ParamName = D.getIdentifier();
if (ParamName) {
- NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName);
+ NamedDecl *PrevDecl = LookupSingleName(S, ParamName, D.getIdentifierLoc(),
+ LookupOrdinaryName,
+ ForRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter())
Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
PrevDecl);
@@ -705,7 +725,7 @@ static void SetNestedNameSpecifier(TagDecl *T, const CXXScopeSpec &SS) {
Sema::DeclResult
Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
- SourceLocation KWLoc, const CXXScopeSpec &SS,
+ SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
TemplateParameterList *TemplateParams,
@@ -733,25 +753,27 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
LookupResult Previous(*this, Name, NameLoc, LookupOrdinaryName,
ForRedeclaration);
if (SS.isNotEmpty() && !SS.isInvalid()) {
- if (RequireCompleteDeclContext(SS))
- return true;
-
SemanticContext = computeDeclContext(SS, true);
if (!SemanticContext) {
// FIXME: Produce a reasonable diagnostic here
return true;
}
+ if (RequireCompleteDeclContext(SS, SemanticContext))
+ return true;
+
LookupQualifiedName(Previous, SemanticContext);
} else {
SemanticContext = CurContext;
LookupName(Previous, S);
}
- assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?");
+ if (Previous.isAmbiguous())
+ return true;
+
NamedDecl *PrevDecl = 0;
if (Previous.begin() != Previous.end())
- PrevDecl = *Previous.begin();
+ PrevDecl = (*Previous.begin())->getUnderlyingDecl();
// If there is a previous declaration with the same name, check
// whether this is a valid redeclaration.
@@ -779,22 +801,24 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// declared as a friend, and when the name of the friend class or
// function is neither a qualified name nor a template-id, scopes outside
// the innermost enclosing namespace scope are not considered.
- DeclContext *OutermostContext = CurContext;
- while (!OutermostContext->isFileContext())
- OutermostContext = OutermostContext->getLookupParent();
-
- if (PrevDecl &&
- (OutermostContext->Equals(PrevDecl->getDeclContext()) ||
- OutermostContext->Encloses(PrevDecl->getDeclContext()))) {
- SemanticContext = PrevDecl->getDeclContext();
- } else {
- // Declarations in outer scopes don't matter. However, the outermost
- // context we computed is the semantic context for our new
- // declaration.
- PrevDecl = PrevClassTemplate = 0;
- SemanticContext = OutermostContext;
+ if (!SS.isSet()) {
+ DeclContext *OutermostContext = CurContext;
+ while (!OutermostContext->isFileContext())
+ OutermostContext = OutermostContext->getLookupParent();
+
+ if (PrevDecl &&
+ (OutermostContext->Equals(PrevDecl->getDeclContext()) ||
+ OutermostContext->Encloses(PrevDecl->getDeclContext()))) {
+ SemanticContext = PrevDecl->getDeclContext();
+ } else {
+ // Declarations in outer scopes don't matter. However, the outermost
+ // context we computed is the semantic context for our new
+ // declaration.
+ PrevDecl = PrevClassTemplate = 0;
+ SemanticContext = OutermostContext;
+ }
}
-
+
if (CurContext->isDependentContext()) {
// If this is a dependent context, we don't want to link the friend
// class template to the template in scope, because that would perform
@@ -804,7 +828,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
} else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S))
PrevDecl = PrevClassTemplate = 0;
-
+
if (PrevClassTemplate) {
// Ensure that the template parameter lists are compatible.
if (!TemplateParameterListsAreEqual(TemplateParams,
@@ -861,9 +885,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
TPC_ClassTemplate))
Invalid = true;
- // FIXME: If we had a scope specifier, we better have a previous template
- // declaration!
-
+ if (SS.isSet()) {
+ // If the name of the template was qualified, we must be defining the
+ // template out-of-line.
+ if (!SS.isInvalid() && !Invalid && !PrevClassTemplate &&
+ !(TUK == TUK_Friend && CurContext->isDependentContext()))
+ Diag(NameLoc, diag::err_member_def_does_not_match)
+ << Name << SemanticContext << SS.getRange();
+ }
+
CXXRecordDecl *NewClass =
CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc,
PrevClassTemplate?
@@ -1206,6 +1236,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
///
/// \param NumParamLists the number of template parameter lists in ParamLists.
///
+/// \param IsFriend Whether to apply the slightly different rules for
+/// matching template parameters to scope specifiers in friend
+/// declarations.
+///
/// \param IsExplicitSpecialization will be set true if the entity being
/// declared is an explicit specialization, false otherwise.
///
@@ -1220,6 +1254,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
const CXXScopeSpec &SS,
TemplateParameterList **ParamLists,
unsigned NumParamLists,
+ bool IsFriend,
bool &IsExplicitSpecialization) {
IsExplicitSpecialization = false;
@@ -1285,6 +1320,13 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
if (Idx >= NumParamLists) {
// We have a template-id without a corresponding template parameter
// list.
+
+ // ...which is fine if this is a friend declaration.
+ if (IsFriend) {
+ IsExplicitSpecialization = true;
+ break;
+ }
+
if (DependentTemplateId) {
// FIXME: the location information here isn't great.
Diag(SS.getRange().getBegin(),
@@ -1302,27 +1344,25 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// Check the template parameter list against its corresponding template-id.
if (DependentTemplateId) {
- TemplateDecl *Template
- = TemplateIdsInSpecifier[Idx]->getTemplateName().getAsTemplateDecl();
-
- if (ClassTemplateDecl *ClassTemplate
- = dyn_cast<ClassTemplateDecl>(Template)) {
- TemplateParameterList *ExpectedTemplateParams = 0;
- // Is this template-id naming the primary template?
- if (Context.hasSameType(TemplateId,
- ClassTemplate->getInjectedClassNameSpecialization(Context)))
- ExpectedTemplateParams = ClassTemplate->getTemplateParameters();
- // ... or a partial specialization?
- else if (ClassTemplatePartialSpecializationDecl *PartialSpec
- = ClassTemplate->findPartialSpecialization(TemplateId))
- ExpectedTemplateParams = PartialSpec->getTemplateParameters();
-
- if (ExpectedTemplateParams)
- TemplateParameterListsAreEqual(ParamLists[Idx],
- ExpectedTemplateParams,
- true, TPL_TemplateMatch);
+ TemplateParameterList *ExpectedTemplateParams = 0;
+
+ // Are there cases in (e.g.) friends where this won't match?
+ if (const InjectedClassNameType *Injected
+ = TemplateId->getAs<InjectedClassNameType>()) {
+ CXXRecordDecl *Record = Injected->getDecl();
+ if (ClassTemplatePartialSpecializationDecl *Partial =
+ dyn_cast<ClassTemplatePartialSpecializationDecl>(Record))
+ ExpectedTemplateParams = Partial->getTemplateParameters();
+ else
+ ExpectedTemplateParams = Record->getDescribedClassTemplate()
+ ->getTemplateParameters();
}
+ if (ExpectedTemplateParams)
+ TemplateParameterListsAreEqual(ParamLists[Idx],
+ ExpectedTemplateParams,
+ true, TPL_TemplateMatch);
+
CheckTemplateParameterList(ParamLists[Idx], 0, TPC_ClassTemplateMember);
} else if (ParamLists[Idx]->size() > 0)
Diag(ParamLists[Idx]->getTemplateLoc(),
@@ -1388,6 +1428,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
"Converted template argument list is too short!");
QualType CanonType;
+ bool IsCurrentInstantiation = false;
if (Name.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments(
@@ -1409,6 +1450,45 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// In the future, we need to teach getTemplateSpecializationType to only
// build the canonical type and return that to us.
CanonType = Context.getCanonicalType(CanonType);
+
+ // This might work out to be a current instantiation, in which
+ // case the canonical type needs to be the InjectedClassNameType.
+ //
+ // TODO: in theory this could be a simple hashtable lookup; most
+ // changes to CurContext don't change the set of current
+ // instantiations.
+ if (isa<ClassTemplateDecl>(Template)) {
+ for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) {
+ // If we get out to a namespace, we're done.
+ if (Ctx->isFileContext()) break;
+
+ // If this isn't a record, keep looking.
+ CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx);
+ if (!Record) continue;
+
+ // Look for one of the two cases with InjectedClassNameTypes
+ // and check whether it's the same template.
+ if (!isa<ClassTemplatePartialSpecializationDecl>(Record) &&
+ !Record->getDescribedClassTemplate())
+ continue;
+
+ // Fetch the injected class name type and check whether its
+ // injected type is equal to the type we just built.
+ QualType ICNT = Context.getTypeDeclType(Record);
+ QualType Injected = cast<InjectedClassNameType>(ICNT)
+ ->getInjectedSpecializationType();
+
+ if (CanonType != Injected->getCanonicalTypeInternal())
+ continue;
+
+ // If so, the canonical type of this TST is the injected
+ // class name type of the record we just found.
+ assert(ICNT.isCanonical());
+ CanonType = ICNT;
+ IsCurrentInstantiation = true;
+ break;
+ }
+ }
} else if (ClassTemplateDecl *ClassTemplate
= dyn_cast<ClassTemplateDecl>(Template)) {
// Find the class template specialization declaration that
@@ -1442,7 +1522,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// Build the fully-sugared type for this class template
// specialization, which refers back to the class template
// specialization we created or found.
- return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType);
+ return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType,
+ IsCurrentInstantiation);
}
Action::TypeResult
@@ -1545,14 +1626,14 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
// We actually only call this from template instantiation.
Sema::OwningExprResult
-Sema::BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS,
+Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
DeclarationName Name,
SourceLocation NameLoc,
const TemplateArgumentListInfo &TemplateArgs) {
DeclContext *DC;
if (!(DC = computeDeclContext(SS, false)) ||
DC->isDependentContext() ||
- RequireCompleteDeclContext(SS))
+ RequireCompleteDeclContext(SS, DC))
return BuildDependentDeclRefExpr(SS, Name, NameLoc, &TemplateArgs);
LookupResult R(*this, Name, NameLoc, LookupOrdinaryName);
@@ -1586,7 +1667,7 @@ Sema::BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS,
/// of the "template" keyword, and "apply" is the \p Name.
Sema::TemplateTy
Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext) {
@@ -1663,11 +1744,25 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
const TemplateArgument &Arg = AL.getArgument();
// Check template type parameter.
- if (Arg.getKind() != TemplateArgument::Type) {
+ switch(Arg.getKind()) {
+ case TemplateArgument::Type:
// C++ [temp.arg.type]p1:
// A template-argument for a template-parameter which is a
// type shall be a type-id.
+ break;
+ case TemplateArgument::Template: {
+ // We have a template type parameter but the template argument
+ // is a template without any arguments.
+ SourceRange SR = AL.getSourceRange();
+ TemplateName Name = Arg.getAsTemplate();
+ Diag(SR.getBegin(), diag::err_template_missing_args)
+ << Name << SR;
+ if (TemplateDecl *Decl = Name.getAsTemplateDecl())
+ Diag(Decl->getLocation(), diag::note_template_decl_here);
+ return true;
+ }
+ default: {
// We have a template type parameter but the template argument
// is not a type.
SourceRange SR = AL.getSourceRange();
@@ -1676,6 +1771,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
return true;
}
+ }
if (CheckTemplateArgument(Param, AL.getTypeSourceInfo()))
return true;
@@ -2317,14 +2413,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
DRE = dyn_cast<DeclRefExpr>(Arg);
if (!DRE) {
- if (S.Context.hasSameUnqualifiedType(ArgType, S.Context.OverloadTy)) {
- S.Diag(Arg->getLocStart(),
- diag::err_template_arg_unresolved_overloaded_function)
- << ParamType << Arg->getSourceRange();
- } else {
- S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
- << Arg->getSourceRange();
- }
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
+ << Arg->getSourceRange();
S.Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
@@ -2525,6 +2615,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// Create the template argument.
Converted = TemplateArgument(Entity->getCanonicalDecl());
+ S.MarkDeclarationReferenced(Arg->getLocStart(), Entity);
return false;
}
@@ -2797,16 +2888,19 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
ParamType->getAs<MemberPointerType>()->getPointeeType()
->isFunctionType())) {
- if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType,
- true,
- FoundResult)) {
- if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
- return true;
+ if (Arg->getType() == Context.OverloadTy) {
+ if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType,
+ true,
+ FoundResult)) {
+ if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
+ return true;
- Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
- ArgType = Arg->getType();
+ Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
+ ArgType = Arg->getType();
+ } else
+ return true;
}
-
+
if (!ParamType->isMemberPointerType())
return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
ParamType,
@@ -2851,17 +2945,20 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
assert(ParamRefType->getPointeeType()->isObjectType() &&
"Only object references allowed here");
- if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg,
- ParamRefType->getPointeeType(),
- true,
- FoundResult)) {
- if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
- return true;
+ if (Arg->getType() == Context.OverloadTy) {
+ if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg,
+ ParamRefType->getPointeeType(),
+ true,
+ FoundResult)) {
+ if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
+ return true;
- Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
- ArgType = Arg->getType();
+ Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
+ ArgType = Arg->getType();
+ } else
+ return true;
}
-
+
return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
ParamType,
Arg, Converted);
@@ -2964,9 +3061,21 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
return ExprError();
RefExpr = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(RefExpr));
+
+ // We might need to perform a trailing qualification conversion, since
+ // the element type on the parameter could be more qualified than the
+ // element type in the expression we constructed.
+ if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(),
+ ParamType.getUnqualifiedType())) {
+ Expr *RefE = RefExpr.takeAs<Expr>();
+ ImpCastExprToType(RefE, ParamType.getUnqualifiedType(),
+ CastExpr::CK_NoOp);
+ RefExpr = Owned(RefE);
+ }
+
assert(!RefExpr.isInvalid() &&
Context.hasSameType(((Expr*) RefExpr.get())->getType(),
- ParamType));
+ ParamType.getUnqualifiedType()));
return move(RefExpr);
}
}
@@ -3467,7 +3576,7 @@ Sema::DeclResult
Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TagUseKind TUK,
SourceLocation KWLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
TemplateTy TemplateD,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
@@ -3500,6 +3609,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
= MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
(TemplateParameterList**)TemplateParameterLists.get(),
TemplateParameterLists.size(),
+ TUK == TUK_Friend,
isExplicitSpecialization);
if (TemplateParams && TemplateParams->size() > 0) {
isPartialSpecialization = true;
@@ -3683,6 +3793,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Create a new class template partial specialization declaration node.
ClassTemplatePartialSpecializationDecl *PrevPartial
= cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl);
+ unsigned SequenceNumber = PrevPartial? PrevPartial->getSequenceNumber()
+ : ClassTemplate->getPartialSpecializations().size();
ClassTemplatePartialSpecializationDecl *Partial
= ClassTemplatePartialSpecializationDecl::Create(Context,
ClassTemplate->getDeclContext(),
@@ -3692,7 +3804,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
Converted,
TemplateArgs,
CanonType,
- PrevPartial);
+ PrevPartial,
+ SequenceNumber);
SetNestedNameSpecifier(Partial, SS);
if (PrevPartial) {
@@ -4032,7 +4145,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
// instantiation has no effect.
//
// In C++98/03 mode, we only give an extension warning here, because it
- // is not not harmful to try to explicitly instantiate something that
+ // is not harmful to try to explicitly instantiate something that
// has been explicitly specialized.
if (!getLangOptions().CPlusPlus0x) {
Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization)
@@ -4068,6 +4181,42 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
return false;
}
+/// \brief Perform semantic analysis for the given dependent function
+/// template specialization. The only possible way to get a dependent
+/// function template specialization is with a friend declaration,
+/// like so:
+///
+/// template <class T> void foo(T);
+/// template <class T> class A {
+/// friend void foo<>(T);
+/// };
+///
+/// There really isn't any useful analysis we can do here, so we
+/// just store the information.
+bool
+Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
+ const TemplateArgumentListInfo &ExplicitTemplateArgs,
+ LookupResult &Previous) {
+ // Remove anything from Previous that isn't a function template in
+ // the correct context.
+ DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext();
+ LookupResult::Filter F = Previous.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next()->getUnderlyingDecl();
+ if (!isa<FunctionTemplateDecl>(D) ||
+ !FDLookupContext->Equals(D->getDeclContext()->getLookupContext()))
+ F.erase();
+ }
+ F.done();
+
+ // Should this be diagnosed here?
+ if (Previous.empty()) return true;
+
+ FD->setDependentTemplateSpecialization(Context, Previous.asUnresolvedSet(),
+ ExplicitTemplateArgs);
+ return false;
+}
+
/// \brief Perform semantic analysis for the given function template
/// specialization.
///
@@ -4153,6 +4302,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Ignore access information; it doesn't figure into redeclaration checking.
FunctionDecl *Specialization = cast<FunctionDecl>(*Result);
+ Specialization->setLocation(FD->getLocation());
// FIXME: Check if the prior specialization has a point of instantiation.
// If so, we have run afoul of .
@@ -4227,7 +4377,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
bool
Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
assert(!isa<TemplateDecl>(Member) && "Only for non-template members");
-
+
// Try to find the member we are instantiating.
NamedDecl *Instantiation = 0;
NamedDecl *InstantiatedFrom = 0;
@@ -4273,6 +4423,25 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
// this mismatch later.
return false;
}
+
+ // If this is a friend, just bail out here before we start turning
+ // things into explicit specializations.
+ if (Member->getFriendObjectKind() != Decl::FOK_None) {
+ // Preserve instantiation information.
+ if (InstantiatedFrom && isa<CXXMethodDecl>(Member)) {
+ cast<CXXMethodDecl>(Member)->setInstantiationOfMemberFunction(
+ cast<CXXMethodDecl>(InstantiatedFrom),
+ cast<CXXMethodDecl>(Instantiation)->getTemplateSpecializationKind());
+ } else if (InstantiatedFrom && isa<CXXRecordDecl>(Member)) {
+ cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
+ cast<CXXRecordDecl>(InstantiatedFrom),
+ cast<CXXRecordDecl>(Instantiation)->getTemplateSpecializationKind());
+ }
+
+ Previous.clear();
+ Previous.addDecl(Instantiation);
+ return false;
+ }
// Make sure that this is a specialization of a member.
if (!InstantiatedFrom) {
@@ -4612,7 +4781,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
SourceLocation TemplateLoc,
unsigned TagSpec,
SourceLocation KWLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
IdentifierInfo *Name,
SourceLocation NameLoc,
AttributeList *Attr) {
@@ -5001,9 +5170,30 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
assert(Keyword != ETK_None && "Invalid tag kind!");
+ if (TUK == TUK_Declaration || TUK == TUK_Definition) {
+ Diag(NameLoc, diag::err_dependent_tag_decl)
+ << (TUK == TUK_Definition) << TagDecl::getTagKindForTypeSpec(TagSpec)
+ << SS.getRange();
+ return true;
+ }
+
return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr();
}
+static void FillTypeLoc(DependentNameTypeLoc TL,
+ SourceLocation TypenameLoc,
+ SourceRange QualifierRange) {
+ // FIXME: typename, qualifier range
+ TL.setNameLoc(TypenameLoc);
+}
+
+static void FillTypeLoc(QualifiedNameTypeLoc TL,
+ SourceLocation TypenameLoc,
+ SourceRange QualifierRange) {
+ // FIXME: typename, qualifier range
+ TL.setNameLoc(TypenameLoc);
+}
+
Sema::TypeResult
Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
const IdentifierInfo &II, SourceLocation IdLoc) {
@@ -5012,10 +5202,23 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
if (!NNS)
return true;
- QualType T = CheckTypenameType(NNS, II, SourceRange(TypenameLoc, IdLoc));
+ QualType T = CheckTypenameType(ETK_Typename, NNS, II,
+ SourceRange(TypenameLoc, IdLoc));
if (T.isNull())
return true;
- return T.getAsOpaquePtr();
+
+ TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
+ if (isa<DependentNameType>(T)) {
+ DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
+ // FIXME: fill inner type loc
+ FillTypeLoc(TL, TypenameLoc, SS.getRange());
+ } else {
+ QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc());
+ // FIXME: fill inner type loc
+ FillTypeLoc(TL, TypenameLoc, SS.getRange());
+ }
+
+ return CreateLocInfoType(T, TSI).getAsOpaquePtr();
}
Sema::TypeResult
@@ -5034,48 +5237,49 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
// track of the nested-name-specifier.
// FIXME: Note that the QualifiedNameType had the "typename" keyword!
- return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
+
+ T = Context.getQualifiedNameType(NNS, T);
+ TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
+ QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc());
+ // FIXME: fill inner type loc
+ FillTypeLoc(TL, TypenameLoc, SS.getRange());
+ return CreateLocInfoType(T, TSI).getAsOpaquePtr();
}
- return Context.getDependentNameType(ETK_Typename, NNS, TemplateId)
- .getAsOpaquePtr();
+ T = Context.getDependentNameType(ETK_Typename, NNS, TemplateId);
+ TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
+ DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
+ // FIXME: fill inner type loc
+ FillTypeLoc(TL, TypenameLoc, SS.getRange());
+ return CreateLocInfoType(T, TSI).getAsOpaquePtr();
}
/// \brief Build the type that describes a C++ typename specifier,
/// e.g., "typename T::type".
QualType
-Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
+Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS, const IdentifierInfo &II,
SourceRange Range) {
- CXXRecordDecl *CurrentInstantiation = 0;
- if (NNS->isDependent()) {
- CurrentInstantiation = getCurrentInstantiationOf(NNS);
-
- // If the nested-name-specifier does not refer to the current
- // instantiation, then build a typename type.
- if (!CurrentInstantiation)
- return Context.getDependentNameType(ETK_Typename, NNS, &II);
-
- // The nested-name-specifier refers to the current instantiation, so the
- // "typename" keyword itself is superfluous. In C++03, the program is
- // actually ill-formed. However, DR 382 (in C++0x CD1) allows such
- // extraneous "typename" keywords, and we retroactively apply this DR to
- // C++03 code.
+ CXXScopeSpec SS;
+ SS.setScopeRep(NNS);
+ SS.setRange(Range);
+
+ DeclContext *Ctx = computeDeclContext(SS);
+ if (!Ctx) {
+ // If the nested-name-specifier is dependent and couldn't be
+ // resolved to a type, build a typename type.
+ assert(NNS->isDependent());
+ return Context.getDependentNameType(Keyword, NNS, &II);
}
- DeclContext *Ctx = 0;
+ // If the nested-name-specifier refers to the current instantiation,
+ // the "typename" keyword itself is superfluous. In C++03, the
+ // program is actually ill-formed. However, DR 382 (in C++0x CD1)
+ // allows such extraneous "typename" keywords, and we retroactively
+ // apply this DR to C++03 code. In any case we continue.
- if (CurrentInstantiation)
- Ctx = CurrentInstantiation;
- else {
- CXXScopeSpec SS;
- SS.setScopeRep(NNS);
- SS.setRange(Range);
- if (RequireCompleteDeclContext(SS))
- return QualType();
-
- Ctx = computeDeclContext(SS);
- }
- assert(Ctx && "No declaration context?");
+ if (RequireCompleteDeclContext(SS, Ctx))
+ return QualType();
DeclarationName Name(&II);
LookupResult Result(*this, Name, Range.getEnd(), LookupOrdinaryName);
@@ -5089,7 +5293,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
case LookupResult::NotFoundInCurrentInstantiation:
// Okay, it's a member of an unknown instantiation.
- return Context.getDependentNameType(ETK_Typename, NNS, &II);
+ return Context.getDependentNameType(Keyword, NNS, &II);
case LookupResult::Found:
if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
@@ -5133,6 +5337,8 @@ namespace {
DeclarationName Entity;
public:
+ typedef TreeTransform<CurrentInstantiationRebuilder> inherited;
+
CurrentInstantiationRebuilder(Sema &SemaRef,
SourceLocation Loc,
DeclarationName Entity)
@@ -5168,7 +5374,7 @@ namespace {
/// FIXME: This is completely unsafe; we will need to actually clone the
/// expressions.
Sema::OwningExprResult TransformExpr(Expr *E) {
- return getSema().Owned(E);
+ return getSema().Owned(E->Retain());
}
/// \brief Transforms a typename type by determining whether the type now
@@ -5256,15 +5462,30 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
/// in X<T> and returning a QualifiedNameType whose canonical type is the same
/// as the canonical type of T*, allowing the return types of the out-of-line
/// definition and the declaration to match.
-QualType Sema::RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc,
- DeclarationName Name) {
- if (T.isNull() || !T->isDependentType())
+TypeSourceInfo *Sema::RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
+ SourceLocation Loc,
+ DeclarationName Name) {
+ if (!T || !T->getType()->isDependentType())
return T;
CurrentInstantiationRebuilder Rebuilder(*this, Loc, Name);
return Rebuilder.TransformType(T);
}
+bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) {
+ if (SS.isInvalid()) return true;
+
+ NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+ CurrentInstantiationRebuilder Rebuilder(*this, SS.getRange().getBegin(),
+ DeclarationName());
+ NestedNameSpecifier *Rebuilt =
+ Rebuilder.TransformNestedNameSpecifier(NNS, SS.getRange());
+ if (!Rebuilt) return true;
+
+ SS.setScopeRep(Rebuilt);
+ return false;
+}
+
/// \brief Produces a formatted string that describes the binding of
/// template parameters to template arguments.
std::string
@@ -5344,8 +5565,15 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
}
case TemplateArgument::Expression: {
- assert(false && "No expressions in deduced template arguments!");
- Result += "<expression>";
+ // FIXME: This is non-optimal, since we're regurgitating the
+ // expression we were given.
+ std::string Str;
+ {
+ llvm::raw_string_ostream OS(Str);
+ Args[I].getAsExpr()->printPretty(OS, Context, 0,
+ Context.PrintingPolicy);
+ }
+ Result += Str;
break;
}
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index d61a767..2bb97eb 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -638,7 +638,8 @@ DeduceTemplateArguments(Sema &S,
case Type::InjectedClassName: {
// Treat a template's injected-class-name as if the template
// specialization type had been used.
- Param = cast<InjectedClassNameType>(Param)->getUnderlyingType();
+ Param = cast<InjectedClassNameType>(Param)
+ ->getInjectedSpecializationType();
assert(isa<TemplateSpecializationType>(Param) &&
"injected class name is not a template specialization type");
// fall through
@@ -960,32 +961,18 @@ static TemplateParameter makeTemplateParameter(Decl *D) {
return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
}
-/// \brief Perform template argument deduction to determine whether
-/// the given template arguments match the given class template
-/// partial specialization per C++ [temp.class.spec.match].
-Sema::TemplateDeductionResult
-Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
- const TemplateArgumentList &TemplateArgs,
- TemplateDeductionInfo &Info) {
- // C++ [temp.class.spec.match]p2:
- // A partial specialization matches a given actual template
- // argument list if the template arguments of the partial
- // specialization can be deduced from the actual template argument
- // list (14.8.2).
- SFINAETrap Trap(*this);
- llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
- Deduced.resize(Partial->getTemplateParameters()->size());
- if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(*this,
- Partial->getTemplateParameters(),
- Partial->getTemplateArgs(),
- TemplateArgs, Info, Deduced))
- return Result;
-
- InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial,
- Deduced.data(), Deduced.size());
- if (Inst)
- return TDK_InstantiationDepth;
+/// Complete template argument deduction for a class template partial
+/// specialization.
+static Sema::TemplateDeductionResult
+FinishTemplateArgumentDeduction(Sema &S,
+ ClassTemplatePartialSpecializationDecl *Partial,
+ const TemplateArgumentList &TemplateArgs,
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ Sema::TemplateDeductionInfo &Info) {
+ // Trap errors.
+ Sema::SFINAETrap Trap(S);
+
+ Sema::ContextRAII SavedContext(S, Partial);
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
@@ -995,18 +982,19 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
if (Deduced[I].isNull()) {
Decl *Param
- = const_cast<NamedDecl *>(
+ = const_cast<NamedDecl *>(
Partial->getTemplateParameters()->getParam(I));
Info.Param = makeTemplateParameter(Param);
- return TDK_Incomplete;
+ return Sema::TDK_Incomplete;
}
-
+
Builder.Append(Deduced[I]);
}
-
+
// Form the template argument list from the deduced template arguments.
TemplateArgumentList *DeducedArgumentList
- = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
+ = new (S.Context) TemplateArgumentList(S.Context, Builder,
+ /*TakeArgs=*/true);
Info.reset(DeducedArgumentList);
// Substitute the deduced template arguments into the template
@@ -1016,7 +1004,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
// to the class template.
// FIXME: Do we have to correct the types of deduced non-type template
// arguments (in particular, integral non-type template arguments?).
- Sema::LocalInstantiationScope InstScope(*this);
+ Sema::LocalInstantiationScope InstScope(S);
ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate();
const TemplateArgumentLoc *PartialTemplateArgs
= Partial->getTemplateArgsAsWritten();
@@ -1029,11 +1017,11 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
Decl *Param = const_cast<NamedDecl *>(
ClassTemplate->getTemplateParameters()->getParam(I));
TemplateArgumentLoc InstArg;
- if (Subst(PartialTemplateArgs[I], InstArg,
- MultiLevelTemplateArgumentList(*DeducedArgumentList))) {
+ if (S.Subst(PartialTemplateArgs[I], InstArg,
+ MultiLevelTemplateArgumentList(*DeducedArgumentList))) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = PartialTemplateArgs[I].getArgument();
- return TDK_SubstitutionFailure;
+ return Sema::TDK_SubstitutionFailure;
}
InstArgs.addArgument(InstArg);
}
@@ -1041,10 +1029,10 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
TemplateArgumentListBuilder ConvertedInstArgs(
ClassTemplate->getTemplateParameters(), N);
- if (CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(),
+ if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(),
InstArgs, false, ConvertedInstArgs)) {
// FIXME: fail with more useful information?
- return TDK_SubstitutionFailure;
+ return Sema::TDK_SubstitutionFailure;
}
for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) {
@@ -1060,26 +1048,60 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
Expr *InstExpr = InstArg.getAsExpr();
if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
- if (CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) {
+ if (S.CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = Partial->getTemplateArgs()[I];
- return TDK_SubstitutionFailure;
+ return Sema::TDK_SubstitutionFailure;
}
}
}
- if (!isSameTemplateArg(Context, TemplateArgs[I], InstArg)) {
+ if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = TemplateArgs[I];
Info.SecondArg = InstArg;
- return TDK_NonDeducedMismatch;
+ return Sema::TDK_NonDeducedMismatch;
}
}
if (Trap.hasErrorOccurred())
- return TDK_SubstitutionFailure;
+ return Sema::TDK_SubstitutionFailure;
- return TDK_Success;
+ return Sema::TDK_Success;
+}
+
+/// \brief Perform template argument deduction to determine whether
+/// the given template arguments match the given class template
+/// partial specialization per C++ [temp.class.spec.match].
+Sema::TemplateDeductionResult
+Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
+ const TemplateArgumentList &TemplateArgs,
+ TemplateDeductionInfo &Info) {
+ // C++ [temp.class.spec.match]p2:
+ // A partial specialization matches a given actual template
+ // argument list if the template arguments of the partial
+ // specialization can be deduced from the actual template argument
+ // list (14.8.2).
+ SFINAETrap Trap(*this);
+ llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
+ Deduced.resize(Partial->getTemplateParameters()->size());
+ if (TemplateDeductionResult Result
+ = ::DeduceTemplateArguments(*this,
+ Partial->getTemplateParameters(),
+ Partial->getTemplateArgs(),
+ TemplateArgs, Info, Deduced))
+ return Result;
+
+ InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial,
+ Deduced.data(), Deduced.size());
+ if (Inst)
+ return TDK_InstantiationDepth;
+
+ if (Trap.hasErrorOccurred())
+ return Sema::TDK_SubstitutionFailure;
+
+ return ::FinishTemplateArgumentDeduction(*this, Partial, TemplateArgs,
+ Deduced, Info);
}
/// \brief Determine whether the given type T is a simple-template-id type.
@@ -1162,6 +1184,8 @@ Sema::SubstituteExplicitTemplateArguments(
if (Inst)
return TDK_InstantiationDepth;
+ ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl());
+
if (CheckTemplateArgumentList(FunctionTemplate,
SourceLocation(),
ExplicitTemplateArgs,
@@ -1310,6 +1334,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
if (Inst)
return TDK_InstantiationDepth;
+ ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl());
+
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
@@ -1416,9 +1442,11 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// Substitute the deduced template arguments into the function template
// declaration to produce the function template specialization.
+ DeclContext *Owner = FunctionTemplate->getDeclContext();
+ if (FunctionTemplate->getFriendObjectKind())
+ Owner = FunctionTemplate->getLexicalDeclContext();
Specialization = cast_or_null<FunctionDecl>(
- SubstDecl(FunctionTemplate->getTemplatedDecl(),
- FunctionTemplate->getDeclContext(),
+ SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner,
MultiLevelTemplateArgumentList(*DeducedArgumentList)));
if (!Specialization)
return TDK_SubstitutionFailure;
@@ -2332,35 +2360,49 @@ Sema::getMoreSpecializedPartialSpecialization(
// whose type is a class template specialization with the template
// arguments of the second partial specialization.
//
- // Rather than synthesize function templates, we merely perform the
- // equivalent partial ordering by performing deduction directly on the
- // template arguments of the class template partial specializations. This
- // computation is slightly simpler than the general problem of function
- // template partial ordering, because class template partial specializations
- // are more constrained. We know that every template parameter is deduc
+ // Rather than synthesize function templates, we merely perform the
+ // equivalent partial ordering by performing deduction directly on
+ // the template arguments of the class template partial
+ // specializations. This computation is slightly simpler than the
+ // general problem of function template partial ordering, because
+ // class template partial specializations are more constrained. We
+ // know that every template parameter is deducible from the class
+ // template partial specialization's template arguments, for
+ // example.
llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
Sema::TemplateDeductionInfo Info(Context, Loc);
+
+ QualType PT1 = PS1->getInjectedSpecializationType();
+ QualType PT2 = PS2->getInjectedSpecializationType();
// Determine whether PS1 is at least as specialized as PS2
Deduced.resize(PS2->getTemplateParameters()->size());
bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(*this,
PS2->getTemplateParameters(),
- Context.getTypeDeclType(PS2),
- Context.getTypeDeclType(PS1),
+ PT2,
+ PT1,
Info,
Deduced,
0);
-
+ if (Better1)
+ Better1 = !::FinishTemplateArgumentDeduction(*this, PS2,
+ PS1->getTemplateArgs(),
+ Deduced, Info);
+
// Determine whether PS2 is at least as specialized as PS1
Deduced.clear();
Deduced.resize(PS1->getTemplateParameters()->size());
bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(*this,
PS1->getTemplateParameters(),
- Context.getTypeDeclType(PS1),
- Context.getTypeDeclType(PS2),
+ PT1,
+ PT2,
Info,
Deduced,
0);
+ if (Better2)
+ Better2 = !::FinishTemplateArgumentDeduction(*this, PS1,
+ PS2->getTemplateArgs(),
+ Deduced, Info);
if (Better1 == Better2)
return 0;
@@ -2537,6 +2579,10 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
break;
}
+ case Type::InjectedClassName:
+ T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType();
+ // fall through
+
case Type::TemplateSpecialization: {
const TemplateSpecializationType *Spec
= cast<TemplateSpecializationType>(T);
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index d21862b..14bd243 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -38,10 +38,16 @@ using namespace clang;
/// arguments relative to the primary template, even when we're
/// dealing with a specialization. This is only relevant for function
/// template specializations.
+///
+/// \param Pattern If non-NULL, indicates the pattern from which we will be
+/// instantiating the definition of the given declaration, \p D. This is
+/// used to determine the proper set of template instantiation arguments for
+/// friend function template specializations.
MultiLevelTemplateArgumentList
Sema::getTemplateInstantiationArgs(NamedDecl *D,
const TemplateArgumentList *Innermost,
- bool RelativeToPrimary) {
+ bool RelativeToPrimary,
+ const FunctionDecl *Pattern) {
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
@@ -89,9 +95,11 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
// If this is a friend declaration and it declares an entity at
// namespace scope, take arguments from its lexical parent
- // instead of its semantic parent.
+ // instead of its semantic parent, unless of course the pattern we're
+ // instantiating actually comes from the file's context!
if (Function->getFriendObjectKind() &&
- Function->getDeclContext()->isFileContext()) {
+ Function->getDeclContext()->isFileContext() &&
+ (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
Ctx = Function->getLexicalDeclContext();
RelativeToPrimary = false;
continue;
@@ -339,12 +347,32 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
/// \brief Prints the current instantiation stack through a series of
/// notes.
void Sema::PrintInstantiationStack() {
+ // Determine which template instantiations to skip, if any.
+ unsigned SkipStart = ActiveTemplateInstantiations.size(), SkipEnd = SkipStart;
+ unsigned Limit = Diags.getTemplateBacktraceLimit();
+ if (Limit && Limit < ActiveTemplateInstantiations.size()) {
+ SkipStart = Limit / 2 + Limit % 2;
+ SkipEnd = ActiveTemplateInstantiations.size() - Limit / 2;
+ }
+
// FIXME: In all of these cases, we need to show the template arguments
+ unsigned InstantiationIdx = 0;
for (llvm::SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator
Active = ActiveTemplateInstantiations.rbegin(),
ActiveEnd = ActiveTemplateInstantiations.rend();
Active != ActiveEnd;
- ++Active) {
+ ++Active, ++InstantiationIdx) {
+ // Skip this instantiation?
+ if (InstantiationIdx >= SkipStart && InstantiationIdx < SkipEnd) {
+ if (InstantiationIdx == SkipStart) {
+ // Note that we're skipping instantiations.
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ diag::note_instantiation_contexts_suppressed)
+ << unsigned(ActiveTemplateInstantiations.size() - Limit);
+ }
+ continue;
+ }
+
switch (Active->Kind) {
case ActiveTemplateInstantiation::TemplateInstantiation: {
Decl *D = reinterpret_cast<Decl *>(Active->Entity);
@@ -512,8 +540,7 @@ bool Sema::isSFINAEContext() const {
// Template Instantiation for Types
//===----------------------------------------------------------------------===/
namespace {
- class TemplateInstantiator
- : public TreeTransform<TemplateInstantiator> {
+ class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
const MultiLevelTemplateArgumentList &TemplateArgs;
SourceLocation Loc;
DeclarationName Entity;
@@ -569,6 +596,11 @@ namespace {
IdentifierInfo *Name,
SourceLocation Loc, SourceRange TypeRange);
+ /// \brief Rebuild the Objective-C exception declaration and register the
+ /// declaration as an instantiated local.
+ VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl,
+ TypeSourceInfo *TSInfo, QualType T);
+
/// \brief Check for tag mismatches when instantiating an
/// elaborated type.
QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag);
@@ -579,13 +611,9 @@ namespace {
Sema::OwningExprResult TransformTemplateParmRefExpr(DeclRefExpr *E,
NonTypeTemplateParmDecl *D);
- /// \brief Transforms a function proto type by performing
- /// substitution in the function parameters, possibly adjusting
- /// their types and marking default arguments as uninstantiated.
- bool TransformFunctionTypeParams(FunctionProtoTypeLoc TL,
- llvm::SmallVectorImpl<QualType> &PTypes,
- llvm::SmallVectorImpl<ParmVarDecl*> &PVars);
-
+ QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
+ FunctionProtoTypeLoc TL,
+ QualType ObjectType);
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm);
/// \brief Transforms a template type parameter type by performing
@@ -667,7 +695,16 @@ TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl,
SourceRange TypeRange) {
VarDecl *Var = inherited::RebuildExceptionDecl(ExceptionDecl, T, Declarator,
Name, Loc, TypeRange);
- if (Var && !Var->isInvalidDecl())
+ if (Var)
+ getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var);
+ return Var;
+}
+
+VarDecl *TemplateInstantiator::RebuildObjCExceptionDecl(VarDecl *ExceptionDecl,
+ TypeSourceInfo *TSInfo,
+ QualType T) {
+ VarDecl *Var = inherited::RebuildObjCExceptionDecl(ExceptionDecl, TSInfo, T);
+ if (Var)
getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var);
return Var;
}
@@ -791,63 +828,17 @@ Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr(
E->getParam());
}
-
-bool
-TemplateInstantiator::TransformFunctionTypeParams(FunctionProtoTypeLoc TL,
- llvm::SmallVectorImpl<QualType> &PTypes,
- llvm::SmallVectorImpl<ParmVarDecl*> &PVars) {
- // Create a local instantiation scope for the parameters.
- // FIXME: When we implement the C++0x late-specified return type,
- // we will need to move this scope out to the function type itself.
- bool IsTemporaryScope = (SemaRef.CurrentInstantiationScope != 0);
- Sema::LocalInstantiationScope Scope(SemaRef, IsTemporaryScope,
- IsTemporaryScope);
-
- if (TreeTransform<TemplateInstantiator>::
- TransformFunctionTypeParams(TL, PTypes, PVars))
- return true;
-
- // Check instantiated parameters.
- if (SemaRef.CheckInstantiatedParams(PVars))
- return true;
-
- return false;
+QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
+ FunctionProtoTypeLoc TL,
+ QualType ObjectType) {
+ // We need a local instantiation scope for this function prototype.
+ Sema::LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
+ return inherited::TransformFunctionProtoType(TLB, TL, ObjectType);
}
ParmVarDecl *
TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm) {
- TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
- TypeSourceInfo *NewDI = getDerived().TransformType(OldDI);
- if (!NewDI)
- return 0;
-
- // TODO: do we have to clone this decl if the types match and
- // there's no default argument?
-
- ParmVarDecl *NewParm
- = ParmVarDecl::Create(SemaRef.Context,
- OldParm->getDeclContext(),
- OldParm->getLocation(),
- OldParm->getIdentifier(),
- NewDI->getType(),
- NewDI,
- OldParm->getStorageClass(),
- /* DefArg */ NULL);
-
- // Maybe adjust new parameter type.
- NewParm->setType(SemaRef.adjustParameterType(NewParm->getType()));
-
- // Mark the (new) default argument as uninstantiated (if any).
- if (OldParm->hasUninstantiatedDefaultArg()) {
- Expr *Arg = OldParm->getUninstantiatedDefaultArg();
- NewParm->setUninstantiatedDefaultArg(Arg);
- } else if (Expr *Arg = OldParm->getDefaultArg())
- NewParm->setUninstantiatedDefaultArg(Arg);
-
- NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
-
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm);
- return NewParm;
+ return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs);
}
QualType
@@ -959,6 +950,91 @@ QualType Sema::SubstType(QualType T,
return Instantiator.TransformType(T);
}
+static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
+ if (T->getType()->isDependentType())
+ return true;
+
+ TypeLoc TL = T->getTypeLoc();
+ if (!isa<FunctionProtoTypeLoc>(TL))
+ return false;
+
+ FunctionProtoTypeLoc FP = cast<FunctionProtoTypeLoc>(TL);
+ for (unsigned I = 0, E = FP.getNumArgs(); I != E; ++I) {
+ ParmVarDecl *P = FP.getArg(I);
+
+ // TODO: currently we always rebuild expressions. When we
+ // properly get lazier about this, we should use the same
+ // logic to avoid rebuilding prototypes here.
+ if (P->hasInit())
+ return true;
+ }
+
+ return false;
+}
+
+/// A form of SubstType intended specifically for instantiating the
+/// type of a FunctionDecl. Its purpose is solely to force the
+/// instantiation of default-argument expressions.
+TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
+ const MultiLevelTemplateArgumentList &Args,
+ SourceLocation Loc,
+ DeclarationName Entity) {
+ assert(!ActiveTemplateInstantiations.empty() &&
+ "Cannot perform an instantiation without some context on the "
+ "instantiation stack");
+
+ if (!NeedsInstantiationAsFunctionType(T))
+ return T;
+
+ TemplateInstantiator Instantiator(*this, Args, Loc, Entity);
+
+ TypeLocBuilder TLB;
+
+ TypeLoc TL = T->getTypeLoc();
+ TLB.reserve(TL.getFullDataSize());
+
+ QualType Result = Instantiator.TransformType(TLB, TL, QualType());
+ if (Result.isNull())
+ return 0;
+
+ return TLB.getTypeSourceInfo(Context, Result);
+}
+
+ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
+ TypeSourceInfo *NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(),
+ OldParm->getDeclName());
+ if (!NewDI)
+ return 0;
+
+ if (NewDI->getType()->isVoidType()) {
+ Diag(OldParm->getLocation(), diag::err_param_with_void_type);
+ return 0;
+ }
+
+ ParmVarDecl *NewParm = CheckParameter(Context.getTranslationUnitDecl(),
+ NewDI, NewDI->getType(),
+ OldParm->getIdentifier(),
+ OldParm->getLocation(),
+ OldParm->getStorageClass(),
+ OldParm->getStorageClassAsWritten());
+ if (!NewParm)
+ return 0;
+
+ // Mark the (new) default argument as uninstantiated (if any).
+ if (OldParm->hasUninstantiatedDefaultArg()) {
+ Expr *Arg = OldParm->getUninstantiatedDefaultArg();
+ NewParm->setUninstantiatedDefaultArg(Arg);
+ } else if (Expr *Arg = OldParm->getDefaultArg())
+ NewParm->setUninstantiatedDefaultArg(Arg);
+
+ NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
+
+ CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm);
+ return NewParm;
+}
+
/// \brief Perform substitution on the base class specifiers of the
/// given class template specialization.
///
@@ -1083,8 +1159,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
- DeclContext *PreviousContext = CurContext;
- CurContext = Instantiation;
+ ContextRAII SavedContext(*this, Instantiation);
// If this is an instantiation of a local class, merge this local
// instantiation scope with the enclosing scope. Otherwise, every
@@ -1120,12 +1195,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
ActOnFields(0, Instantiation->getLocation(), DeclPtrTy::make(Instantiation),
Fields.data(), Fields.size(), SourceLocation(), SourceLocation(),
0);
- CheckCompletedCXXClass(Instantiation);
+ CheckCompletedCXXClass(/*Scope=*/0, Instantiation);
if (Instantiation->isInvalidDecl())
Invalid = true;
// Exit the scope of this instantiation.
- CurContext = PreviousContext;
+ SavedContext.pop();
// 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
@@ -1195,21 +1270,20 @@ Sema::InstantiateClassTemplateSpecialization(
typedef std::pair<ClassTemplatePartialSpecializationDecl *,
TemplateArgumentList *> MatchResult;
llvm::SmallVector<MatchResult, 4> Matched;
- for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
- Partial = Template->getPartialSpecializations().begin(),
- PartialEnd = Template->getPartialSpecializations().end();
- Partial != PartialEnd;
- ++Partial) {
+ llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+ Template->getPartialSpecializations(PartialSpecs);
+ for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
+ ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
TemplateDeductionInfo Info(Context, PointOfInstantiation);
if (TemplateDeductionResult Result
- = DeduceTemplateArguments(&*Partial,
+ = DeduceTemplateArguments(Partial,
ClassTemplateSpec->getTemplateArgs(),
Info)) {
// FIXME: Store the failed-deduction information for use in
// diagnostics, later.
(void)Result;
} else {
- Matched.push_back(std::make_pair(&*Partial, Info.take()));
+ Matched.push_back(std::make_pair(Partial, Info.take()));
}
}
@@ -1331,6 +1405,10 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
MemberSpecializationInfo *MSInfo
= Function->getMemberSpecializationInfo();
assert(MSInfo && "No member specialization information?");
+ if (MSInfo->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization)
+ continue;
+
if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK,
Function,
MSInfo->getTemplateSpecializationKind(),
@@ -1363,6 +1441,10 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
if (Var->isStaticDataMember()) {
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
assert(MSInfo && "No member specialization information?");
+ if (MSInfo->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization)
+ continue;
+
if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK,
Var,
MSInfo->getTemplateSpecializationKind(),
@@ -1389,11 +1471,19 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
}
}
} else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
- if (Record->isInjectedClassName())
+ // Always skip the injected-class-name, along with any
+ // redeclarations of nested classes, since both would cause us
+ // to try to instantiate the members of a class twice.
+ if (Record->isInjectedClassName() || Record->getPreviousDeclaration())
continue;
MemberSpecializationInfo *MSInfo = Record->getMemberSpecializationInfo();
assert(MSInfo && "No member specialization information?");
+
+ if (MSInfo->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization)
+ continue;
+
if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK,
Record,
MSInfo->getTemplateSpecializationKind(),
@@ -1502,3 +1592,29 @@ bool Sema::Subst(const TemplateArgumentLoc &Input, TemplateArgumentLoc &Output,
return Instantiator.TransformTemplateArgument(Input, Output);
}
+
+Decl *Sema::LocalInstantiationScope::getInstantiationOf(const Decl *D) {
+ for (LocalInstantiationScope *Current = this; Current;
+ Current = Current->Outer) {
+ // Check if we found something within this scope.
+ llvm::DenseMap<const Decl *, Decl *>::iterator Found
+ = Current->LocalDecls.find(D);
+ if (Found != Current->LocalDecls.end())
+ return Found->second;
+
+ // If we aren't combined with our outer scope, we're done.
+ if (!Current->CombineWithOuterScope)
+ break;
+ }
+
+ assert(D->isInvalidDecl() &&
+ "declaration was not instantiated in this scope!");
+ return 0;
+}
+
+void Sema::LocalInstantiationScope::InstantiatedLocal(const Decl *D,
+ Decl *Inst) {
+ Decl *&Stored = LocalDecls[D];
+ assert((!Stored || Stored == Inst)&& "Already instantiated this local");
+ Stored = Inst;
+}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 3375ccc..8b851b2 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -200,12 +200,22 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
if (Invalid)
Typedef->setInvalidDecl();
+ if (const TagType *TT = DI->getType()->getAs<TagType>()) {
+ TagDecl *TD = TT->getDecl();
+
+ // If the TagDecl that the TypedefDecl points to is an anonymous decl
+ // keep track of the TypedefDecl.
+ if (!TD->getIdentifier() && !TD->getTypedefForAnonDecl())
+ TD->setTypedefForAnonDecl(Typedef);
+ }
+
if (TypedefDecl *Prev = D->getPreviousDeclaration()) {
NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev,
TemplateArgs);
Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev));
}
+
Typedef->setAccess(D->getAccess());
Owner->addDecl(Typedef);
@@ -322,7 +332,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner,
D->getLocation(), D->getIdentifier(),
DI->getType(), DI,
- D->getStorageClass());
+ D->getStorageClass(),
+ D->getStorageClassAsWritten());
Var->setThreadSpecified(D->isThreadSpecified());
Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
Var->setDeclaredInCondition(D->isDeclaredInCondition());
@@ -354,6 +365,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
Owner->makeDeclVisibleInContext(Var);
} else {
Owner->addDecl(Var);
+
+ if (Owner->isFunctionOrMethod())
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Var);
}
// Link instantiations of static data members back to the template from
@@ -476,47 +490,37 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
}
Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
- FriendDecl::FriendUnion FU;
-
// Handle friend type expressions by simply substituting template
- // parameters into the pattern type.
+ // parameters into the pattern type and checking the result.
if (TypeSourceInfo *Ty = D->getFriendType()) {
TypeSourceInfo *InstTy =
SemaRef.SubstType(Ty, TemplateArgs,
D->getLocation(), DeclarationName());
- if (!InstTy) return 0;
-
- // This assertion is valid because the source type was necessarily
- // an elaborated-type-specifier with a record tag.
- assert(getLangOptions().CPlusPlus0x || InstTy->getType()->isRecordType());
-
- FU = InstTy;
-
- // Handle everything else by appropriate substitution.
- } else {
- NamedDecl *ND = D->getFriendDecl();
- assert(ND && "friend decl must be a decl or a type!");
-
- // FIXME: We have a problem here, because the nested call to Visit(ND)
- // will inject the thing that the friend references into the current
- // owner, which is wrong.
- Decl *NewND;
+ if (!InstTy)
+ return 0;
- // Hack to make this work almost well pending a rewrite.
- if (D->wasSpecialization()) {
- // Totally egregious hack to work around PR5866
+ FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getFriendLoc(), InstTy);
+ if (!FD)
return 0;
- } else {
- NewND = Visit(ND);
- }
- if (!NewND) return 0;
+
+ FD->setAccess(AS_public);
+ Owner->addDecl(FD);
+ return FD;
+ }
+
+ NamedDecl *ND = D->getFriendDecl();
+ assert(ND && "friend decl must be a decl or a type!");
- FU = cast<NamedDecl>(NewND);
- }
+ // All of the Visit implementations for the various potential friend
+ // declarations have to be carefully written to work for friend
+ // objects, with the most important detail being that the target
+ // decl should almost certainly not be placed in Owner.
+ Decl *NewND = Visit(ND);
+ if (!NewND) return 0;
FriendDecl *FD =
- FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), FU,
- D->getFriendLoc());
+ FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ cast<NamedDecl>(NewND), D->getFriendLoc());
FD->setAccess(AS_public);
Owner->addDecl(FD);
return FD;
@@ -619,21 +623,6 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
return 0;
}
-namespace {
- class SortDeclByLocation {
- SourceManager &SourceMgr;
-
- public:
- explicit SortDeclByLocation(SourceManager &SourceMgr)
- : SourceMgr(SourceMgr) { }
-
- bool operator()(const Decl *X, const Decl *Y) const {
- return SourceMgr.isBeforeInTranslationUnit(X->getLocation(),
- Y->getLocation());
- }
- };
-}
-
Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
bool isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
@@ -698,19 +687,52 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
return 0;
}
+ bool AdoptedPreviousTemplateParams = false;
if (PrevClassTemplate) {
+ bool Complain = true;
+
+ // HACK: libstdc++ 4.2.1 contains an ill-formed friend class
+ // template for struct std::tr1::__detail::_Map_base, where the
+ // template parameters of the friend declaration don't match the
+ // template parameters of the original declaration. In this one
+ // case, we don't complain about the ill-formed friend
+ // declaration.
+ if (isFriend && Pattern->getIdentifier() &&
+ Pattern->getIdentifier()->isStr("_Map_base") &&
+ DC->isNamespace() &&
+ cast<NamespaceDecl>(DC)->getIdentifier() &&
+ cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__detail")) {
+ DeclContext *DCParent = DC->getParent();
+ if (DCParent->isNamespace() &&
+ cast<NamespaceDecl>(DCParent)->getIdentifier() &&
+ cast<NamespaceDecl>(DCParent)->getIdentifier()->isStr("tr1")) {
+ DeclContext *DCParent2 = DCParent->getParent();
+ if (DCParent2->isNamespace() &&
+ cast<NamespaceDecl>(DCParent2)->getIdentifier() &&
+ cast<NamespaceDecl>(DCParent2)->getIdentifier()->isStr("std") &&
+ DCParent2->getParent()->isTranslationUnit())
+ Complain = false;
+ }
+ }
+
TemplateParameterList *PrevParams
= PrevClassTemplate->getTemplateParameters();
// Make sure the parameter lists match.
if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams,
- /*Complain=*/true,
- Sema::TPL_TemplateMatch))
- return 0;
+ Complain,
+ Sema::TPL_TemplateMatch)) {
+ if (Complain)
+ return 0;
+
+ AdoptedPreviousTemplateParams = true;
+ InstParams = PrevParams;
+ }
// Do some additional validation, then merge default arguments
// from the existing declarations.
- if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams,
+ if (!AdoptedPreviousTemplateParams &&
+ SemaRef.CheckTemplateParameterList(InstParams, PrevParams,
Sema::TPC_ClassTemplate))
return 0;
}
@@ -730,7 +752,13 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
D->getIdentifier(), InstParams, RecordInst,
PrevClassTemplate);
RecordInst->setDescribedClassTemplate(Inst);
+
if (isFriend) {
+ if (PrevClassTemplate)
+ Inst->setAccess(PrevClassTemplate->getAccess());
+ else
+ Inst->setAccess(D->getAccess());
+
Inst->setObjectOfFriendDecl(PrevClassTemplate != 0);
// TODO: do we want to track the instantiation progeny of this
// friend target decl?
@@ -742,29 +770,19 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// Trigger creation of the type for the instantiation.
SemaRef.Context.getInjectedClassNameType(RecordInst,
Inst->getInjectedClassNameSpecialization(SemaRef.Context));
-
+
// Finish handling of friends.
if (isFriend) {
DC->makeDeclVisibleInContext(Inst, /*Recoverable*/ false);
return Inst;
}
- Inst->setAccess(D->getAccess());
Owner->addDecl(Inst);
- // First, we sort the partial specializations by location, so
- // that we instantiate them in the order they were declared.
- llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
- for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
- P = D->getPartialSpecializations().begin(),
- PEnd = D->getPartialSpecializations().end();
- P != PEnd; ++P)
- PartialSpecs.push_back(&*P);
- std::sort(PartialSpecs.begin(), PartialSpecs.end(),
- SortDeclByLocation(SemaRef.SourceMgr));
-
// Instantiate all of the partial specializations of this member class
// template.
+ llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+ D->getPartialSpecializations(PartialSpecs);
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I)
InstantiateClassTemplatePartialSpecialization(Inst, PartialSpecs[I]);
@@ -807,7 +825,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
// merged with the local instantiation scope for the function template
// itself.
Sema::LocalInstantiationScope Scope(SemaRef);
-
+
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
@@ -963,7 +981,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
D->getDeclName(), T, TInfo,
- D->getStorageClass(),
+ D->getStorageClass(), D->getStorageClassAsWritten(),
D->isInlineSpecified(), D->hasWrittenPrototype());
if (Qualifier)
@@ -1027,11 +1045,47 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
+ bool isExplicitSpecialization = false;
LookupResult Previous(SemaRef, Function->getDeclName(), SourceLocation(),
Sema::LookupOrdinaryName, Sema::ForRedeclaration);
- if (TemplateParams || !FunctionTemplate) {
+ if (DependentFunctionTemplateSpecializationInfo *Info
+ = D->getDependentSpecializationInfo()) {
+ assert(isFriend && "non-friend has dependent specialization info?");
+
+ // This needs to be set now for future sanity.
+ Function->setObjectOfFriendDecl(/*HasPrevious*/ true);
+
+ // Instantiate the explicit template arguments.
+ TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
+ Info->getRAngleLoc());
+ for (unsigned I = 0, E = Info->getNumTemplateArgs(); I != E; ++I) {
+ TemplateArgumentLoc Loc;
+ if (SemaRef.Subst(Info->getTemplateArg(I), Loc, TemplateArgs))
+ return 0;
+
+ ExplicitArgs.addArgument(Loc);
+ }
+
+ // Map the candidate templates to their instantiations.
+ for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) {
+ Decl *Temp = SemaRef.FindInstantiatedDecl(D->getLocation(),
+ Info->getTemplate(I),
+ TemplateArgs);
+ if (!Temp) return 0;
+
+ Previous.addDecl(cast<FunctionTemplateDecl>(Temp));
+ }
+
+ if (SemaRef.CheckFunctionTemplateSpecialization(Function,
+ &ExplicitArgs,
+ Previous))
+ Function->setInvalidDecl();
+
+ isExplicitSpecialization = true;
+
+ } else if (TemplateParams || !FunctionTemplate) {
// Look only into the namespace where the friend would be declared to
// find a previous declaration. This is the innermost enclosing namespace,
// as described in ActOnFriendFunctionDecl.
@@ -1046,25 +1100,30 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
}
SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous,
- false, Redeclaration,
+ isExplicitSpecialization, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
+ NamedDecl *PrincipalDecl = (TemplateParams
+ ? cast<NamedDecl>(FunctionTemplate)
+ : Function);
+
// If the original function was part of a friend declaration,
// inherit its namespace state and add it to the owner.
if (isFriend) {
- NamedDecl *ToFriendD = 0;
NamedDecl *PrevDecl;
- if (TemplateParams) {
- ToFriendD = cast<NamedDecl>(FunctionTemplate);
+ if (TemplateParams)
PrevDecl = FunctionTemplate->getPreviousDeclaration();
- } else {
- ToFriendD = Function;
+ else
PrevDecl = Function->getPreviousDeclaration();
- }
- ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL);
- DC->makeDeclVisibleInContext(ToFriendD, /*Recoverable=*/ false);
+
+ PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0);
+ DC->makeDeclVisibleInContext(PrincipalDecl, /*Recoverable=*/ false);
}
+ if (Function->isOverloadedOperator() && !DC->isRecord() &&
+ PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ PrincipalDecl->setNonMemberOperator();
+
return Function;
}
@@ -1146,14 +1205,16 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Constructor->getLocation(),
Name, T, TInfo,
Constructor->isExplicit(),
- Constructor->isInlineSpecified(), false);
+ Constructor->isInlineSpecified(),
+ false);
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
Name = SemaRef.Context.DeclarationNames.getCXXDestructorName(
SemaRef.Context.getCanonicalType(ClassTy));
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
Destructor->getLocation(), Name,
- T, Destructor->isInlineSpecified(), false);
+ T, Destructor->isInlineSpecified(),
+ false);
} else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
CanQualType ConvTy
= SemaRef.Context.getCanonicalType(
@@ -1168,7 +1229,9 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
} else {
Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
D->getDeclName(), T, TInfo,
- D->isStatic(), D->isInlineSpecified());
+ D->isStatic(),
+ D->getStorageClassAsWritten(),
+ D->isInlineSpecified());
}
if (Qualifier)
@@ -1279,41 +1342,7 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
}
ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
- QualType T;
- TypeSourceInfo *DI = D->getTypeSourceInfo();
- if (DI) {
- DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(),
- D->getDeclName());
- if (DI) T = DI->getType();
- } else {
- T = SemaRef.SubstType(D->getType(), TemplateArgs, D->getLocation(),
- D->getDeclName());
- DI = 0;
- }
-
- if (T.isNull())
- return 0;
-
- T = SemaRef.adjustParameterType(T);
-
- // Allocate the parameter
- ParmVarDecl *Param
- = ParmVarDecl::Create(SemaRef.Context,
- SemaRef.Context.getTranslationUnitDecl(),
- D->getLocation(),
- D->getIdentifier(), T, DI, D->getStorageClass(), 0);
-
- // Mark the default argument as being uninstantiated.
- if (D->hasUninstantiatedDefaultArg())
- Param->setUninstantiatedDefaultArg(D->getUninstantiatedDefaultArg());
- else if (Expr *Arg = D->getDefaultArg())
- Param->setUninstantiatedDefaultArg(Arg);
-
- // Note: we don't try to instantiate function parameters until after
- // we've instantiated the function's type. Therefore, we don't have
- // to check for 'void' parameter types here.
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param);
- return Param;
+ return SemaRef.SubstParmVarDecl(D, TemplateArgs);
}
Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
@@ -1718,7 +1747,8 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
Converted,
InstTemplateArgs,
CanonType,
- 0);
+ 0,
+ ClassTemplate->getPartialSpecializations().size());
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
return 0;
@@ -1733,48 +1763,50 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
return false;
}
-bool
-Sema::CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl*> &Params) {
- bool Invalid = false;
- for (unsigned i = 0, i_end = Params.size(); i != i_end; ++i)
- if (ParmVarDecl *PInst = Params[i]) {
- if (PInst->isInvalidDecl())
- Invalid = true;
- else if (PInst->getType()->isVoidType()) {
- Diag(PInst->getLocation(), diag::err_param_with_void_type);
- PInst->setInvalidDecl();
- Invalid = true;
- }
- else if (RequireNonAbstractType(PInst->getLocation(),
- PInst->getType(),
- diag::err_abstract_type_in_decl,
- Sema::AbstractParamType)) {
- PInst->setInvalidDecl();
- Invalid = true;
- }
- }
- return Invalid;
-}
-
TypeSourceInfo*
TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params) {
TypeSourceInfo *OldTInfo = D->getTypeSourceInfo();
assert(OldTInfo && "substituting function without type source info");
assert(Params.empty() && "parameter vector is non-empty at start");
- TypeSourceInfo *NewTInfo = SemaRef.SubstType(OldTInfo, TemplateArgs,
- D->getTypeSpecStartLoc(),
- D->getDeclName());
+ TypeSourceInfo *NewTInfo
+ = SemaRef.SubstFunctionDeclType(OldTInfo, TemplateArgs,
+ D->getTypeSpecStartLoc(),
+ D->getDeclName());
if (!NewTInfo)
return 0;
- // Get parameters from the new type info.
- TypeLoc NewTL = NewTInfo->getTypeLoc();
- FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL);
- assert(NewProtoLoc && "Missing prototype?");
- for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i)
- Params.push_back(NewProtoLoc->getArg(i));
-
+ if (NewTInfo != OldTInfo) {
+ // Get parameters from the new type info.
+ TypeLoc OldTL = OldTInfo->getTypeLoc();
+ if (FunctionProtoTypeLoc *OldProtoLoc
+ = dyn_cast<FunctionProtoTypeLoc>(&OldTL)) {
+ TypeLoc NewTL = NewTInfo->getTypeLoc();
+ FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL);
+ assert(NewProtoLoc && "Missing prototype?");
+ for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i) {
+ // FIXME: Variadic templates will break this.
+ Params.push_back(NewProtoLoc->getArg(i));
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(
+ OldProtoLoc->getArg(i),
+ NewProtoLoc->getArg(i));
+ }
+ }
+ } else {
+ // The function type itself was not dependent and therefore no
+ // substitution occurred. However, we still need to instantiate
+ // the function parameters themselves.
+ TypeLoc OldTL = OldTInfo->getTypeLoc();
+ if (FunctionProtoTypeLoc *OldProtoLoc
+ = dyn_cast<FunctionProtoTypeLoc>(&OldTL)) {
+ for (unsigned i = 0, i_end = OldProtoLoc->getNumArgs(); i != i_end; ++i) {
+ ParmVarDecl *Parm = VisitParmVarDecl(OldProtoLoc->getArg(i));
+ if (!Parm)
+ return 0;
+ Params.push_back(Parm);
+ }
+ }
+ }
return NewTInfo;
}
@@ -1938,8 +1970,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
if (Inst)
- return;
-
+ return;
+
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate later,
// while we're still within our own instantiation context.
@@ -1971,7 +2003,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
CurContext = Function;
MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(Function);
+ getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
// If this is a constructor, instantiate the member initializers.
if (const CXXConstructorDecl *Ctor =
@@ -2459,7 +2491,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
T = Context.getTypeDeclType(Record);
assert(isa<InjectedClassNameType>(T) &&
"type of partial specialization is not an InjectedClassNameType");
- T = cast<InjectedClassNameType>(T)->getUnderlyingType();
+ T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType();
}
if (!T.isNull()) {
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 8278691..d1a74be 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -81,9 +81,12 @@ static void ProcessDelayedFnAttrs(Sema &S, QualType &Type,
DelayedAttributeSet &Attrs) {
for (DelayedAttributeSet::iterator I = Attrs.begin(),
E = Attrs.end(); I != E; ++I)
- if (ProcessFnAttr(S, Type, *I->first))
+ if (ProcessFnAttr(S, Type, *I->first)) {
S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type)
<< I->first->getName() << I->second;
+ // Avoid any further processing of this attribute.
+ I->first->setInvalid();
+ }
Attrs.clear();
}
@@ -92,6 +95,8 @@ static void DiagnoseDelayedFnAttrs(Sema &S, DelayedAttributeSet &Attrs) {
E = Attrs.end(); I != E; ++I) {
S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type)
<< I->first->getName() << I->second;
+ // Avoid any further processing of this attribute.
+ I->first->setInvalid();
}
Attrs.clear();
}
@@ -280,6 +285,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema,
if (TheSema.getLangOptions().CPlusPlus) {
TagDecl::TagKind Tag
= TagDecl::getTagKindForTypeSpec(DS.getTypeSpecType());
+ Result = TheSema.getQualifiedNameType(DS.getTypeSpecScope(), Result);
Result = Context.getElaboratedType(Result, Tag);
}
@@ -498,6 +504,8 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals,
Qs.removeRestrict();
}
+ assert(!T->isObjCInterfaceType() && "Should build ObjCObjectPointerType");
+
// Build the pointer type.
return Context.getQualifiedType(Context.getPointerType(T), Qs);
}
@@ -604,15 +612,31 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
SourceRange Brackets, DeclarationName Entity) {
SourceLocation Loc = Brackets.getBegin();
- // C99 6.7.5.2p1: If the element type is an incomplete or function type,
- // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]())
- // Not in C++, though. There we only dislike void.
if (getLangOptions().CPlusPlus) {
+ // C++ [dcl.array]p1:
+ // T is called the array element type; this type shall not be a reference
+ // type, the (possibly cv-qualified) type void, a function type or an
+ // abstract class type.
+ //
+ // Note: function types are handled in the common path with C.
+ if (T->isReferenceType()) {
+ Diag(Loc, diag::err_illegal_decl_array_of_references)
+ << getPrintableNameForEntity(Entity) << T;
+ return QualType();
+ }
+
if (T->isVoidType()) {
Diag(Loc, diag::err_illegal_decl_array_incomplete_type) << T;
return QualType();
}
+
+ if (RequireNonAbstractType(Brackets.getBegin(), T,
+ diag::err_array_of_abstract_type))
+ return QualType();
+
} else {
+ // C99 6.7.5.2p1: If the element type is an incomplete or function type,
+ // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]())
if (RequireCompleteType(Loc, T,
diag::err_illegal_decl_array_incomplete_type))
return QualType();
@@ -624,13 +648,6 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
return QualType();
}
- // C++ 8.3.2p4: There shall be no ... arrays of references ...
- if (T->isReferenceType()) {
- Diag(Loc, diag::err_illegal_decl_array_of_references)
- << getPrintableNameForEntity(Entity) << T;
- return QualType();
- }
-
if (Context.getCanonicalType(T) == Context.UndeducedAutoTy) {
Diag(Loc, diag::err_illegal_decl_array_of_auto)
<< getPrintableNameForEntity(Entity);
@@ -922,7 +939,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// Determine the type of the declarator. Not all forms of declarator
// have a type.
QualType T;
-
+ TypeSourceInfo *ReturnTypeInfo = 0;
+
llvm::SmallVector<DelayedAttribute,4> FnAttrsFromDeclSpec;
switch (D.getName().getKind()) {
@@ -948,12 +966,17 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// Constructors and destructors don't have return types. Use
// "void" instead.
T = Context.VoidTy;
+
+ if (TInfo)
+ ReturnTypeInfo = Context.getTrivialTypeSourceInfo(T,
+ D.getName().StartLocation);
break;
case UnqualifiedId::IK_ConversionFunctionId:
// The result type of a conversion function is the type that it
// converts to.
- T = GetTypeFromParser(D.getName().ConversionFunctionId);
+ T = GetTypeFromParser(D.getName().ConversionFunctionId,
+ TInfo? &ReturnTypeInfo : 0);
break;
}
@@ -1036,7 +1059,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (getLangOptions().ObjC1 && T->isObjCInterfaceType()) {
const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>();
T = Context.getObjCObjectPointerType(T,
- (ObjCProtocolDecl **)OIT->qual_begin(),
+ const_cast<ObjCProtocolDecl **>(
+ OIT->qual_begin()),
OIT->getNumProtocols(),
DeclType.Ptr.TypeQuals);
break;
@@ -1253,8 +1277,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
// The scope spec must refer to a class, or be dependent.
QualType ClsType;
- if (isDependentScopeSpecifier(DeclType.Mem.Scope())
- || dyn_cast_or_null<CXXRecordDecl>(
+ if (DeclType.Mem.Scope().isInvalid()) {
+ // Avoid emitting extra errors if we already errored on the scope.
+ D.setInvalidType(true);
+ } else if (isDependentScopeSpecifier(DeclType.Mem.Scope())
+ || dyn_cast_or_null<CXXRecordDecl>(
computeDeclContext(DeclType.Mem.Scope()))) {
NestedNameSpecifier *NNS
= (NestedNameSpecifier *)DeclType.Mem.Scope().getScopeRep();
@@ -1353,7 +1380,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (D.isInvalidType())
*TInfo = 0;
else
- *TInfo = GetTypeSourceInfoForDeclarator(D, T);
+ *TInfo = GetTypeSourceInfoForDeclarator(D, T, ReturnTypeInfo);
}
return T;
@@ -1538,8 +1565,14 @@ namespace {
/// \brief Create and instantiate a TypeSourceInfo with type source information.
///
/// \param T QualType referring to the type as written in source code.
+///
+/// \param ReturnTypeInfo For declarators whose return type does not show
+/// up in the normal place in the declaration specifiers (such as a C++
+/// conversion function), this pointer will refer to a type source information
+/// for that return type.
TypeSourceInfo *
-Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T) {
+Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
+ TypeSourceInfo *ReturnTypeInfo) {
TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T);
UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc();
@@ -1549,7 +1582,18 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T) {
}
TypeSpecLocFiller(D.getDeclSpec()).Visit(CurrTL);
-
+
+ // We have source information for the return type that was not in the
+ // declaration specifiers; copy that information into the current type
+ // location so that it will be retained. This occurs, for example, with
+ // a C++ conversion function, where the return type occurs within the
+ // declarator-id rather than in the declaration specifiers.
+ if (ReturnTypeInfo && D.getDeclSpec().getTypeSpecType() == TST_unspecified) {
+ TypeLoc TL = ReturnTypeInfo->getTypeLoc();
+ assert(TL.getFullDataSize() == CurrTL.getFullDataSize());
+ memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize());
+ }
+
return TInfo;
}
@@ -1648,12 +1692,14 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
// for two or more different address spaces."
if (Type.getAddressSpace()) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers);
+ Attr.setInvalid();
return;
}
// Check the attribute arguments.
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ Attr.setInvalid();
return;
}
Expr *ASArgExpr = static_cast<Expr *>(Attr.getArg(0));
@@ -1661,6 +1707,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
if (!ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_space_not_int)
<< ASArgExpr->getSourceRange();
+ Attr.setInvalid();
return;
}
@@ -1669,6 +1716,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
if (addrSpace.isNegative()) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_space_negative)
<< ASArgExpr->getSourceRange();
+ Attr.setInvalid();
return;
}
addrSpace.setIsSigned(false);
@@ -1678,6 +1726,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
if (addrSpace > max) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high)
<< Qualifiers::MaxAddressSpace << ASArgExpr->getSourceRange();
+ Attr.setInvalid();
return;
}
@@ -1691,6 +1740,7 @@ static void HandleObjCGCTypeAttribute(QualType &Type,
const AttributeList &Attr, Sema &S) {
if (Type.getObjCGCAttr() != Qualifiers::GCNone) {
S.Diag(Attr.getLoc(), diag::err_attribute_multiple_objc_gc);
+ Attr.setInvalid();
return;
}
@@ -1698,11 +1748,13 @@ static void HandleObjCGCTypeAttribute(QualType &Type,
if (!Attr.getParameterName()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "objc_gc" << 1;
+ Attr.setInvalid();
return;
}
Qualifiers::GC GCAttr;
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ Attr.setInvalid();
return;
}
if (Attr.getParameterName()->isStr("weak"))
@@ -1712,6 +1764,7 @@ static void HandleObjCGCTypeAttribute(QualType &Type,
else {
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
<< "objc_gc" << Attr.getParameterName();
+ Attr.setInvalid();
return;
}
@@ -1725,6 +1778,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
// Complain immediately if the arg count is wrong.
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ Attr.setInvalid();
return false;
}
@@ -1766,6 +1820,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
// Otherwise, a calling convention.
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ Attr.setInvalid();
return false;
}
@@ -1788,13 +1843,17 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
CallingConv CCOld = Fn->getCallConv();
if (S.Context.getCanonicalCallConv(CC) ==
- S.Context.getCanonicalCallConv(CCOld)) return false;
+ S.Context.getCanonicalCallConv(CCOld)) {
+ Attr.setInvalid();
+ return false;
+ }
if (CCOld != CC_Default) {
// Should we diagnose reapplications of the same convention?
S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
<< FunctionType::getNameForCallConv(CC)
<< FunctionType::getNameForCallConv(CCOld);
+ Attr.setInvalid();
return false;
}
@@ -1803,6 +1862,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
if (isa<FunctionNoProtoType>(Fn)) {
S.Diag(Attr.getLoc(), diag::err_cconv_knr)
<< FunctionType::getNameForCallConv(CC);
+ Attr.setInvalid();
return false;
}
@@ -1810,6 +1870,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
if (FnP->isVariadic()) {
S.Diag(Attr.getLoc(), diag::err_cconv_varargs)
<< FunctionType::getNameForCallConv(CC);
+ Attr.setInvalid();
return false;
}
}
@@ -1829,6 +1890,7 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S
// Check the attribute arugments.
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ Attr.setInvalid();
return;
}
Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0));
@@ -1836,12 +1898,14 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S
if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "vector_size" << sizeExpr->getSourceRange();
+ Attr.setInvalid();
return;
}
// the base type must be integer or float, and can't already be a vector.
if (CurType->isVectorType() ||
(!CurType->isIntegerType() && !CurType->isRealFloatingType())) {
S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType;
+ Attr.setInvalid();
return;
}
unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType));
@@ -1852,11 +1916,13 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S
if (vectorSize % typeSize) {
S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size)
<< sizeExpr->getSourceRange();
+ Attr.setInvalid();
return;
}
if (vectorSize == 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_zero_size)
<< sizeExpr->getSourceRange();
+ Attr.setInvalid();
return;
}
@@ -1873,8 +1939,12 @@ void ProcessTypeAttributeList(Sema &S, QualType &Result,
// type, but others can be present in the type specifiers even though they
// apply to the decl. Here we apply type attributes and ignore the rest.
for (; AL; AL = AL->getNext()) {
- // If this is an attribute we can handle, do so now, otherwise, add it to
- // the LeftOverAttrs list for rechaining.
+ // Skip attributes that were marked to be invalid.
+ if (AL->isInvalid())
+ continue;
+
+ // If this is an attribute we can handle, do so now,
+ // otherwise, add it to the FnAttrs list for rechaining.
switch (AL->getKind()) {
default: break;
@@ -2029,7 +2099,10 @@ QualType Sema::BuildTypeofExprType(Expr *E) {
// function template specialization wherever deduction cannot occur.
if (FunctionDecl *Specialization
= ResolveSingleFunctionTemplateSpecialization(E)) {
- E = FixOverloadedFunctionReference(E, Specialization, Specialization);
+ // The access doesn't really matter in this case.
+ DeclAccessPair Found = DeclAccessPair::make(Specialization,
+ Specialization->getAccess());
+ E = FixOverloadedFunctionReference(E, Found, Specialization);
if (!E)
return QualType();
} else {
@@ -2049,7 +2122,10 @@ QualType Sema::BuildDecltypeType(Expr *E) {
// function template specialization wherever deduction cannot occur.
if (FunctionDecl *Specialization
= ResolveSingleFunctionTemplateSpecialization(E)) {
- E = FixOverloadedFunctionReference(E, Specialization, Specialization);
+ // The access doesn't really matter in this case.
+ DeclAccessPair Found = DeclAccessPair::make(Specialization,
+ Specialization->getAccess());
+ E = FixOverloadedFunctionReference(E, Found, Specialization);
if (!E)
return QualType();
} else {
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index f9ffd3f..5ce268b 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -338,6 +338,7 @@ public:
QualType ObjectType);
OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
+ OwningExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E);
#define STMT(Node, Parent) \
OwningStmtResult Transform##Node(Node *S);
@@ -378,10 +379,6 @@ public:
QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType,
SourceLocation Sigil);
- /// \brief Build a new Objective C object pointer type.
- QualType RebuildObjCObjectPointerType(QualType PointeeType,
- SourceLocation Sigil);
-
/// \brief Build a new array type given the element type, size
/// modifier, size of the array (if known), size expression, and index type
/// qualifiers.
@@ -577,10 +574,9 @@ public:
TagDecl::TagKind Kind = TagDecl::TK_enum;
switch (Keyword) {
case ETK_None:
- // FIXME: Note the lack of the "typename" specifier!
- // Fall through
+ // Fall through.
case ETK_Typename:
- return SemaRef.CheckTypenameType(NNS, *Id, SR);
+ return SemaRef.CheckTypenameType(Keyword, NNS, *Id, SR);
case ETK_Class: Kind = TagDecl::TK_class; break;
case ETK_Struct: Kind = TagDecl::TK_struct; break;
@@ -892,6 +888,88 @@ public:
move(Exprs), move(AsmString), move(Clobbers),
RParenLoc, MSAsm);
}
+
+ /// \brief Build a new Objective-C @try statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildObjCAtTryStmt(SourceLocation AtLoc,
+ StmtArg TryBody,
+ MultiStmtArg CatchStmts,
+ StmtArg Finally) {
+ return getSema().ActOnObjCAtTryStmt(AtLoc, move(TryBody), move(CatchStmts),
+ move(Finally));
+ }
+
+ /// \brief Rebuild an Objective-C exception declaration.
+ ///
+ /// By default, performs semantic analysis to build the new declaration.
+ /// Subclasses may override this routine to provide different behavior.
+ VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl,
+ TypeSourceInfo *TInfo, QualType T) {
+ return getSema().BuildObjCExceptionDecl(TInfo, T,
+ ExceptionDecl->getIdentifier(),
+ ExceptionDecl->getLocation());
+ }
+
+ /// \brief Build a new Objective-C @catch statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildObjCAtCatchStmt(SourceLocation AtLoc,
+ SourceLocation RParenLoc,
+ VarDecl *Var,
+ StmtArg Body) {
+ return getSema().ActOnObjCAtCatchStmt(AtLoc, RParenLoc,
+ Sema::DeclPtrTy::make(Var),
+ move(Body));
+ }
+
+ /// \brief Build a new Objective-C @finally statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildObjCAtFinallyStmt(SourceLocation AtLoc,
+ StmtArg Body) {
+ return getSema().ActOnObjCAtFinallyStmt(AtLoc, move(Body));
+ }
+
+ /// \brief Build a new Objective-C @throw statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildObjCAtThrowStmt(SourceLocation AtLoc,
+ ExprArg Operand) {
+ return getSema().BuildObjCAtThrowStmt(AtLoc, move(Operand));
+ }
+
+ /// \brief Build a new Objective-C @synchronized statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildObjCAtSynchronizedStmt(SourceLocation AtLoc,
+ ExprArg Object,
+ StmtArg Body) {
+ return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, move(Object),
+ move(Body));
+ }
+
+ /// \brief Build a new Objective-C fast enumeration statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildObjCForCollectionStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc,
+ StmtArg Element,
+ ExprArg Collection,
+ SourceLocation RParenLoc,
+ StmtArg Body) {
+ return getSema().ActOnObjCForCollectionStmt(ForLoc, LParenLoc,
+ move(Element),
+ move(Collection),
+ RParenLoc,
+ move(Body));
+ }
/// \brief Build a new C++ exception declaration.
///
@@ -989,6 +1067,19 @@ public:
return getSema().BuildUnaryOp(/*Scope=*/0, OpLoc, Opc, move(SubExpr));
}
+ /// \brief Build a new builtin offsetof expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildOffsetOfExpr(SourceLocation OperatorLoc,
+ TypeSourceInfo *Type,
+ Action::OffsetOfComponent *Components,
+ unsigned NumComponents,
+ SourceLocation RParenLoc) {
+ return getSema().BuildBuiltinOffsetOf(OperatorLoc, Type, Components,
+ NumComponents, RParenLoc);
+ }
+
/// \brief Build a new sizeof or alignof expression with a type argument.
///
/// By default, performs semantic analysis to build the new expression.
@@ -1421,30 +1512,24 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc,
- SourceLocation LParenLoc,
- QualType T,
+ OwningExprResult RebuildCXXTypeidExpr(QualType TypeInfoType,
+ SourceLocation TypeidLoc,
+ TypeSourceInfo *Operand,
SourceLocation RParenLoc) {
- return getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, true,
- T.getAsOpaquePtr(), RParenLoc);
+ return getSema().BuildCXXTypeId(TypeInfoType, TypeidLoc, Operand,
+ RParenLoc);
}
/// \brief Build a new C++ typeid(expr) expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc,
- SourceLocation LParenLoc,
+ OwningExprResult RebuildCXXTypeidExpr(QualType TypeInfoType,
+ SourceLocation TypeidLoc,
ExprArg Operand,
SourceLocation RParenLoc) {
- OwningExprResult Result
- = getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, false, Operand.get(),
- RParenLoc);
- if (Result.isInvalid())
- return getSema().ExprError();
-
- Operand.release(); // FIXME: since ActOnCXXTypeid silently took ownership
- return move(Result);
+ return getSema().BuildCXXTypeId(TypeInfoType, TypeidLoc, move(Operand),
+ RParenLoc);
}
/// \brief Build a new C++ "this" expression.
@@ -1688,29 +1773,147 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildObjCEncodeExpr(SourceLocation AtLoc,
- QualType T,
+ TypeSourceInfo *EncodeTypeInfo,
SourceLocation RParenLoc) {
- return SemaRef.Owned(SemaRef.BuildObjCEncodeExpression(AtLoc, T,
+ return SemaRef.Owned(SemaRef.BuildObjCEncodeExpression(AtLoc, EncodeTypeInfo,
RParenLoc));
}
- /// \brief Build a new Objective-C protocol expression.
+ /// \brief Build a new Objective-C class message.
+ OwningExprResult RebuildObjCMessageExpr(TypeSourceInfo *ReceiverTypeInfo,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ SourceLocation LBracLoc,
+ MultiExprArg Args,
+ SourceLocation RBracLoc) {
+ return SemaRef.BuildClassMessage(ReceiverTypeInfo,
+ ReceiverTypeInfo->getType(),
+ /*SuperLoc=*/SourceLocation(),
+ Sel, Method, LBracLoc, RBracLoc,
+ move(Args));
+ }
+
+ /// \brief Build a new Objective-C instance message.
+ OwningExprResult RebuildObjCMessageExpr(ExprArg Receiver,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ SourceLocation LBracLoc,
+ MultiExprArg Args,
+ SourceLocation RBracLoc) {
+ QualType ReceiverType = static_cast<Expr *>(Receiver.get())->getType();
+ return SemaRef.BuildInstanceMessage(move(Receiver),
+ ReceiverType,
+ /*SuperLoc=*/SourceLocation(),
+ Sel, Method, LBracLoc, RBracLoc,
+ move(Args));
+ }
+
+ /// \brief Build a new Objective-C ivar reference expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- OwningExprResult RebuildObjCProtocolExpr(ObjCProtocolDecl *Protocol,
- SourceLocation AtLoc,
- SourceLocation ProtoLoc,
- SourceLocation LParenLoc,
- SourceLocation RParenLoc) {
- return SemaRef.Owned(SemaRef.ParseObjCProtocolExpression(
- Protocol->getIdentifier(),
- AtLoc,
- ProtoLoc,
- LParenLoc,
- RParenLoc));
+ OwningExprResult RebuildObjCIvarRefExpr(ExprArg BaseArg, ObjCIvarDecl *Ivar,
+ SourceLocation IvarLoc,
+ bool IsArrow, bool IsFreeIvar) {
+ // FIXME: We lose track of the IsFreeIvar bit.
+ CXXScopeSpec SS;
+ Expr *Base = BaseArg.takeAs<Expr>();
+ LookupResult R(getSema(), Ivar->getDeclName(), IvarLoc,
+ Sema::LookupMemberName);
+ OwningExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow,
+ /*FIME:*/IvarLoc,
+ SS, DeclPtrTy());
+ if (Result.isInvalid())
+ return getSema().ExprError();
+
+ if (Result.get())
+ return move(Result);
+
+ return getSema().BuildMemberReferenceExpr(getSema().Owned(Base),
+ Base->getType(),
+ /*FIXME:*/IvarLoc, IsArrow, SS,
+ /*FirstQualifierInScope=*/0,
+ R,
+ /*TemplateArgs=*/0);
+ }
+
+ /// \brief Build a new Objective-C property reference expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildObjCPropertyRefExpr(ExprArg BaseArg,
+ ObjCPropertyDecl *Property,
+ SourceLocation PropertyLoc) {
+ CXXScopeSpec SS;
+ Expr *Base = BaseArg.takeAs<Expr>();
+ LookupResult R(getSema(), Property->getDeclName(), PropertyLoc,
+ Sema::LookupMemberName);
+ bool IsArrow = false;
+ OwningExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow,
+ /*FIME:*/PropertyLoc,
+ SS, DeclPtrTy());
+ if (Result.isInvalid())
+ return getSema().ExprError();
+
+ if (Result.get())
+ return move(Result);
+
+ return getSema().BuildMemberReferenceExpr(getSema().Owned(Base),
+ Base->getType(),
+ /*FIXME:*/PropertyLoc, IsArrow,
+ SS,
+ /*FirstQualifierInScope=*/0,
+ R,
+ /*TemplateArgs=*/0);
+ }
+
+ /// \brief Build a new Objective-C implicit setter/getter reference
+ /// expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildObjCImplicitSetterGetterRefExpr(
+ ObjCMethodDecl *Getter,
+ QualType T,
+ ObjCMethodDecl *Setter,
+ SourceLocation NameLoc,
+ ExprArg Base) {
+ // Since these expressions can only be value-dependent, we do not need to
+ // perform semantic analysis again.
+ return getSema().Owned(
+ new (getSema().Context) ObjCImplicitSetterGetterRefExpr(Getter, T,
+ Setter,
+ NameLoc,
+ Base.takeAs<Expr>()));
}
+ /// \brief Build a new Objective-C "isa" expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildObjCIsaExpr(ExprArg BaseArg, SourceLocation IsaLoc,
+ bool IsArrow) {
+ CXXScopeSpec SS;
+ Expr *Base = BaseArg.takeAs<Expr>();
+ LookupResult R(getSema(), &getSema().Context.Idents.get("isa"), IsaLoc,
+ Sema::LookupMemberName);
+ OwningExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow,
+ /*FIME:*/IsaLoc,
+ SS, DeclPtrTy());
+ if (Result.isInvalid())
+ return getSema().ExprError();
+
+ if (Result.get())
+ return move(Result);
+
+ return getSema().BuildMemberReferenceExpr(getSema().Owned(Base),
+ Base->getType(),
+ /*FIXME:*/IsaLoc, IsArrow, SS,
+ /*FirstQualifierInScope=*/0,
+ R,
+ /*TemplateArgs=*/0);
+ }
+
/// \brief Build a new shuffle vector expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -2225,29 +2428,6 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) {
return T.getType();
}
-// Ugly metaprogramming macros because I couldn't be bothered to make
-// the equivalent template version work.
-#define TransformPointerLikeType(TypeClass) do { \
- QualType PointeeType \
- = getDerived().TransformType(TLB, TL.getPointeeLoc()); \
- if (PointeeType.isNull()) \
- return QualType(); \
- \
- QualType Result = TL.getType(); \
- if (getDerived().AlwaysRebuild() || \
- PointeeType != TL.getPointeeLoc().getType()) { \
- Result = getDerived().Rebuild##TypeClass(PointeeType, \
- TL.getSigilLoc()); \
- if (Result.isNull()) \
- return QualType(); \
- } \
- \
- TypeClass##Loc NewT = TLB.push<TypeClass##Loc>(Result); \
- NewT.setSigilLoc(TL.getSigilLoc()); \
- \
- return Result; \
-} while(0)
-
template<typename Derived>
QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB,
BuiltinTypeLoc T,
@@ -2271,7 +2451,42 @@ template<typename Derived>
QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
PointerTypeLoc TL,
QualType ObjectType) {
- TransformPointerLikeType(PointerType);
+ QualType PointeeType
+ = getDerived().TransformType(TLB, TL.getPointeeLoc());
+ if (PointeeType.isNull())
+ return QualType();
+
+ QualType Result = TL.getType();
+ if (PointeeType->isObjCInterfaceType()) {
+ // A dependent pointer type 'T *' has is being transformed such
+ // that an Objective-C class type is being replaced for 'T'. The
+ // resulting pointer type is an ObjCObjectPointerType, not a
+ // PointerType.
+ const ObjCInterfaceType *IFace = PointeeType->getAs<ObjCInterfaceType>();
+ Result = SemaRef.Context.getObjCObjectPointerType(PointeeType,
+ const_cast<ObjCProtocolDecl **>(
+ IFace->qual_begin()),
+ IFace->getNumProtocols());
+
+ ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result);
+ NewT.setStarLoc(TL.getSigilLoc());
+ NewT.setHasProtocolsAsWritten(false);
+ NewT.setLAngleLoc(SourceLocation());
+ NewT.setRAngleLoc(SourceLocation());
+ NewT.setHasBaseTypeAsWritten(true);
+ return Result;
+ }
+
+ if (getDerived().AlwaysRebuild() ||
+ PointeeType != TL.getPointeeLoc().getType()) {
+ Result = getDerived().RebuildPointerType(PointeeType, TL.getSigilLoc());
+ if (Result.isNull())
+ return QualType();
+ }
+
+ PointerTypeLoc NewT = TLB.push<PointerTypeLoc>(Result);
+ NewT.setSigilLoc(TL.getSigilLoc());
+ return Result;
}
template<typename Derived>
@@ -2279,7 +2494,23 @@ QualType
TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB,
BlockPointerTypeLoc TL,
QualType ObjectType) {
- TransformPointerLikeType(BlockPointerType);
+ QualType PointeeType
+ = getDerived().TransformType(TLB, TL.getPointeeLoc());
+ if (PointeeType.isNull())
+ return QualType();
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() ||
+ PointeeType != TL.getPointeeLoc().getType()) {
+ Result = getDerived().RebuildBlockPointerType(PointeeType,
+ TL.getSigilLoc());
+ if (Result.isNull())
+ return QualType();
+ }
+
+ BlockPointerTypeLoc NewT = TLB.push<BlockPointerTypeLoc>(Result);
+ NewT.setSigilLoc(TL.getSigilLoc());
+ return Result;
}
/// Transforms a reference type. Note that somewhat paradoxically we
@@ -2630,6 +2861,7 @@ TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm) {
NewDI->getType(),
NewDI,
OldParm->getStorageClass(),
+ OldParm->getStorageClassAsWritten(),
/* DefArg */ NULL);
}
@@ -2675,17 +2907,19 @@ QualType
TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc TL,
QualType ObjectType) {
- FunctionProtoType *T = TL.getTypePtr();
- QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
- if (ResultType.isNull())
- return QualType();
-
- // Transform the parameters.
+ // Transform the parameters. We do this first for the benefit of template
+ // instantiations, so that the ParmVarDecls get/ placed into the template
+ // instantiation scope before we transform the function type.
llvm::SmallVector<QualType, 4> ParamTypes;
llvm::SmallVector<ParmVarDecl*, 4> ParamDecls;
if (getDerived().TransformFunctionTypeParams(TL, ParamTypes, ParamDecls))
return QualType();
-
+
+ FunctionProtoType *T = TL.getTypePtr();
+ QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
+ if (ResultType.isNull())
+ return QualType();
+
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
ResultType != T->getResultType() ||
@@ -3117,8 +3351,8 @@ QualType
TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB,
ObjCInterfaceTypeLoc TL,
QualType ObjectType) {
- assert(false && "TransformObjCInterfaceType unimplemented");
- return QualType();
+ // ObjCInterfaceType is never dependent.
+ return TL.getType();
}
template<typename Derived>
@@ -3126,8 +3360,8 @@ QualType
TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB,
ObjCObjectPointerTypeLoc TL,
QualType ObjectType) {
- assert(false && "TransformObjCObjectPointerType unimplemented");
- return QualType();
+ // ObjCObjectPointerType is never dependent.
+ return TL.getType();
}
//===----------------------------------------------------------------------===//
@@ -3587,51 +3821,172 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot transform an Objective-C @try statement");
- return SemaRef.Owned(S->Retain());
+ // Transform the body of the @try.
+ OwningStmtResult TryBody = getDerived().TransformStmt(S->getTryBody());
+ if (TryBody.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the @catch statements (if present).
+ bool AnyCatchChanged = false;
+ ASTOwningVector<&ActionBase::DeleteStmt> CatchStmts(SemaRef);
+ for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) {
+ OwningStmtResult Catch = getDerived().TransformStmt(S->getCatchStmt(I));
+ if (Catch.isInvalid())
+ return SemaRef.StmtError();
+ if (Catch.get() != S->getCatchStmt(I))
+ AnyCatchChanged = true;
+ CatchStmts.push_back(Catch.release());
+ }
+
+ // Transform the @finally statement (if present).
+ OwningStmtResult Finally(SemaRef);
+ if (S->getFinallyStmt()) {
+ Finally = getDerived().TransformStmt(S->getFinallyStmt());
+ if (Finally.isInvalid())
+ return SemaRef.StmtError();
+ }
+
+ // If nothing changed, just retain this statement.
+ if (!getDerived().AlwaysRebuild() &&
+ TryBody.get() == S->getTryBody() &&
+ !AnyCatchChanged &&
+ Finally.get() == S->getFinallyStmt())
+ return SemaRef.Owned(S->Retain());
+
+ // Build a new statement.
+ return getDerived().RebuildObjCAtTryStmt(S->getAtTryLoc(), move(TryBody),
+ move_arg(CatchStmts), move(Finally));
}
template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformObjCAtCatchStmt(ObjCAtCatchStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot transform an Objective-C @catch statement");
- return SemaRef.Owned(S->Retain());
+ // Transform the @catch parameter, if there is one.
+ VarDecl *Var = 0;
+ if (VarDecl *FromVar = S->getCatchParamDecl()) {
+ TypeSourceInfo *TSInfo = 0;
+ if (FromVar->getTypeSourceInfo()) {
+ TSInfo = getDerived().TransformType(FromVar->getTypeSourceInfo());
+ if (!TSInfo)
+ return SemaRef.StmtError();
+ }
+
+ QualType T;
+ if (TSInfo)
+ T = TSInfo->getType();
+ else {
+ T = getDerived().TransformType(FromVar->getType());
+ if (T.isNull())
+ return SemaRef.StmtError();
+ }
+
+ Var = getDerived().RebuildObjCExceptionDecl(FromVar, TSInfo, T);
+ if (!Var)
+ return SemaRef.StmtError();
+ }
+
+ OwningStmtResult Body = getDerived().TransformStmt(S->getCatchBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ return getDerived().RebuildObjCAtCatchStmt(S->getAtCatchLoc(),
+ S->getRParenLoc(),
+ Var, move(Body));
}
template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot transform an Objective-C @finally statement");
- return SemaRef.Owned(S->Retain());
+ // Transform the body.
+ OwningStmtResult Body = getDerived().TransformStmt(S->getFinallyBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ // If nothing changed, just retain this statement.
+ if (!getDerived().AlwaysRebuild() &&
+ Body.get() == S->getFinallyBody())
+ return SemaRef.Owned(S->Retain());
+
+ // Build a new statement.
+ return getDerived().RebuildObjCAtFinallyStmt(S->getAtFinallyLoc(),
+ move(Body));
}
template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformObjCAtThrowStmt(ObjCAtThrowStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot transform an Objective-C @throw statement");
- return SemaRef.Owned(S->Retain());
+ OwningExprResult Operand(SemaRef);
+ if (S->getThrowExpr()) {
+ Operand = getDerived().TransformExpr(S->getThrowExpr());
+ if (Operand.isInvalid())
+ return getSema().StmtError();
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ Operand.get() == S->getThrowExpr())
+ return getSema().Owned(S->Retain());
+
+ return getDerived().RebuildObjCAtThrowStmt(S->getThrowLoc(), move(Operand));
}
template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformObjCAtSynchronizedStmt(
ObjCAtSynchronizedStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot transform an Objective-C @synchronized statement");
- return SemaRef.Owned(S->Retain());
+ // Transform the object we are locking.
+ OwningExprResult Object = getDerived().TransformExpr(S->getSynchExpr());
+ if (Object.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the body.
+ OwningStmtResult Body = getDerived().TransformStmt(S->getSynchBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ // If nothing change, just retain the current statement.
+ if (!getDerived().AlwaysRebuild() &&
+ Object.get() == S->getSynchExpr() &&
+ Body.get() == S->getSynchBody())
+ return SemaRef.Owned(S->Retain());
+
+ // Build a new statement.
+ return getDerived().RebuildObjCAtSynchronizedStmt(S->getAtSynchronizedLoc(),
+ move(Object), move(Body));
}
template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformObjCForCollectionStmt(
ObjCForCollectionStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot transform an Objective-C for-each statement");
- return SemaRef.Owned(S->Retain());
+ // Transform the element statement.
+ OwningStmtResult Element = getDerived().TransformStmt(S->getElement());
+ if (Element.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the collection expression.
+ OwningExprResult Collection = getDerived().TransformExpr(S->getCollection());
+ if (Collection.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the body.
+ OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ // If nothing changed, just retain this statement.
+ if (!getDerived().AlwaysRebuild() &&
+ Element.get() == S->getElement() &&
+ Collection.get() == S->getCollection() &&
+ Body.get() == S->getBody())
+ return SemaRef.Owned(S->Retain());
+
+ // Build a new statement.
+ return getDerived().RebuildObjCForCollectionStmt(S->getForLoc(),
+ /*FIXME:*/S->getForLoc(),
+ move(Element),
+ move(Collection),
+ S->getRParenLoc(),
+ move(Body));
}
@@ -3828,6 +4183,72 @@ TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) {
template<typename Derived>
Sema::OwningExprResult
+TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) {
+ // Transform the type.
+ TypeSourceInfo *Type = getDerived().TransformType(E->getTypeSourceInfo());
+ if (!Type)
+ return getSema().ExprError();
+
+ // Transform all of the components into components similar to what the
+ // parser uses.
+ // FIXME: It would be slightly more efficient in the non-dependent case to
+ // just map FieldDecls, rather than requiring the rebuilder to look for
+ // the fields again. However, __builtin_offsetof is rare enough in
+ // template code that we don't care.
+ bool ExprChanged = false;
+ typedef Action::OffsetOfComponent Component;
+ typedef OffsetOfExpr::OffsetOfNode Node;
+ llvm::SmallVector<Component, 4> Components;
+ for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
+ const Node &ON = E->getComponent(I);
+ Component Comp;
+ Comp.isBrackets = true;
+ Comp.LocStart = ON.getRange().getBegin();
+ Comp.LocEnd = ON.getRange().getEnd();
+ switch (ON.getKind()) {
+ case Node::Array: {
+ Expr *FromIndex = E->getIndexExpr(ON.getArrayExprIndex());
+ OwningExprResult Index = getDerived().TransformExpr(FromIndex);
+ if (Index.isInvalid())
+ return getSema().ExprError();
+
+ ExprChanged = ExprChanged || Index.get() != FromIndex;
+ Comp.isBrackets = true;
+ Comp.U.E = Index.takeAs<Expr>(); // FIXME: leaked
+ break;
+ }
+
+ case Node::Field:
+ case Node::Identifier:
+ Comp.isBrackets = false;
+ Comp.U.IdentInfo = ON.getFieldName();
+ if (!Comp.U.IdentInfo)
+ continue;
+
+ break;
+
+ case Node::Base:
+ // Will be recomputed during the rebuild.
+ continue;
+ }
+
+ Components.push_back(Comp);
+ }
+
+ // If nothing changed, retain the existing expression.
+ if (!getDerived().AlwaysRebuild() &&
+ Type == E->getTypeSourceInfo() &&
+ !ExprChanged)
+ return SemaRef.Owned(E->Retain());
+
+ // Build a new offsetof expression.
+ return getDerived().RebuildOffsetOfExpr(E->getOperatorLoc(), Type,
+ Components.data(), Components.size(),
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
if (E->isArgumentType()) {
TypeSourceInfo *OldT = E->getArgumentTypeInfo();
@@ -4597,19 +5018,18 @@ template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
if (E->isTypeOperand()) {
- TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
-
- QualType T = getDerived().TransformType(E->getTypeOperand());
- if (T.isNull())
+ TypeSourceInfo *TInfo
+ = getDerived().TransformType(E->getTypeOperandSourceInfo());
+ if (!TInfo)
return SemaRef.ExprError();
if (!getDerived().AlwaysRebuild() &&
- T == E->getTypeOperand())
+ TInfo == E->getTypeOperandSourceInfo())
return SemaRef.Owned(E->Retain());
- return getDerived().RebuildCXXTypeidExpr(E->getLocStart(),
- /*FIXME:*/E->getLocStart(),
- T,
+ return getDerived().RebuildCXXTypeidExpr(E->getType(),
+ E->getLocStart(),
+ TInfo,
E->getLocEnd());
}
@@ -4627,8 +5047,8 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
SubExpr.get() == E->getExprOperand())
return SemaRef.Owned(E->Retain());
- return getDerived().RebuildCXXTypeidExpr(E->getLocStart(),
- /*FIXME:*/E->getLocStart(),
+ return getDerived().RebuildCXXTypeidExpr(E->getType(),
+ E->getLocStart(),
move(SubExpr),
E->getLocEnd());
}
@@ -4997,6 +5417,17 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
SS.setScopeRep(Qualifier);
SS.setRange(Old->getQualifierRange());
+ }
+
+ if (Old->getNamingClass()) {
+ CXXRecordDecl *NamingClass
+ = cast_or_null<CXXRecordDecl>(getDerived().TransformDecl(
+ Old->getNameLoc(),
+ Old->getNamingClass()));
+ if (!NamingClass)
+ return SemaRef.ExprError();
+
+ R.setNamingClass(NamingClass);
}
// If we have no template arguments, it's a normal declaration name.
@@ -5423,6 +5854,18 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
R.resolveKind();
+ // Determine the naming class.
+ if (!Old->getNamingClass()) {
+ CXXRecordDecl *NamingClass
+ = cast_or_null<CXXRecordDecl>(getDerived().TransformDecl(
+ Old->getMemberLoc(),
+ Old->getNamingClass()));
+ if (!NamingClass)
+ return SemaRef.ExprError();
+
+ R.setNamingClass(NamingClass);
+ }
+
TemplateArgumentListInfo TransArgs;
if (Old->hasExplicitTemplateArgs()) {
TransArgs.setLAngleLoc(Old->getLAngleLoc());
@@ -5463,27 +5906,76 @@ TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) {
- // FIXME: poor source location
- TemporaryBase Rebase(*this, E->getAtLoc(), DeclarationName());
- QualType EncodedType = getDerived().TransformType(E->getEncodedType());
- if (EncodedType.isNull())
+ TypeSourceInfo *EncodedTypeInfo
+ = getDerived().TransformType(E->getEncodedTypeSourceInfo());
+ if (!EncodedTypeInfo)
return SemaRef.ExprError();
if (!getDerived().AlwaysRebuild() &&
- EncodedType == E->getEncodedType())
+ EncodedTypeInfo == E->getEncodedTypeSourceInfo())
return SemaRef.Owned(E->Retain());
return getDerived().RebuildObjCEncodeExpr(E->getAtLoc(),
- EncodedType,
+ EncodedTypeInfo,
E->getRParenLoc());
}
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
- // FIXME: Implement this!
- assert(false && "Cannot transform Objective-C expressions yet");
- return SemaRef.Owned(E->Retain());
+ // Transform arguments.
+ bool ArgChanged = false;
+ ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
+ OwningExprResult Arg = getDerived().TransformExpr(E->getArg(I));
+ if (Arg.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgChanged = ArgChanged || Arg.get() != E->getArg(I);
+ Args.push_back(Arg.takeAs<Expr>());
+ }
+
+ if (E->getReceiverKind() == ObjCMessageExpr::Class) {
+ // Class message: transform the receiver type.
+ TypeSourceInfo *ReceiverTypeInfo
+ = getDerived().TransformType(E->getClassReceiverTypeInfo());
+ if (!ReceiverTypeInfo)
+ return SemaRef.ExprError();
+
+ // If nothing changed, just retain the existing message send.
+ if (!getDerived().AlwaysRebuild() &&
+ ReceiverTypeInfo == E->getClassReceiverTypeInfo() && !ArgChanged)
+ return SemaRef.Owned(E->Retain());
+
+ // Build a new class message send.
+ return getDerived().RebuildObjCMessageExpr(ReceiverTypeInfo,
+ E->getSelector(),
+ E->getMethodDecl(),
+ E->getLeftLoc(),
+ move_arg(Args),
+ E->getRightLoc());
+ }
+
+ // Instance message: transform the receiver
+ assert(E->getReceiverKind() == ObjCMessageExpr::Instance &&
+ "Only class and instance messages may be instantiated");
+ OwningExprResult Receiver
+ = getDerived().TransformExpr(E->getInstanceReceiver());
+ if (Receiver.isInvalid())
+ return SemaRef.ExprError();
+
+ // If nothing changed, just retain the existing message send.
+ if (!getDerived().AlwaysRebuild() &&
+ Receiver.get() == E->getInstanceReceiver() && !ArgChanged)
+ return SemaRef.Owned(E->Retain());
+
+ // Build a new instance message send.
+ return getDerived().RebuildObjCMessageExpr(move(Receiver),
+ E->getSelector(),
+ E->getMethodDecl(),
+ E->getLeftLoc(),
+ move_arg(Args),
+ E->getRightLoc());
}
template<typename Derived>
@@ -5495,64 +5987,100 @@ TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E) {
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) {
- ObjCProtocolDecl *Protocol
- = cast_or_null<ObjCProtocolDecl>(
- getDerived().TransformDecl(E->getLocStart(),
- E->getProtocol()));
- if (!Protocol)
- return SemaRef.ExprError();
-
- if (!getDerived().AlwaysRebuild() &&
- Protocol == E->getProtocol())
- return SemaRef.Owned(E->Retain());
-
- return getDerived().RebuildObjCProtocolExpr(Protocol,
- E->getAtLoc(),
- /*FIXME:*/E->getAtLoc(),
- /*FIXME:*/E->getAtLoc(),
- E->getRParenLoc());
-
+ return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) {
- // FIXME: Implement this!
- assert(false && "Cannot transform Objective-C expressions yet");
- return SemaRef.Owned(E->Retain());
+ // Transform the base expression.
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ // We don't need to transform the ivar; it will never change.
+
+ // If nothing changed, just retain the existing expression.
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildObjCIvarRefExpr(move(Base), E->getDecl(),
+ E->getLocation(),
+ E->isArrow(), E->isFreeIvar());
}
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
- // FIXME: Implement this!
- assert(false && "Cannot transform Objective-C expressions yet");
- return SemaRef.Owned(E->Retain());
+ // Transform the base expression.
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ // We don't need to transform the property; it will never change.
+
+ // If nothing changed, just retain the existing expression.
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildObjCPropertyRefExpr(move(Base), E->getProperty(),
+ E->getLocation());
}
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr(
ObjCImplicitSetterGetterRefExpr *E) {
- // FIXME: Implement this!
- assert(false && "Cannot transform Objective-C expressions yet");
- return SemaRef.Owned(E->Retain());
+ // If this implicit setter/getter refers to class methods, it cannot have any
+ // dependent parts. Just retain the existing declaration.
+ if (E->getInterfaceDecl())
+ return SemaRef.Owned(E->Retain());
+
+ // Transform the base expression.
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ // We don't need to transform the getters/setters; they will never change.
+
+ // If nothing changed, just retain the existing expression.
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildObjCImplicitSetterGetterRefExpr(
+ E->getGetterMethod(),
+ E->getType(),
+ E->getSetterMethod(),
+ E->getLocation(),
+ move(Base));
+
}
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E) {
- // FIXME: Implement this!
- assert(false && "Cannot transform Objective-C expressions yet");
+ // Can never occur in a dependent context.
return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) {
- // FIXME: Implement this!
- assert(false && "Cannot transform Objective-C expressions yet");
- return SemaRef.Owned(E->Retain());
+ // Transform the base expression.
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ // If nothing changed, just retain the existing expression.
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildObjCIsaExpr(move(Base), E->getIsaMemberLoc(),
+ E->isArrow());
}
template<typename Derived>
@@ -5632,14 +6160,6 @@ TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType,
template<typename Derived>
QualType
-TreeTransform<Derived>::RebuildObjCObjectPointerType(QualType PointeeType,
- SourceLocation Sigil) {
- return SemaRef.BuildPointerType(PointeeType, Qualifiers(), Sigil,
- getDerived().getBaseEntity());
-}
-
-template<typename Derived>
-QualType
TreeTransform<Derived>::RebuildArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt *Size,
@@ -5767,6 +6287,7 @@ QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(Decl *D) {
assert(D && "no decl found");
if (D->isInvalidDecl()) return QualType();
+ // FIXME: Doesn't account for ObjCInterfaceDecl!
TypeDecl *Ty;
if (isa<UsingDecl>(D)) {
UsingDecl *Using = cast<UsingDecl>(D);
OpenPOWER on IntegriCloud