summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2009-12-15 18:49:47 +0000
committerrdivacky <rdivacky@FreeBSD.org>2009-12-15 18:49:47 +0000
commit77212133072dc40f070a280af8217032f55a9eb4 (patch)
tree2fd5819f49caecc5f520219b6b9254fe94ebb138 /lib
parent4b08eb6308ca90a6c08e2fc79d100821b1b1f6aa (diff)
downloadFreeBSD-src-77212133072dc40f070a280af8217032f55a9eb4.zip
FreeBSD-src-77212133072dc40f070a280af8217032f55a9eb4.tar.gz
Update clang to 91430.
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/ASTContext.cpp216
-rw-r--r--lib/AST/CXXInheritance.cpp51
-rw-r--r--lib/AST/Decl.cpp47
-rw-r--r--lib/AST/DeclBase.cpp48
-rw-r--r--lib/AST/DeclCXX.cpp190
-rw-r--r--lib/AST/DeclObjC.cpp4
-rw-r--r--lib/AST/DeclPrinter.cpp35
-rw-r--r--lib/AST/DeclTemplate.cpp4
-rw-r--r--lib/AST/DeclarationName.cpp2
-rw-r--r--lib/AST/Expr.cpp64
-rw-r--r--lib/AST/ExprCXX.cpp46
-rw-r--r--lib/AST/ExprConstant.cpp53
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp78
-rw-r--r--lib/AST/RecordLayoutBuilder.h1
-rw-r--r--lib/AST/StmtDumper.cpp264
-rw-r--r--lib/AST/StmtPrinter.cpp16
-rw-r--r--lib/AST/StmtProfile.cpp25
-rw-r--r--lib/AST/TemplateBase.cpp2
-rw-r--r--lib/AST/TemplateName.cpp28
-rw-r--r--lib/AST/Type.cpp46
-rw-r--r--lib/AST/TypeLoc.cpp29
-rw-r--r--lib/AST/TypePrinter.cpp40
-rw-r--r--lib/Analysis/AnalysisContext.cpp153
-rw-r--r--lib/Analysis/BasicStore.cpp10
-rw-r--r--lib/Analysis/BugReporter.cpp17
-rw-r--r--lib/Analysis/BuiltinFunctionChecker.cpp76
-rw-r--r--lib/Analysis/CFG.cpp12
-rw-r--r--lib/Analysis/CFRefCount.cpp117
-rw-r--r--lib/Analysis/CMakeLists.txt4
-rw-r--r--lib/Analysis/CallAndMessageChecker.cpp27
-rw-r--r--lib/Analysis/CheckDeadStores.cpp7
-rw-r--r--lib/Analysis/CheckSecuritySyntaxOnly.cpp42
-rw-r--r--lib/Analysis/Checker.cpp4
-rw-r--r--lib/Analysis/GRExprEngine.cpp541
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.h3
-rw-r--r--lib/Analysis/GRState.cpp12
-rw-r--r--lib/Analysis/MallocChecker.cpp123
-rw-r--r--lib/Analysis/MemRegion.cpp362
-rw-r--r--lib/Analysis/NoReturnFunctionChecker.cpp80
-rw-r--r--lib/Analysis/OSAtomicChecker.cpp196
-rw-r--r--lib/Analysis/PathDiagnostic.cpp49
-rw-r--r--lib/Analysis/RegionStore.cpp123
-rw-r--r--lib/Analysis/Store.cpp37
-rw-r--r--lib/Analysis/SymbolManager.cpp5
-rw-r--r--lib/Analysis/ValueManager.cpp9
-rw-r--r--lib/Basic/Diagnostic.cpp6
-rw-r--r--lib/Basic/FileManager.cpp114
-rw-r--r--lib/Basic/SourceManager.cpp196
-rw-r--r--lib/CodeGen/CGBlocks.cpp22
-rw-r--r--lib/CodeGen/CGBuiltin.cpp49
-rw-r--r--lib/CodeGen/CGCXX.cpp419
-rw-r--r--lib/CodeGen/CGCall.cpp5
-rw-r--r--lib/CodeGen/CGClass.cpp36
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp311
-rw-r--r--lib/CodeGen/CGDebugInfo.h9
-rw-r--r--lib/CodeGen/CGDecl.cpp286
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp211
-rw-r--r--lib/CodeGen/CGException.cpp542
-rw-r--r--lib/CodeGen/CGExpr.cpp104
-rw-r--r--lib/CodeGen/CGExprAgg.cpp19
-rw-r--r--lib/CodeGen/CGExprCXX.cpp189
-rw-r--r--lib/CodeGen/CGExprConstant.cpp6
-rw-r--r--lib/CodeGen/CGExprScalar.cpp119
-rw-r--r--lib/CodeGen/CGObjCMac.cpp62
-rw-r--r--lib/CodeGen/CGRTTI.cpp (renamed from lib/CodeGen/CGRtti.cpp)261
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp10
-rw-r--r--lib/CodeGen/CGVtable.cpp955
-rw-r--r--lib/CodeGen/CGVtable.h47
-rw-r--r--lib/CodeGen/CMakeLists.txt3
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp73
-rw-r--r--lib/CodeGen/CodeGenFunction.h119
-rw-r--r--lib/CodeGen/CodeGenModule.cpp88
-rw-r--r--lib/CodeGen/CodeGenModule.h49
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp8
-rw-r--r--lib/CodeGen/GlobalDecl.h15
-rw-r--r--lib/CodeGen/Mangle.cpp261
-rw-r--r--lib/CodeGen/Mangle.h7
-rw-r--r--lib/CodeGen/TargetABIInfo.cpp22
-rw-r--r--lib/Driver/Driver.cpp217
-rw-r--r--lib/Driver/DriverOptions.cpp2
-rw-r--r--lib/Driver/Job.cpp9
-rw-r--r--lib/Driver/OptTable.cpp122
-rw-r--r--lib/Driver/ToolChains.cpp2
-rw-r--r--lib/Driver/Tools.cpp77
-rw-r--r--lib/Driver/Types.cpp4
-rw-r--r--lib/Frontend/ASTConsumers.cpp9
-rw-r--r--lib/Frontend/ASTUnit.cpp130
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp38
-rw-r--r--lib/Frontend/Backend.cpp101
-rw-r--r--lib/Frontend/CompilerInstance.cpp14
-rw-r--r--lib/Frontend/CompilerInvocation.cpp89
-rw-r--r--lib/Frontend/DiagChecker.cpp10
-rw-r--r--lib/Frontend/FixItRewriter.cpp2
-rw-r--r--lib/Frontend/FrontendAction.cpp8
-rw-r--r--lib/Frontend/FrontendActions.cpp51
-rw-r--r--lib/Frontend/HTMLPrint.cpp4
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp140
-rw-r--r--lib/Frontend/InitPreprocessor.cpp82
-rw-r--r--lib/Frontend/LangStandards.cpp4
-rw-r--r--lib/Frontend/PCHReader.cpp37
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp9
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp6
-rw-r--r--lib/Frontend/PCHWriter.cpp22
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp20
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp2
-rw-r--r--lib/Frontend/PlistDiagnostics.cpp39
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp60
-rw-r--r--lib/Frontend/RewriteObjC.cpp312
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp49
-rw-r--r--lib/Headers/limits.h1
-rw-r--r--lib/Headers/tmmintrin.h2
-rw-r--r--lib/Index/ASTVisitor.h6
-rw-r--r--lib/Index/CMakeLists.txt1
-rw-r--r--lib/Index/CallGraph.cpp (renamed from lib/Analysis/CallGraph.cpp)2
-rw-r--r--lib/Index/ResolveLocation.cpp42
-rw-r--r--lib/Lex/Lexer.cpp191
-rw-r--r--lib/Lex/MacroArgs.cpp18
-rw-r--r--lib/Lex/MacroArgs.h30
-rw-r--r--lib/Lex/PPDirectives.cpp14
-rw-r--r--lib/Lex/PPExpressions.cpp52
-rw-r--r--lib/Lex/PPLexerChange.cpp8
-rw-r--r--lib/Lex/PPMacroExpansion.cpp19
-rw-r--r--lib/Lex/Preprocessor.cpp68
-rw-r--r--lib/Lex/TokenLexer.cpp13
-rw-r--r--lib/Parse/DeclSpec.cpp12
-rw-r--r--lib/Parse/ExtensionRAIIObject.h40
-rw-r--r--lib/Parse/MinimalAction.cpp1
-rw-r--r--lib/Parse/ParseDecl.cpp36
-rw-r--r--lib/Parse/ParseDeclCXX.cpp76
-rw-r--r--lib/Parse/ParseExpr.cpp18
-rw-r--r--lib/Parse/ParseExprCXX.cpp21
-rw-r--r--lib/Parse/ParseObjc.cpp155
-rw-r--r--lib/Parse/ParseStmt.cpp24
-rw-r--r--lib/Parse/ParseTemplate.cpp3
-rw-r--r--lib/Parse/Parser.cpp37
-rw-r--r--lib/Parse/RAIIObjectsForParser.h85
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp2
-rw-r--r--lib/Sema/Lookup.h19
-rw-r--r--lib/Sema/ParseAST.cpp9
-rw-r--r--lib/Sema/Sema.cpp49
-rw-r--r--lib/Sema/Sema.h238
-rw-r--r--lib/Sema/SemaAttr.cpp9
-rw-r--r--lib/Sema/SemaCXXCast.cpp28
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp95
-rw-r--r--lib/Sema/SemaChecking.cpp18
-rw-r--r--lib/Sema/SemaCodeComplete.cpp522
-rw-r--r--lib/Sema/SemaDecl.cpp587
-rw-r--r--lib/Sema/SemaDeclAttr.cpp102
-rw-r--r--lib/Sema/SemaDeclCXX.cpp1104
-rw-r--r--lib/Sema/SemaDeclObjC.cpp12
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp17
-rw-r--r--lib/Sema/SemaExpr.cpp1065
-rw-r--r--lib/Sema/SemaExprCXX.cpp82
-rw-r--r--lib/Sema/SemaInit.cpp1398
-rw-r--r--lib/Sema/SemaInit.h579
-rw-r--r--lib/Sema/SemaLookup.cpp84
-rw-r--r--lib/Sema/SemaOverload.cpp376
-rw-r--r--lib/Sema/SemaOverload.h22
-rw-r--r--lib/Sema/SemaTemplate.cpp251
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp1
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp63
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp364
-rw-r--r--lib/Sema/SemaType.cpp123
-rw-r--r--lib/Sema/TreeTransform.h663
164 files changed, 12940 insertions, 5509 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 6c9ecf0..cc7055d 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -260,24 +260,40 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
}
NamedDecl *
-ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) {
+ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) {
llvm::DenseMap<UsingDecl *, NamedDecl *>::const_iterator Pos
- = InstantiatedFromUnresolvedUsingDecl.find(UUD);
- if (Pos == InstantiatedFromUnresolvedUsingDecl.end())
+ = InstantiatedFromUsingDecl.find(UUD);
+ if (Pos == InstantiatedFromUsingDecl.end())
return 0;
return Pos->second;
}
void
-ASTContext::setInstantiatedFromUnresolvedUsingDecl(UsingDecl *UD,
- NamedDecl *UUD) {
- assert((isa<UnresolvedUsingValueDecl>(UUD) ||
- isa<UnresolvedUsingTypenameDecl>(UUD)) &&
- "original declaration is not an unresolved using decl");
- assert(!InstantiatedFromUnresolvedUsingDecl[UD] &&
- "Already noted what using decl what instantiated from");
- InstantiatedFromUnresolvedUsingDecl[UD] = UUD;
+ASTContext::setInstantiatedFromUsingDecl(UsingDecl *Inst, NamedDecl *Pattern) {
+ assert((isa<UsingDecl>(Pattern) ||
+ isa<UnresolvedUsingValueDecl>(Pattern) ||
+ isa<UnresolvedUsingTypenameDecl>(Pattern)) &&
+ "pattern decl is not a using decl");
+ assert(!InstantiatedFromUsingDecl[Inst] && "pattern already exists");
+ InstantiatedFromUsingDecl[Inst] = Pattern;
+}
+
+UsingShadowDecl *
+ASTContext::getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst) {
+ llvm::DenseMap<UsingShadowDecl*, UsingShadowDecl*>::const_iterator Pos
+ = InstantiatedFromUsingShadowDecl.find(Inst);
+ if (Pos == InstantiatedFromUsingShadowDecl.end())
+ return 0;
+
+ return Pos->second;
+}
+
+void
+ASTContext::setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst,
+ UsingShadowDecl *Pattern) {
+ assert(!InstantiatedFromUsingShadowDecl[Inst] && "pattern already exists");
+ InstantiatedFromUsingShadowDecl[Inst] = Pattern;
}
FieldDecl *ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) {
@@ -711,10 +727,6 @@ ASTContext::getTypeInfo(const Type *T) {
break;
}
case Type::MemberPointer: {
- // FIXME: This is ABI dependent. We use the Itanium C++ ABI.
- // http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers
- // If we ever want to support other ABIs this needs to be abstracted.
-
QualType Pointee = cast<MemberPointerType>(T)->getPointeeType();
std::pair<uint64_t, unsigned> PtrDiffInfo =
getTypeInfo(getPointerDiffType());
@@ -997,31 +1009,31 @@ void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD,
ObjCImpls[CatD] = ImplD;
}
-/// \brief Allocate an uninitialized DeclaratorInfo.
+/// \brief Allocate an uninitialized TypeSourceInfo.
///
-/// The caller should initialize the memory held by DeclaratorInfo using
+/// The caller should initialize the memory held by TypeSourceInfo using
/// the TypeLoc wrappers.
///
/// \param T the type that will be the basis for type source info. This type
/// should refer to how the declarator was written in source code, not to
/// what type semantic analysis resolved the declarator to.
-DeclaratorInfo *ASTContext::CreateDeclaratorInfo(QualType T,
+TypeSourceInfo *ASTContext::CreateTypeSourceInfo(QualType T,
unsigned DataSize) {
if (!DataSize)
DataSize = TypeLoc::getFullDataSizeForType(T);
else
assert(DataSize == TypeLoc::getFullDataSizeForType(T) &&
- "incorrect data size provided to CreateDeclaratorInfo!");
+ "incorrect data size provided to CreateTypeSourceInfo!");
- DeclaratorInfo *DInfo =
- (DeclaratorInfo*)BumpAlloc.Allocate(sizeof(DeclaratorInfo) + DataSize, 8);
- new (DInfo) DeclaratorInfo(T);
- return DInfo;
+ TypeSourceInfo *TInfo =
+ (TypeSourceInfo*)BumpAlloc.Allocate(sizeof(TypeSourceInfo) + DataSize, 8);
+ new (TInfo) TypeSourceInfo(T);
+ return TInfo;
}
-DeclaratorInfo *ASTContext::getTrivialDeclaratorInfo(QualType T,
+TypeSourceInfo *ASTContext::getTrivialTypeSourceInfo(QualType T,
SourceLocation L) {
- DeclaratorInfo *DI = CreateDeclaratorInfo(T);
+ TypeSourceInfo *DI = CreateTypeSourceInfo(T);
DI->getTypeLoc().initialize(L);
return DI;
}
@@ -1092,6 +1104,20 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
return *NewEntry;
}
+const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
+ RD = cast<CXXRecordDecl>(RD->getDefinition(*this));
+ assert(RD && "Cannot get key function for forward declarations!");
+
+ const CXXMethodDecl *&Entry = KeyFunctions[RD];
+ if (!Entry)
+ Entry = ASTRecordLayoutBuilder::ComputeKeyFunction(RD);
+ else
+ assert(Entry == ASTRecordLayoutBuilder::ComputeKeyFunction(RD) &&
+ "Key function changed!");
+
+ return Entry;
+}
+
//===----------------------------------------------------------------------===//
// Type creation/memoization methods
//===----------------------------------------------------------------------===//
@@ -1174,32 +1200,42 @@ QualType ASTContext::getObjCGCQualType(QualType T,
return getExtQualType(TypeNode, Quals);
}
-QualType ASTContext::getNoReturnType(QualType T) {
+QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) {
QualType ResultType;
- if (T->isPointerType()) {
- QualType Pointee = T->getAs<PointerType>()->getPointeeType();
- ResultType = getNoReturnType(Pointee);
+ if (const PointerType *Pointer = T->getAs<PointerType>()) {
+ QualType Pointee = Pointer->getPointeeType();
+ ResultType = getNoReturnType(Pointee, AddNoReturn);
+ if (ResultType == Pointee)
+ return T;
+
ResultType = getPointerType(ResultType);
- } else if (T->isBlockPointerType()) {
- QualType Pointee = T->getAs<BlockPointerType>()->getPointeeType();
- ResultType = getNoReturnType(Pointee);
+ } else if (const BlockPointerType *BlockPointer
+ = T->getAs<BlockPointerType>()) {
+ QualType Pointee = BlockPointer->getPointeeType();
+ ResultType = getNoReturnType(Pointee, AddNoReturn);
+ if (ResultType == Pointee)
+ return T;
+
ResultType = getBlockPointerType(ResultType);
- } else {
- assert (T->isFunctionType()
- && "can't noreturn qualify non-pointer to function or block type");
-
- if (const FunctionNoProtoType *FNPT = T->getAs<FunctionNoProtoType>()) {
- ResultType = getFunctionNoProtoType(FNPT->getResultType(), true);
+ } else if (const FunctionType *F = T->getAs<FunctionType>()) {
+ if (F->getNoReturnAttr() == AddNoReturn)
+ return T;
+
+ if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(F)) {
+ ResultType = getFunctionNoProtoType(FNPT->getResultType(), AddNoReturn);
} else {
- const FunctionProtoType *F = T->getAs<FunctionProtoType>();
+ const FunctionProtoType *FPT = cast<FunctionProtoType>(F);
ResultType
- = getFunctionType(F->getResultType(), F->arg_type_begin(),
- F->getNumArgs(), F->isVariadic(), F->getTypeQuals(),
- F->hasExceptionSpec(), F->hasAnyExceptionSpec(),
- F->getNumExceptions(), F->exception_begin(), true);
+ = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(),
+ FPT->getNumArgs(), FPT->isVariadic(),
+ FPT->getTypeQuals(),
+ FPT->hasExceptionSpec(), FPT->hasAnyExceptionSpec(),
+ FPT->getNumExceptions(), FPT->exception_begin(),
+ AddNoReturn);
}
- }
-
+ } else
+ return T;
+
return getQualifiedType(ResultType, T.getLocalQualifiers());
}
@@ -1766,6 +1802,9 @@ QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) {
Decl->TypeForDecl = PrevDecl->TypeForDecl;
else
Decl->TypeForDecl = new (*this, TypeAlignment) EnumType(Enum);
+ } else if (UnresolvedUsingTypenameDecl *Using =
+ dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) {
+ Decl->TypeForDecl = new (*this, TypeAlignment) UnresolvedUsingType(Using);
} else
assert(false && "TypeDecl without a type?");
@@ -2238,7 +2277,7 @@ QualType ASTContext::getTagDeclType(const TagDecl *Decl) {
/// getSizeType - Return the unique type for "size_t" (C99 7.17), the result
/// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and
/// needs to agree with the definition in <stddef.h>.
-QualType ASTContext::getSizeType() const {
+CanQualType ASTContext::getSizeType() const {
return getFromTargetType(Target.getSizeType());
}
@@ -2354,8 +2393,9 @@ DeclarationName ASTContext::getNameForTemplate(TemplateName Name) {
}
}
- assert(Name.getAsOverloadedFunctionDecl());
- return Name.getAsOverloadedFunctionDecl()->getDeclName();
+ OverloadedTemplateStorage *Storage = Name.getAsOverloadedTemplate();
+ assert(Storage);
+ return (*Storage->begin())->getDeclName();
}
TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) {
@@ -2364,27 +2404,7 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) {
if (TemplateDecl *Template = Name.getAsTemplateDecl())
return TemplateName(cast<TemplateDecl>(Template->getCanonicalDecl()));
- // If this template name refers to a set of overloaded function templates,
- /// the canonical template name merely stores the set of function templates.
- if (OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl()) {
- OverloadedFunctionDecl *CanonOvl = 0;
- for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
- FEnd = Ovl->function_end();
- F != FEnd; ++F) {
- Decl *Canon = F->get()->getCanonicalDecl();
- if (CanonOvl || Canon != F->get()) {
- if (!CanonOvl)
- CanonOvl = OverloadedFunctionDecl::Create(*this,
- Ovl->getDeclContext(),
- Ovl->getDeclName());
-
- CanonOvl->addOverload(
- AnyFunctionDecl::getFromNamedDecl(cast<NamedDecl>(Canon)));
- }
- }
-
- return TemplateName(CanonOvl? CanonOvl : Ovl);
- }
+ assert(!Name.getAsOverloadedTemplate());
DependentTemplateName *DTN = Name.getAsDependentTemplateName();
assert(DTN && "Non-dependent template names must refer to template decls.");
@@ -2651,7 +2671,7 @@ int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) {
unsigned ASTContext::getIntegerRank(Type *T) {
assert(T->isCanonicalUnqualified() && "T should be canonicalized");
if (EnumType* ET = dyn_cast<EnumType>(T))
- T = ET->getDecl()->getIntegerType().getTypePtr();
+ T = ET->getDecl()->getPromotionType().getTypePtr();
if (T->isSpecificBuiltinType(BuiltinType::WChar))
T = getFromTargetType(Target.getWCharType()).getTypePtr();
@@ -2732,6 +2752,8 @@ QualType ASTContext::isPromotableBitField(Expr *E) {
QualType ASTContext::getPromotedIntegerType(QualType Promotable) {
assert(!Promotable.isNull());
assert(Promotable->isPromotableIntegerType());
+ if (const EnumType *ET = Promotable->getAs<EnumType>())
+ return ET->getDecl()->getPromotionType();
if (Promotable->isSignedIntegerType())
return IntTy;
uint64_t PromotableSize = getTypeSize(Promotable);
@@ -2812,7 +2834,7 @@ QualType ASTContext::getCFConstantStringType() {
for (unsigned i = 0; i < 4; ++i) {
FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl,
SourceLocation(), 0,
- FieldTypes[i], /*DInfo=*/0,
+ FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
/*Mutable=*/false);
CFConstantStringTypeDecl->addDecl(Field);
@@ -2848,7 +2870,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() {
FieldDecl *Field = FieldDecl::Create(*this,
ObjCFastEnumerationStateTypeDecl,
SourceLocation(), 0,
- FieldTypes[i], /*DInfo=*/0,
+ FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
/*Mutable=*/false);
ObjCFastEnumerationStateTypeDecl->addDecl(Field);
@@ -2884,7 +2906,7 @@ QualType ASTContext::getBlockDescriptorType() {
T,
SourceLocation(),
&Idents.get(FieldNames[i]),
- FieldTypes[i], /*DInfo=*/0,
+ FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
/*Mutable=*/false);
T->addDecl(Field);
@@ -2931,7 +2953,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() {
T,
SourceLocation(),
&Idents.get(FieldNames[i]),
- FieldTypes[i], /*DInfo=*/0,
+ FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
/*Mutable=*/false);
T->addDecl(Field);
@@ -3009,7 +3031,7 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) {
continue;
FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
&Idents.get(FieldNames[i]),
- FieldTypes[i], /*DInfo=*/0,
+ FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0, /*Mutable=*/false);
T->addDecl(Field);
}
@@ -3052,7 +3074,7 @@ QualType ASTContext::getBlockParmType(
for (size_t i = 0; i < 5; ++i) {
FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
&Idents.get(FieldNames[i]),
- FieldTypes[i], /*DInfo=*/0,
+ FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0, /*Mutable=*/false);
T->addDecl(Field);
}
@@ -3072,7 +3094,7 @@ QualType ASTContext::getBlockParmType(
FieldType);
FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
- Name, FieldType, /*DInfo=*/0,
+ Name, FieldType, /*TInfo=*/0,
/*BitWidth=*/0, /*Mutable=*/false);
T->addDecl(Field);
}
@@ -3690,36 +3712,40 @@ void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) {
ObjCConstantStringType = getObjCInterfaceType(Decl);
}
-/// \brief Retrieve the template name that represents a qualified
-/// template name such as \c std::vector.
-TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
- bool TemplateKeyword,
- TemplateDecl *Template) {
- llvm::FoldingSetNodeID ID;
- QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template);
+/// \brief Retrieve the template name that corresponds to a non-empty
+/// lookup.
+TemplateName ASTContext::getOverloadedTemplateName(NamedDecl * const *Begin,
+ NamedDecl * const *End) {
+ unsigned size = End - Begin;
+ assert(size > 1 && "set is not overloaded!");
- void *InsertPos = 0;
- QualifiedTemplateName *QTN =
- QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
- if (!QTN) {
- QTN = new (*this,4) QualifiedTemplateName(NNS, TemplateKeyword, Template);
- QualifiedTemplateNames.InsertNode(QTN, InsertPos);
+ void *memory = Allocate(sizeof(OverloadedTemplateStorage) +
+ size * sizeof(FunctionTemplateDecl*));
+ OverloadedTemplateStorage *OT = new(memory) OverloadedTemplateStorage(size);
+
+ NamedDecl **Storage = OT->getStorage();
+ for (NamedDecl * const *I = Begin; I != End; ++I) {
+ NamedDecl *D = *I;
+ assert(isa<FunctionTemplateDecl>(D) ||
+ (isa<UsingShadowDecl>(D) &&
+ isa<FunctionTemplateDecl>(D->getUnderlyingDecl())));
+ *Storage++ = D;
}
- return TemplateName(QTN);
+ return TemplateName(OT);
}
/// \brief Retrieve the template name that represents a qualified
/// template name such as \c std::vector.
TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
bool TemplateKeyword,
- OverloadedFunctionDecl *Template) {
+ TemplateDecl *Template) {
llvm::FoldingSetNodeID ID;
QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template);
void *InsertPos = 0;
QualifiedTemplateName *QTN =
- QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
+ QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
if (!QTN) {
QTN = new (*this,4) QualifiedTemplateName(NNS, TemplateKeyword, Template);
QualifiedTemplateNames.InsertNode(QTN, InsertPos);
@@ -4334,6 +4360,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
if (LHSClass != RHSClass) {
// C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
// a signed integer type, or an unsigned integer type.
+ // Compatibility is based on the underlying type, not the promotion
+ // type.
if (const EnumType* ETy = LHS->getAs<EnumType>()) {
if (ETy->getDecl()->getIntegerType() == RHSCan.getUnqualifiedType())
return RHS;
@@ -4493,6 +4521,8 @@ unsigned ASTContext::getIntWidth(QualType T) {
if (FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) {
return FWIT->getWidth();
}
+ if (EnumType *ET = dyn_cast<EnumType>(T))
+ T = ET->getDecl()->getIntegerType();
// For builtin types, just use the standard type sizing method
return (unsigned)getTypeSize(T);
}
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index 023bca4..92a58b7 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -90,6 +90,57 @@ bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) cons
return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths);
}
+static bool BaseIsNot(const CXXRecordDecl *Base, void *OpaqueTarget) {
+ // OpaqueTarget is a CXXRecordDecl*.
+ return Base->getCanonicalDecl() != (const CXXRecordDecl*) OpaqueTarget;
+}
+
+bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const {
+ return forallBases(BaseIsNot, (void*) Base->getCanonicalDecl());
+}
+
+bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
+ void *OpaqueData,
+ bool AllowShortCircuit) const {
+ ASTContext &Context = getASTContext();
+ llvm::SmallVector<const CXXRecordDecl*, 8> Queue;
+
+ const CXXRecordDecl *Record = this;
+ bool AllMatches = true;
+ while (true) {
+ for (CXXRecordDecl::base_class_const_iterator
+ I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) {
+ const RecordType *Ty = I->getType()->getAs<RecordType>();
+ if (!Ty) {
+ if (AllowShortCircuit) return false;
+ AllMatches = false;
+ continue;
+ }
+
+ CXXRecordDecl *Base =
+ cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition(Context));
+ if (!Base) {
+ if (AllowShortCircuit) return false;
+ AllMatches = false;
+ continue;
+ }
+
+ Queue.push_back(Base);
+ if (!BaseMatches(Base, OpaqueData)) {
+ if (AllowShortCircuit) return false;
+ AllMatches = false;
+ continue;
+ }
+ }
+
+ if (Queue.empty()) break;
+ Record = Queue.back(); // not actually a queue.
+ Queue.pop_back();
+ }
+
+ return AllMatches;
+}
+
bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
void *UserData,
CXXBasePaths &Paths) const {
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 572d76f..4d0d422 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -38,7 +38,7 @@ void Attr::Destroy(ASTContext &C) {
}
/// \brief Return the TypeLoc wrapper for the type source info.
-TypeLoc DeclaratorInfo::getTypeLoc() const {
+TypeLoc TypeSourceInfo::getTypeLoc() const {
return TypeLoc(Ty, (void*)(this + 1));
}
@@ -86,17 +86,17 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
- QualType T, DeclaratorInfo *DInfo,
+ QualType T, TypeSourceInfo *TInfo,
StorageClass S, Expr *DefArg) {
- return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, DInfo, S, DefArg);
+ return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg);
}
SourceRange ParmVarDecl::getDefaultArgRange() const {
if (const Expr *E = getInit())
return E->getSourceRange();
- if (const Expr *E = getUninstantiatedDefaultArg())
- return E->getSourceRange();
+ if (hasUninstantiatedDefaultArg())
+ return getUninstantiatedDefaultArg()->getSourceRange();
return SourceRange();
}
@@ -136,11 +136,11 @@ bool VarDecl::isExternC() const {
FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
DeclarationName N, QualType T,
- DeclaratorInfo *DInfo,
+ TypeSourceInfo *TInfo,
StorageClass S, bool isInline,
bool hasWrittenPrototype) {
FunctionDecl *New
- = new (C) FunctionDecl(Function, DC, L, N, T, DInfo, S, isInline);
+ = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline);
New->HasWrittenPrototype = hasWrittenPrototype;
return New;
}
@@ -151,8 +151,8 @@ BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, QualType T,
- DeclaratorInfo *DInfo, Expr *BW, bool Mutable) {
- return new (C) FieldDecl(Decl::Field, DC, L, Id, T, DInfo, BW, Mutable);
+ TypeSourceInfo *TInfo, Expr *BW, bool Mutable) {
+ return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable);
}
bool FieldDecl::isAnonymousStructOrUnion() const {
@@ -179,8 +179,8 @@ void EnumConstantDecl::Destroy(ASTContext& C) {
TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
- DeclaratorInfo *DInfo) {
- return new (C) TypedefDecl(DC, L, Id, DInfo);
+ TypeSourceInfo *TInfo) {
+ return new (C) TypedefDecl(DC, L, Id, TInfo);
}
EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
@@ -195,9 +195,12 @@ void EnumDecl::Destroy(ASTContext& C) {
Decl::Destroy(C);
}
-void EnumDecl::completeDefinition(ASTContext &C, QualType NewType) {
+void EnumDecl::completeDefinition(ASTContext &C,
+ QualType NewType,
+ QualType NewPromotionType) {
assert(!isDefinition() && "Cannot redefine enums!");
IntegerType = NewType;
+ PromotionType = NewPromotionType;
TagDecl::completeDefinition();
}
@@ -535,9 +538,9 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
//===----------------------------------------------------------------------===//
VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, QualType T, DeclaratorInfo *DInfo,
+ IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
StorageClass S) {
- return new (C) VarDecl(Var, DC, L, Id, T, DInfo, S);
+ return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S);
}
void VarDecl::Destroy(ASTContext& C) {
@@ -838,8 +841,20 @@ unsigned FunctionDecl::getMinRequiredArguments() const {
}
bool FunctionDecl::isInlined() const {
- if (isInlineSpecified() || (isa<CXXMethodDecl>(this) && !isOutOfLine()))
+ // FIXME: This is not enough. Consider:
+ //
+ // inline void f();
+ // void f() { }
+ //
+ // f is inlined, but does not have inline specified.
+ // To fix this we should add an 'inline' flag to FunctionDecl.
+ if (isInlineSpecified())
return true;
+
+ if (isa<CXXMethodDecl>(this)) {
+ if (!isOutOfLine() || getCanonicalDecl()->isInlineSpecified())
+ return true;
+ }
switch (getTemplateSpecializationKind()) {
case TSK_Undeclared:
@@ -1199,7 +1214,7 @@ TagDecl* TagDecl::getDefinition(ASTContext& C) const {
TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) {
switch (TypeSpec) {
- default: llvm::llvm_unreachable("unexpected type specifier");
+ default: llvm_unreachable("unexpected type specifier");
case DeclSpec::TST_struct: return TK_struct;
case DeclSpec::TST_class: return TK_class;
case DeclSpec::TST_union: return TK_union;
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 2dcd80b..3afb4e4 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -190,7 +190,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case CXXConstructor:
case CXXDestructor:
case CXXConversion:
- case OverloadedFunction:
case Typedef:
case EnumConstant:
case Var:
@@ -199,7 +198,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case NonTypeTemplateParm:
case ObjCMethod:
case ObjCContainer:
- case ObjCCategory:
case ObjCInterface:
case ObjCProperty:
case ObjCCompatibleAlias:
@@ -221,8 +219,9 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCImplementation:
return IDNS_ObjCImplementation;
+ case ObjCCategory:
case ObjCCategoryImpl:
- return IDNS_ObjCCategoryImpl;
+ return IDNS_ObjCCategoryName;
case Field:
case ObjCAtDefsField:
@@ -637,6 +636,46 @@ bool DeclContext::decls_empty() const {
return !FirstDecl;
}
+void DeclContext::removeDecl(Decl *D) {
+ assert(D->getLexicalDeclContext() == this &&
+ "decl being removed from non-lexical context");
+ assert((D->NextDeclInContext || D == LastDecl) &&
+ "decl is not in decls list");
+
+ // Remove D from the decl chain. This is O(n) but hopefully rare.
+ if (D == FirstDecl) {
+ if (D == LastDecl)
+ FirstDecl = LastDecl = 0;
+ else
+ FirstDecl = D->NextDeclInContext;
+ } else {
+ for (Decl *I = FirstDecl; true; I = I->NextDeclInContext) {
+ assert(I && "decl not found in linked list");
+ if (I->NextDeclInContext == D) {
+ I->NextDeclInContext = D->NextDeclInContext;
+ if (D == LastDecl) LastDecl = I;
+ break;
+ }
+ }
+ }
+
+ // Mark that D is no longer in the decl chain.
+ D->NextDeclInContext = 0;
+
+ // Remove D from the lookup table if necessary.
+ if (isa<NamedDecl>(D)) {
+ NamedDecl *ND = cast<NamedDecl>(D);
+
+ void *OpaqueMap = getPrimaryContext()->LookupPtr;
+ if (!OpaqueMap) return;
+
+ StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(OpaqueMap);
+ StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName());
+ assert(Pos != Map->end() && "no lookup entry for decl");
+ Pos->second.remove(ND);
+ }
+}
+
void DeclContext::addHiddenDecl(Decl *D) {
assert(D->getLexicalDeclContext() == this &&
"Decl inserted into wrong lexical context");
@@ -742,6 +781,9 @@ void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) {
// from being visible?
if (isa<ClassTemplateSpecializationDecl>(D))
return;
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->isFunctionTemplateSpecialization())
+ return;
DeclContext *PrimaryContext = getPrimaryContext();
if (PrimaryContext != this) {
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 4001988..292a3ed 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -438,6 +439,18 @@ void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
Conversions.addDecl(ConvDecl);
}
+
+void CXXRecordDecl::setMethodAsVirtual(FunctionDecl *Method) {
+ Method->setVirtualAsWritten(true);
+ setAggregate(false);
+ setPOD(false);
+ setEmpty(false);
+ setPolymorphic(true);
+ setHasTrivialConstructor(false);
+ setHasTrivialCopyConstructor(false);
+ setHasTrivialCopyAssignment(false);
+}
+
CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo())
return cast<CXXRecordDecl>(MSInfo->getInstantiatedFrom());
@@ -459,8 +472,8 @@ CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
= new (getASTContext()) MemberSpecializationInfo(RD, TSK);
}
-TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() {
- if (ClassTemplateSpecializationDecl *Spec
+TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() const{
+ if (const ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(this))
return Spec->getSpecializationKind();
@@ -507,8 +520,7 @@ CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {
return 0;
}
-const CXXDestructorDecl *
-CXXRecordDecl::getDestructor(ASTContext &Context) {
+CXXDestructorDecl *CXXRecordDecl::getDestructor(ASTContext &Context) {
QualType ClassType = Context.getTypeDeclType(this);
DeclarationName Name
@@ -519,7 +531,7 @@ CXXRecordDecl::getDestructor(ASTContext &Context) {
llvm::tie(I, E) = lookup(Name);
assert(I != E && "Did not find a destructor!");
- const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I);
+ CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I);
assert(++I == E && "Found more than one destructor!");
return Dtor;
@@ -528,9 +540,9 @@ CXXRecordDecl::getDestructor(ASTContext &Context) {
CXXMethodDecl *
CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
- QualType T, DeclaratorInfo *DInfo,
+ QualType T, TypeSourceInfo *TInfo,
bool isStatic, bool isInline) {
- return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, DInfo,
+ return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, TInfo,
isStatic, isInline);
}
@@ -577,6 +589,8 @@ typedef llvm::DenseMap<const CXXMethodDecl*,
static OverriddenMethodsMapTy *OverriddenMethods = 0;
void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
+ assert(MD->isCanonicalDecl() && "Method is not canonical!");
+
// FIXME: The CXXMethodDecl dtor needs to remove and free the entry.
if (!OverriddenMethods)
@@ -630,55 +644,107 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const {
return C.getPointerType(ClassTy);
}
-CXXBaseOrMemberInitializer::
-CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs,
- CXXConstructorDecl *C,
- SourceLocation L, SourceLocation R)
- : Args(0), NumArgs(0), CtorOrAnonUnion(), IdLoc(L), RParenLoc(R) {
- BaseOrMember = reinterpret_cast<uintptr_t>(BaseType.getTypePtr());
- assert((BaseOrMember & 0x01) == 0 && "Invalid base class type pointer");
- BaseOrMember |= 0x01;
+static bool MethodHasBody(const CXXMethodDecl *MD, const FunctionDecl *&fn) {
+ // Simple case: function has a body
+ if (MD->getBody(fn))
+ return true;
+ // Complex case: function is an instantiation of a function which has a
+ // body, but the definition hasn't been instantiated.
+ const FunctionDecl *PatternDecl = MD->getTemplateInstantiationPattern();
+ if (PatternDecl && PatternDecl->getBody(fn))
+ return true;
+
+ return false;
+}
+
+bool CXXMethodDecl::hasInlineBody() const {
+ const FunctionDecl *fn;
+ return MethodHasBody(this, fn) && !fn->isOutOfLine();
+}
+
+CXXBaseOrMemberInitializer::
+CXXBaseOrMemberInitializer(ASTContext &Context,
+ TypeSourceInfo *TInfo, CXXConstructorDecl *C,
+ SourceLocation L,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation R)
+ : BaseOrMember(TInfo), Args(0), NumArgs(0), CtorOrAnonUnion(C),
+ LParenLoc(L), RParenLoc(R)
+{
if (NumArgs > 0) {
this->NumArgs = NumArgs;
- // FIXME. Allocation via Context
- this->Args = new Stmt*[NumArgs];
+ this->Args = new (Context) Stmt*[NumArgs];
for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
this->Args[Idx] = Args[Idx];
}
- CtorOrAnonUnion = C;
}
CXXBaseOrMemberInitializer::
-CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs,
- CXXConstructorDecl *C,
- SourceLocation L, SourceLocation R)
- : Args(0), NumArgs(0), CtorOrAnonUnion(), IdLoc(L), RParenLoc(R) {
- BaseOrMember = reinterpret_cast<uintptr_t>(Member);
- assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer");
-
+CXXBaseOrMemberInitializer(ASTContext &Context,
+ FieldDecl *Member, SourceLocation MemberLoc,
+ CXXConstructorDecl *C, SourceLocation L,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation R)
+ : BaseOrMember(Member), MemberLocation(MemberLoc), Args(0), NumArgs(0),
+ CtorOrAnonUnion(C), LParenLoc(L), RParenLoc(R)
+{
if (NumArgs > 0) {
this->NumArgs = NumArgs;
- this->Args = new Stmt*[NumArgs];
+ this->Args = new (Context) Stmt*[NumArgs];
for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
this->Args[Idx] = Args[Idx];
}
- CtorOrAnonUnion = C;
}
-CXXBaseOrMemberInitializer::~CXXBaseOrMemberInitializer() {
- delete [] Args;
+void CXXBaseOrMemberInitializer::Destroy(ASTContext &Context) {
+ for (unsigned I = 0; I != NumArgs; ++I)
+ Args[I]->Destroy(Context);
+ Context.Deallocate(Args);
+ this->~CXXBaseOrMemberInitializer();
+}
+
+TypeLoc CXXBaseOrMemberInitializer::getBaseClassLoc() const {
+ if (isBaseInitializer())
+ return BaseOrMember.get<TypeSourceInfo*>()->getTypeLoc();
+ else
+ return TypeLoc();
+}
+
+Type *CXXBaseOrMemberInitializer::getBaseClass() {
+ if (isBaseInitializer())
+ return BaseOrMember.get<TypeSourceInfo*>()->getType().getTypePtr();
+ else
+ return 0;
+}
+
+const Type *CXXBaseOrMemberInitializer::getBaseClass() const {
+ if (isBaseInitializer())
+ return BaseOrMember.get<TypeSourceInfo*>()->getType().getTypePtr();
+ else
+ return 0;
+}
+
+SourceLocation CXXBaseOrMemberInitializer::getSourceLocation() const {
+ if (isMemberInitializer())
+ return getMemberLocation();
+
+ return getBaseClassLoc().getSourceRange().getBegin();
+}
+
+SourceRange CXXBaseOrMemberInitializer::getSourceRange() const {
+ return SourceRange(getSourceLocation(), getRParenLoc());
}
CXXConstructorDecl *
CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
- QualType T, DeclaratorInfo *DInfo,
+ QualType T, TypeSourceInfo *TInfo,
bool isExplicit,
bool isInline, bool isImplicitlyDeclared) {
assert(N.getNameKind() == DeclarationName::CXXConstructorName &&
"Name must refer to a constructor");
- return new (C) CXXConstructorDecl(RD, L, N, T, DInfo, isExplicit, isInline,
+ return new (C) CXXConstructorDecl(RD, L, N, T, TInfo, isExplicit, isInline,
isImplicitlyDeclared);
}
@@ -790,69 +856,11 @@ CXXConstructorDecl::Destroy(ASTContext& C) {
CXXConversionDecl *
CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
- QualType T, DeclaratorInfo *DInfo,
+ QualType T, TypeSourceInfo *TInfo,
bool isInline, bool isExplicit) {
assert(N.getNameKind() == DeclarationName::CXXConversionFunctionName &&
"Name must refer to a conversion function");
- return new (C) CXXConversionDecl(RD, L, N, T, DInfo, isInline, isExplicit);
-}
-
-OverloadedFunctionDecl *
-OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC,
- DeclarationName N) {
- return new (C) OverloadedFunctionDecl(DC, N);
-}
-
-OverloadIterator::OverloadIterator(NamedDecl *ND) : D(0) {
- if (!ND)
- return;
-
- if (isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND))
- D = ND;
- else if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(ND)) {
- if (Ovl->size() != 0) {
- D = ND;
- Iter = Ovl->function_begin();
- }
- }
-}
-
-void OverloadedFunctionDecl::addOverload(AnyFunctionDecl F) {
- Functions.push_back(F);
- this->setLocation(F.get()->getLocation());
-}
-
-OverloadIterator::reference OverloadIterator::operator*() const {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- return FD;
-
- if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
- return FTD;
-
- assert(isa<OverloadedFunctionDecl>(D));
- return *Iter;
-}
-
-OverloadIterator &OverloadIterator::operator++() {
- if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
- D = 0;
- return *this;
- }
-
- if (++Iter == cast<OverloadedFunctionDecl>(D)->function_end())
- D = 0;
-
- return *this;
-}
-
-bool OverloadIterator::Equals(const OverloadIterator &Other) const {
- if (!D || !Other.D)
- return D == Other.D;
-
- if (D != Other.D)
- return false;
-
- return !isa<OverloadedFunctionDecl>(D) || Iter == Other.Iter;
+ return new (C) CXXConversionDecl(RD, L, N, T, TInfo, isInline, isExplicit);
}
FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index c33720f..2506f27 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -501,9 +501,9 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto,
ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
- QualType T, DeclaratorInfo *DInfo,
+ QualType T, TypeSourceInfo *TInfo,
AccessControl ac, Expr *BW) {
- return new (C) ObjCIvarDecl(DC, L, Id, T, DInfo, ac, BW);
+ return new (C) ObjCIvarDecl(DC, L, Id, T, TInfo, ac, BW);
}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index a5982cf..32ac53d 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -52,7 +52,6 @@ namespace {
void VisitVarDecl(VarDecl *D);
void VisitParmVarDecl(ParmVarDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
- void VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D);
void VisitNamespaceDecl(NamespaceDecl *D);
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
@@ -149,6 +148,17 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls,
}
}
+void DeclContext::dumpDeclContext() const {
+ // Get the translation unit
+ const DeclContext *DC = this;
+ while (!DC->isTranslationUnit())
+ DC = DC->getParent();
+
+ ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
+ DeclPrinter Printer(llvm::errs(), Ctx, Ctx.PrintingPolicy, 0);
+ Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false);
+}
+
void Decl::dump() const {
print(llvm::errs());
}
@@ -362,6 +372,24 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
Proto += ")";
+
+ if (FT && FT->hasExceptionSpec()) {
+ Proto += " throw(";
+ if (FT->hasAnyExceptionSpec())
+ Proto += "...";
+ else
+ for (unsigned I = 0, N = FT->getNumExceptions(); I != N; ++I) {
+ if (I)
+ Proto += ", ";
+
+
+ std::string ExceptionType;
+ FT->getExceptionType(I).getAsStringInternal(ExceptionType, SubPolicy);
+ Proto += ExceptionType;
+ }
+ Proto += ")";
+ }
+
if (D->hasAttr<NoReturnAttr>())
Proto += " __attribute((noreturn))";
if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) {
@@ -488,11 +516,6 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
//----------------------------------------------------------------------------
// C++ declarations
//----------------------------------------------------------------------------
-void DeclPrinter::VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D) {
- assert(false &&
- "OverloadedFunctionDecls aren't really decls and are never printed");
-}
-
void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) {
Out << "namespace " << D->getNameAsString() << " {\n";
VisitDeclContext(D);
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 902339e..75b3975 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -262,8 +262,8 @@ NonTypeTemplateParmDecl *
NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
IdentifierInfo *Id, QualType T,
- DeclaratorInfo *DInfo) {
- return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, DInfo);
+ TypeSourceInfo *TInfo) {
+ return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, TInfo);
}
SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 3471657..0ce03c2 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -338,7 +338,7 @@ void DeclarationName::setFETokenInfo(void *T) {
DeclarationName DeclarationName::getUsingDirectiveName() {
// Single instance of DeclarationNameExtra for using-directive
- static DeclarationNameExtra UDirExtra =
+ static const DeclarationNameExtra UDirExtra =
{ DeclarationNameExtra::CXXUsingDirective };
uintptr_t Ptr = reinterpret_cast<uintptr_t>(&UDirExtra);
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 624a620..139e04b 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -110,7 +110,7 @@ void DeclRefExpr::computeDependence() {
DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
- NamedDecl *D, SourceLocation NameLoc,
+ ValueDecl *D, SourceLocation NameLoc,
const TemplateArgumentListInfo *TemplateArgs,
QualType T)
: Expr(DeclRefExprClass, T, false, false),
@@ -118,7 +118,6 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier,
(Qualifier? HasQualifierFlag : 0) |
(TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)),
Loc(NameLoc) {
- assert(!isa<OverloadedFunctionDecl>(D));
if (Qualifier) {
NameQualifier *NQ = getNameQualifier();
NQ->NNS = Qualifier;
@@ -134,7 +133,7 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier,
DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
- NamedDecl *D,
+ ValueDecl *D,
SourceLocation NameLoc,
QualType T,
const TemplateArgumentListInfo *TemplateArgs) {
@@ -204,7 +203,8 @@ std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT,
}
Proto += ")";
- AFT->getResultType().getAsStringInternal(Proto, Policy);
+ if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
+ AFT->getResultType().getAsStringInternal(Proto, Policy);
Out << Proto;
@@ -471,7 +471,7 @@ QualType CallExpr::getCallReturnType() const {
}
MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
- SourceRange qualrange, NamedDecl *memberdecl,
+ SourceRange qualrange, ValueDecl *memberdecl,
SourceLocation l, const TemplateArgumentListInfo *targs,
QualType ty)
: Expr(MemberExprClass, ty,
@@ -494,7 +494,7 @@ MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifier *qual,
SourceRange qualrange,
- NamedDecl *memberdecl,
+ ValueDecl *memberdecl,
SourceLocation l,
const TemplateArgumentListInfo *targs,
QualType ty) {
@@ -558,12 +558,40 @@ const char *CastExpr::getCastKindName() const {
return "FloatingCast";
case CastExpr::CK_MemberPointerToBoolean:
return "MemberPointerToBoolean";
+ case CastExpr::CK_AnyPointerToObjCPointerCast:
+ return "AnyPointerToObjCPointerCast";
+ case CastExpr::CK_AnyPointerToBlockPointerCast:
+ return "AnyPointerToBlockPointerCast";
}
assert(0 && "Unhandled cast kind!");
return 0;
}
+Expr *CastExpr::getSubExprAsWritten() {
+ Expr *SubExpr = 0;
+ CastExpr *E = this;
+ do {
+ SubExpr = E->getSubExpr();
+
+ // Skip any temporary bindings; they're implicit.
+ if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(SubExpr))
+ SubExpr = Binder->getSubExpr();
+
+ // Conversions by constructor and conversion functions have a
+ // subexpression describing the call; strip it off.
+ if (E->getCastKind() == CastExpr::CK_ConstructorConversion)
+ SubExpr = cast<CXXConstructExpr>(SubExpr)->getArg(0);
+ else if (E->getCastKind() == CastExpr::CK_UserDefinedConversion)
+ SubExpr = cast<CXXMemberCallExpr>(SubExpr)->getImplicitObjectArgument();
+
+ // If the subexpression we're left with is an implicit cast, look
+ // through that, too.
+ } while ((E = dyn_cast<ImplicitCastExpr>(SubExpr)));
+
+ return SubExpr;
+}
+
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "<<=".
const char *BinaryOperator::getOpcodeStr(Opcode Op) {
@@ -944,8 +972,7 @@ static bool DeclCanBeLvalue(const NamedDecl *Decl, ASTContext &Ctx) {
return isa<VarDecl>(Decl) || isa<FieldDecl>(Decl) ||
// C++ 3.10p2: An lvalue refers to an object or function.
(Ctx.getLangOptions().CPlusPlus &&
- (isa<FunctionDecl>(Decl) || isa<OverloadedFunctionDecl>(Decl) ||
- isa<FunctionTemplateDecl>(Decl)));
+ (isa<FunctionDecl>(Decl) || isa<FunctionTemplateDecl>(Decl)));
}
/// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or an
@@ -982,6 +1009,7 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
// Check whether the expression can be sanely treated like an l-value
Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
switch (getStmtClass()) {
+ case ObjCIsaExprClass:
case StringLiteralClass: // C99 6.5.1p4
case ObjCEncodeExprClass: // @encode behaves like its string in every way.
return LV_Valid;
@@ -1343,6 +1371,13 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
}
}
+bool Expr::isDefaultArgument() const {
+ const Expr *E = this;
+ while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+ E = ICE->getSubExprAsWritten();
+
+ return isa<CXXDefaultArgExpr>(E);
+}
/// hasAnyTypeDependentArguments - Determines if any of the expressions
/// in Exprs is type-dependent.
@@ -1598,13 +1633,18 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// constant expression (5.19). In that case, the member can appear
// in integral constant expressions.
if (Def->isOutOfLine()) {
- Dcl->setInitKnownICE(Ctx, false);
+ Dcl->setInitKnownICE(false);
+ return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+ }
+
+ if (Dcl->isCheckingICE()) {
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
}
-
+
+ Dcl->setCheckingICE();
ICEDiag Result = CheckICE(Init, Ctx);
// Cache the result of the ICE test.
- Dcl->setInitKnownICE(Ctx, Result.Val == 0);
+ Dcl->setInitKnownICE(Result.Val == 0);
return Result;
}
}
@@ -1804,7 +1844,7 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
}
EvalResult EvalResult;
if (!Evaluate(EvalResult, Ctx))
- llvm::llvm_unreachable("ICE cannot be evaluated!");
+ llvm_unreachable("ICE cannot be evaluated!");
assert(!EvalResult.HasSideEffects && "ICE with side effects!");
assert(EvalResult.Val.isInt() && "ICE that isn't integer!");
Result = EvalResult.Val.getInt();
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index d1a0390..a9f96ad 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -199,6 +199,7 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
switch(UTT) {
default: assert(false && "Unknown type trait or not implemented");
case UTT_IsPOD: return QueriedType->isPODType();
+ case UTT_IsLiteral: return QueriedType->isLiteralType();
case UTT_IsClass: // Fallthrough
case UTT_IsUnion:
if (const RecordType *Record = QueriedType->getAs<RecordType>()) {
@@ -518,7 +519,8 @@ Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() {
}
CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType,
+ bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -527,8 +529,8 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
SourceLocation MemberLoc,
const TemplateArgumentListInfo *TemplateArgs)
: Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true),
- Base(Base), IsArrow(IsArrow),
- HasExplicitTemplateArgumentList(TemplateArgs),
+ Base(Base), BaseType(BaseType), IsArrow(IsArrow),
+ HasExplicitTemplateArgs(TemplateArgs != 0),
OperatorLoc(OperatorLoc),
Qualifier(Qualifier), QualifierRange(QualifierRange),
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
@@ -539,7 +541,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
CXXDependentScopeMemberExpr *
CXXDependentScopeMemberExpr::Create(ASTContext &C,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -548,22 +550,22 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C,
SourceLocation MemberLoc,
const TemplateArgumentListInfo *TemplateArgs) {
if (!TemplateArgs)
- return new (C) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc,
- Qualifier, QualifierRange,
- FirstQualifierFoundInScope,
- Member, MemberLoc);
+ return new (C) CXXDependentScopeMemberExpr(C, Base, BaseType,
+ IsArrow, OperatorLoc,
+ Qualifier, QualifierRange,
+ FirstQualifierFoundInScope,
+ Member, MemberLoc);
std::size_t size = sizeof(CXXDependentScopeMemberExpr);
if (TemplateArgs)
size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
void *Mem = C.Allocate(size, llvm::alignof<CXXDependentScopeMemberExpr>());
- return new (Mem) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc,
- Qualifier, QualifierRange,
- FirstQualifierFoundInScope,
- Member,
- MemberLoc,
- TemplateArgs);
+ return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType,
+ IsArrow, OperatorLoc,
+ Qualifier, QualifierRange,
+ FirstQualifierFoundInScope,
+ Member, MemberLoc, TemplateArgs);
}
Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() {
@@ -571,12 +573,15 @@ Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() {
}
Stmt::child_iterator CXXDependentScopeMemberExpr::child_end() {
+ if (isImplicitAccess())
+ return child_iterator(&Base);
return child_iterator(&Base + 1);
}
UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent,
bool HasUnresolvedUsing,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType,
+ bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -584,7 +589,8 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent,
SourceLocation MemberLoc,
const TemplateArgumentListInfo *TemplateArgs)
: Expr(UnresolvedMemberExprClass, T, Dependent, Dependent),
- Base(Base), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing),
+ Base(Base), BaseType(BaseType), IsArrow(IsArrow),
+ HasUnresolvedUsing(HasUnresolvedUsing),
HasExplicitTemplateArgs(TemplateArgs != 0),
OperatorLoc(OperatorLoc),
Qualifier(Qualifier), QualifierRange(QualifierRange),
@@ -596,7 +602,7 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent,
UnresolvedMemberExpr *
UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent,
bool HasUnresolvedUsing,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -610,8 +616,8 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent,
void *Mem = C.Allocate(size, llvm::alignof<UnresolvedMemberExpr>());
return new (Mem) UnresolvedMemberExpr(
Dependent ? C.DependentTy : C.OverloadTy,
- Dependent, HasUnresolvedUsing, Base, IsArrow,
- OperatorLoc, Qualifier, QualifierRange,
+ Dependent, HasUnresolvedUsing, Base, BaseType,
+ IsArrow, OperatorLoc, Qualifier, QualifierRange,
Member, MemberLoc, TemplateArgs);
}
@@ -620,5 +626,7 @@ Stmt::child_iterator UnresolvedMemberExpr::child_begin() {
}
Stmt::child_iterator UnresolvedMemberExpr::child_end() {
+ if (isImplicitAccess())
+ return child_iterator(&Base);
return child_iterator(&Base + 1);
}
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index a20e1cc..13831dc 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -848,16 +848,8 @@ static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) {
bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
// Enums are integer constant exprs.
- if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
- // FIXME: This is an ugly hack around the fact that enums don't set their
- // signedness consistently; see PR3173.
- APSInt SI = ECD->getInitVal();
- SI.setIsUnsigned(!E->getType()->isSignedIntegerType());
- // FIXME: This is an ugly hack around the fact that enums don't
- // set their width (!?!) consistently; see PR3173.
- SI.extOrTrunc(Info.Ctx.getIntWidth(E->getType()));
- return Success(SI, E);
- }
+ if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D))
+ return Success(ECD->getInitVal(), E);
// In C++, const, non-volatile integers initialized with ICEs are ICEs.
// In C, they can also be folded, although they are not ICEs.
@@ -866,15 +858,24 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
const VarDecl *Def = 0;
if (const Expr *Init = VD->getDefinition(Def)) {
- if (APValue *V = VD->getEvaluatedValue())
- return Success(V->getInt(), E);
-
+ if (APValue *V = VD->getEvaluatedValue()) {
+ if (V->isInt())
+ return Success(V->getInt(), E);
+ return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+ }
+
+ if (VD->isEvaluatingValue())
+ return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+
+ VD->setEvaluatingValue();
+
if (Visit(const_cast<Expr*>(Init))) {
// Cache the evaluated value in the variable declaration.
- VD->setEvaluatedValue(Info.Ctx, Result);
+ VD->setEvaluatedValue(Result);
return true;
}
+ VD->setEvaluatedValue(APValue());
return false;
}
}
@@ -1506,6 +1507,7 @@ public:
bool VisitFloatingLiteral(const FloatingLiteral *E);
bool VisitCastExpr(CastExpr *E);
bool VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E);
+ bool VisitConditionalOperator(ConditionalOperator *E);
bool VisitChooseExpr(const ChooseExpr *E)
{ return Visit(E->getChosenSubExpr(Info.Ctx)); }
@@ -1513,8 +1515,7 @@ public:
{ return Visit(E->getSubExpr()); }
// FIXME: Missing: __real__/__imag__, array subscript of vector,
- // member of vector, ImplicitValueInitExpr,
- // conditional ?:
+ // member of vector, ImplicitValueInitExpr
};
} // end anonymous namespace
@@ -1547,16 +1548,10 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (!S->isWide()) {
const llvm::fltSemantics &Sem =
Info.Ctx.getFloatTypeSemantics(E->getType());
- llvm::SmallString<16> s;
- s.append(S->getStrData(), S->getStrData() + S->getByteLength());
- s += '\0';
- long l;
- char *endp;
- l = strtol(&s[0], &endp, 0);
- if (endp != s.end()-1)
+ unsigned Type = 0;
+ if (!S->getString().empty() && S->getString().getAsInteger(0, Type))
return false;
- unsigned type = (unsigned int)l;;
- Result = llvm::APFloat::getNaN(Sem, false, type);
+ Result = llvm::APFloat::getNaN(Sem, false, Type);
return true;
}
}
@@ -1673,6 +1668,14 @@ bool FloatExprEvaluator::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
return true;
}
+bool FloatExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
+ bool Cond;
+ if (!HandleConversionToBool(E->getCond(), Cond, Info))
+ return false;
+
+ return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr());
+}
+
//===----------------------------------------------------------------------===//
// Complex Evaluation (for float and integer)
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 326a1dc..c914f3f 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -663,31 +663,6 @@ void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
Alignment = NewAlignment;
}
-static const CXXMethodDecl *GetKeyFunction(const CXXRecordDecl *RD) {
- if (!RD->isDynamicClass())
- return 0;
-
- 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;
-
- const FunctionDecl *fn;
- if (MD->getBody(fn) && !fn->isOutOfLine())
- continue;
-
- // We found it.
- return MD;
- }
-
- return 0;
-}
-
const ASTRecordLayout *
ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
const RecordDecl *D) {
@@ -711,8 +686,6 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
uint64_t NonVirtualSize =
IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
- const CXXMethodDecl *KeyFunction = GetKeyFunction(cast<CXXRecordDecl>(D));
-
return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize,
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size(),
@@ -722,8 +695,7 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
Builder.Bases.data(),
Builder.Bases.size(),
Builder.VBases.data(),
- Builder.VBases.size(),
- KeyFunction);
+ Builder.VBases.size());
}
const ASTRecordLayout *
@@ -739,3 +711,51 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
}
+
+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 (!RD->isPolymorphic())
+ return 0;
+
+ // A class template specialization or instantation does not have a key
+ // function.
+ if (RD->getTemplateSpecializationKind() != TSK_Undeclared)
+ return 0;
+
+ // A class inside an anonymous namespace doesn't have a key function. (Or
+ // at least, there's no point to assigning a key function to such a class;
+ // this doesn't affect the ABI.)
+ if (RD->isInAnonymousNamespace())
+ return 0;
+
+ 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;
+
+ if (MD->isInlineSpecified())
+ continue;
+
+ // Ignore implicit member functions, they are always marked as inline, but
+ // they don't have a body until they're defined.
+ if (MD->isImplicit())
+ continue;
+
+ if (MD->hasInlineBody())
+ continue;
+
+ // We found it.
+ return MD;
+ }
+
+ return 0;
+}
+
diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h
index 69e0498..d4171d3 100644
--- a/lib/AST/RecordLayoutBuilder.h
+++ b/lib/AST/RecordLayoutBuilder.h
@@ -151,6 +151,7 @@ public:
static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx,
const ObjCInterfaceDecl *D,
const ObjCImplementationDecl *Impl);
+ static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
};
} // end namespace clang
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index bbe6a71..ae76526 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -17,7 +17,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/SourceManager.h"
-#include <cstdio>
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -27,7 +27,7 @@ using namespace clang;
namespace {
class StmtDumper : public StmtVisitor<StmtDumper> {
SourceManager *SM;
- FILE *F;
+ llvm::raw_ostream &OS;
unsigned IndentLevel;
/// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump
@@ -41,8 +41,8 @@ namespace {
unsigned LastLocLine;
public:
- StmtDumper(SourceManager *sm, FILE *f, unsigned maxDepth)
- : SM(sm), F(f), IndentLevel(0-1), MaxDepth(maxDepth) {
+ StmtDumper(SourceManager *sm, llvm::raw_ostream &os, unsigned maxDepth)
+ : SM(sm), OS(os), IndentLevel(0-1), MaxDepth(maxDepth) {
LastLocFilename = "";
LastLocLine = ~0U;
}
@@ -62,15 +62,15 @@ namespace {
Stmt::child_iterator CI = S->child_begin(), CE = S->child_end();
if (CI != CE) {
while (CI != CE) {
- fprintf(F, "\n");
+ OS << '\n';
DumpSubTree(*CI++);
}
}
- fprintf(F, ")");
+ OS << ')';
}
} else {
Indent();
- fprintf(F, "<<<NULL>>>");
+ OS << "<<<NULL>>>";
}
--IndentLevel;
}
@@ -79,27 +79,28 @@ namespace {
void Indent() const {
for (int i = 0, e = IndentLevel; i < e; ++i)
- fprintf(F, " ");
+ OS << " ";
}
void DumpType(QualType T) {
- fprintf(F, "'%s'", T.getAsString().c_str());
+ OS << "'" << T.getAsString() << "'";
if (!T.isNull()) {
// If the type is sugared, also dump a (shallow) desugared type.
QualType Simplified = T.getDesugaredType();
if (Simplified != T)
- fprintf(F, ":'%s'", Simplified.getAsString().c_str());
+ OS << ":'" << Simplified.getAsString() << "'";
}
}
void DumpStmt(const Stmt *Node) {
Indent();
- fprintf(F, "(%s %p", Node->getStmtClassName(), (void*)Node);
+ OS << "(" << Node->getStmtClassName()
+ << " " << (void*)Node;
DumpSourceRange(Node);
}
void DumpExpr(const Expr *Node) {
DumpStmt(Node);
- fprintf(F, " ");
+ OS << ' ';
DumpType(Node->getType());
}
void DumpSourceRange(const Stmt *Node);
@@ -138,6 +139,7 @@ namespace {
void VisitCXXConstructExpr(CXXConstructExpr *Node);
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node);
void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node);
+ void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node);
void DumpCXXTemporary(CXXTemporary *Temporary);
// ObjC
@@ -161,7 +163,7 @@ void StmtDumper::DumpLocation(SourceLocation Loc) {
SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
if (SpellingLoc.isInvalid()) {
- fprintf(stderr, "<invalid sloc>");
+ OS << "<invalid sloc>";
return;
}
@@ -170,15 +172,16 @@ void StmtDumper::DumpLocation(SourceLocation Loc) {
PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc);
if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
- fprintf(stderr, "%s:%u:%u", PLoc.getFilename(), PLoc.getLine(),
- PLoc.getColumn());
+ OS << PLoc.getFilename() << ':' << PLoc.getLine()
+ << ':' << PLoc.getColumn();
LastLocFilename = PLoc.getFilename();
LastLocLine = PLoc.getLine();
} else if (PLoc.getLine() != LastLocLine) {
- fprintf(stderr, "line:%u:%u", PLoc.getLine(), PLoc.getColumn());
+ OS << "line" << ':' << PLoc.getLine()
+ << ':' << PLoc.getColumn();
LastLocLine = PLoc.getLine();
} else {
- fprintf(stderr, "col:%u", PLoc.getColumn());
+ OS << "col" << ':' << PLoc.getColumn();
}
}
@@ -190,13 +193,13 @@ void StmtDumper::DumpSourceRange(const Stmt *Node) {
// location.
SourceRange R = Node->getSourceRange();
- fprintf(stderr, " <");
+ OS << " <";
DumpLocation(R.getBegin());
if (R.getBegin() != R.getEnd()) {
- fprintf(stderr, ", ");
+ OS << ", ";
DumpLocation(R.getEnd());
}
- fprintf(stderr, ">");
+ OS << ">";
// <t2.c:123:421[blah], t2.c:412:321>
@@ -215,31 +218,30 @@ void StmtDumper::DumpDeclarator(Decl *D) {
// FIXME: Need to complete/beautify this... this code simply shows the
// nodes are where they need to be.
if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
- fprintf(F, "\"typedef %s %s\"",
- localType->getUnderlyingType().getAsString().c_str(),
- localType->getNameAsString().c_str());
+ OS << "\"typedef " << localType->getUnderlyingType().getAsString()
+ << " " << localType->getNameAsString() << "\"";
} else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
- fprintf(F, "\"");
+ OS << "\"";
// Emit storage class for vardecls.
if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
if (V->getStorageClass() != VarDecl::None)
- fprintf(F, "%s ",
- VarDecl::getStorageClassSpecifierString(V->getStorageClass()));
+ OS << VarDecl::getStorageClassSpecifierString(V->getStorageClass())
+ << " ";
}
std::string Name = VD->getNameAsString();
VD->getType().getAsStringInternal(Name,
PrintingPolicy(VD->getASTContext().getLangOptions()));
- fprintf(F, "%s", Name.c_str());
+ OS << Name;
// If this is a vardecl with an initializer, emit it.
if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
if (V->getInit()) {
- fprintf(F, " =\n");
+ OS << " =\n";
DumpSubTree(V->getInit());
}
}
- fprintf(F, "\"");
+ OS << '"';
} else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
// print a free standing tag decl (e.g. "struct x;").
const char *tagname;
@@ -247,7 +249,7 @@ void StmtDumper::DumpDeclarator(Decl *D) {
tagname = II->getNameStart();
else
tagname = "<anonymous>";
- fprintf(F, "\"%s %s;\"", TD->getKindName(), tagname);
+ OS << '"' << TD->getKindName() << ' ' << tagname << ";\"";
// FIXME: print tag bodies.
} else if (UsingDirectiveDecl *UD = dyn_cast<UsingDirectiveDecl>(D)) {
// print using-directive decl (e.g. "using namespace x;")
@@ -256,7 +258,7 @@ void StmtDumper::DumpDeclarator(Decl *D) {
ns = II->getNameStart();
else
ns = "<anonymous>";
- fprintf(F, "\"%s %s;\"",UD->getDeclKindName(), ns);
+ OS << '"' << UD->getDeclKindName() << ns << ";\"";
} else {
assert(0 && "Unexpected decl");
}
@@ -264,28 +266,29 @@ void StmtDumper::DumpDeclarator(Decl *D) {
void StmtDumper::VisitDeclStmt(DeclStmt *Node) {
DumpStmt(Node);
- fprintf(F,"\n");
+ OS << "\n";
for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
DI != DE; ++DI) {
Decl* D = *DI;
++IndentLevel;
Indent();
- fprintf(F, "%p ", (void*) D);
+ OS << (void*) D << " ";
DumpDeclarator(D);
if (DI+1 != DE)
- fprintf(F,"\n");
+ OS << "\n";
--IndentLevel;
}
}
void StmtDumper::VisitLabelStmt(LabelStmt *Node) {
DumpStmt(Node);
- fprintf(F, " '%s'", Node->getName());
+ OS << " '" << Node->getName() << "'";
}
void StmtDumper::VisitGotoStmt(GotoStmt *Node) {
DumpStmt(Node);
- fprintf(F, " '%s':%p", Node->getLabel()->getName(), (void*)Node->getLabel());
+ OS << " '" << Node->getLabel()->getName()
+ << "':" << (void*)Node->getLabel();
}
//===----------------------------------------------------------------------===//
@@ -298,129 +301,130 @@ void StmtDumper::VisitExpr(Expr *Node) {
void StmtDumper::VisitCastExpr(CastExpr *Node) {
DumpExpr(Node);
- fprintf(F, " <%s>", Node->getCastKindName());
+ OS << " <" << Node->getCastKindName() << ">";
}
void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
VisitCastExpr(Node);
if (Node->isLvalueCast())
- fprintf(F, " lvalue");
+ OS << " lvalue";
}
void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
DumpExpr(Node);
- fprintf(F, " ");
+ OS << " ";
switch (Node->getDecl()->getKind()) {
- default: fprintf(F,"Decl"); break;
- case Decl::Function: fprintf(F,"FunctionDecl"); break;
- case Decl::Var: fprintf(F,"Var"); break;
- case Decl::ParmVar: fprintf(F,"ParmVar"); break;
- case Decl::EnumConstant: fprintf(F,"EnumConstant"); break;
- case Decl::Typedef: fprintf(F,"Typedef"); break;
- case Decl::Record: fprintf(F,"Record"); break;
- case Decl::Enum: fprintf(F,"Enum"); break;
- case Decl::CXXRecord: fprintf(F,"CXXRecord"); break;
- case Decl::ObjCInterface: fprintf(F,"ObjCInterface"); break;
- case Decl::ObjCClass: fprintf(F,"ObjCClass"); break;
+ default: OS << "Decl"; break;
+ case Decl::Function: OS << "FunctionDecl"; break;
+ case Decl::Var: OS << "Var"; break;
+ case Decl::ParmVar: OS << "ParmVar"; break;
+ case Decl::EnumConstant: OS << "EnumConstant"; break;
+ case Decl::Typedef: OS << "Typedef"; break;
+ case Decl::Record: OS << "Record"; break;
+ case Decl::Enum: OS << "Enum"; break;
+ case Decl::CXXRecord: OS << "CXXRecord"; break;
+ case Decl::ObjCInterface: OS << "ObjCInterface"; break;
+ case Decl::ObjCClass: OS << "ObjCClass"; break;
}
- fprintf(F, "='%s' %p", Node->getDecl()->getNameAsString().c_str(),
- (void*)Node->getDecl());
+ OS << "='" << Node->getDecl()->getNameAsString()
+ << "' " << (void*)Node->getDecl();
+}
+
+void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
+ DumpExpr(Node);
+ OS << " (";
+ if (!Node->requiresADL()) OS << "no ";
+ OS << "ADL) = '" << Node->getName().getAsString() << "'";
+
+ UnresolvedLookupExpr::decls_iterator
+ I = Node->decls_begin(), E = Node->decls_end();
+ if (I == E) OS << " empty";
+ for (; I != E; ++I)
+ OS << " " << (void*) *I;
}
void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
DumpExpr(Node);
- fprintf(F, " %sDecl='%s' %p", Node->getDecl()->getDeclKindName(),
- Node->getDecl()->getNameAsString().c_str(), (void*)Node->getDecl());
+ OS << " " << Node->getDecl()->getDeclKindName()
+ << "Decl='" << Node->getDecl()->getNameAsString()
+ << "' " << (void*)Node->getDecl();
if (Node->isFreeIvar())
- fprintf(F, " isFreeIvar");
+ OS << " isFreeIvar";
}
void StmtDumper::VisitPredefinedExpr(PredefinedExpr *Node) {
DumpExpr(Node);
switch (Node->getIdentType()) {
default: assert(0 && "unknown case");
- case PredefinedExpr::Func: fprintf(F, " __func__"); break;
- case PredefinedExpr::Function: fprintf(F, " __FUNCTION__"); break;
- case PredefinedExpr::PrettyFunction: fprintf(F, " __PRETTY_FUNCTION__");break;
+ case PredefinedExpr::Func: OS << " __func__"; break;
+ case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
+ case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
}
}
void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) {
DumpExpr(Node);
- fprintf(F, " %d", Node->getValue());
+ OS << Node->getValue();
}
void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) {
DumpExpr(Node);
bool isSigned = Node->getType()->isSignedIntegerType();
- fprintf(F, " %s", Node->getValue().toString(10, isSigned).c_str());
+ OS << " " << Node->getValue().toString(10, isSigned);
}
void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) {
DumpExpr(Node);
- fprintf(F, " %f", Node->getValueAsApproximateDouble());
+ OS << " " << Node->getValueAsApproximateDouble();
}
void StmtDumper::VisitStringLiteral(StringLiteral *Str) {
DumpExpr(Str);
// FIXME: this doesn't print wstrings right.
- fprintf(F, " %s\"", Str->isWide() ? "L" : "");
-
- for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) {
- switch (char C = Str->getStrData()[i]) {
- default:
- if (isprint(C))
- fputc(C, F);
- else
- fprintf(F, "\\%03o", C);
- break;
- // Handle some common ones to make dumps prettier.
- case '\\': fprintf(F, "\\\\"); break;
- case '"': fprintf(F, "\\\""); break;
- case '\n': fprintf(F, "\\n"); break;
- case '\t': fprintf(F, "\\t"); break;
- case '\a': fprintf(F, "\\a"); break;
- case '\b': fprintf(F, "\\b"); break;
- }
- }
- fprintf(F, "\"");
+ OS << " ";
+ if (Str->isWide())
+ OS << "L";
+ OS << '"';
+ OS.write_escaped(llvm::StringRef(Str->getStrData(),
+ Str->getByteLength()));
+ OS << '"';
}
void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) {
DumpExpr(Node);
- fprintf(F, " %s '%s'", Node->isPostfix() ? "postfix" : "prefix",
- UnaryOperator::getOpcodeStr(Node->getOpcode()));
+ OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
+ << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
}
void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
DumpExpr(Node);
- fprintf(F, " %s ", Node->isSizeOf() ? "sizeof" : "alignof");
+ OS << " " << (Node->isSizeOf() ? "sizeof" : "alignof") << " ";
if (Node->isArgumentType())
DumpType(Node->getArgumentType());
}
void StmtDumper::VisitMemberExpr(MemberExpr *Node) {
DumpExpr(Node);
- fprintf(F, " %s%s %p", Node->isArrow() ? "->" : ".",
- Node->getMemberDecl()->getNameAsString().c_str(),
- (void*)Node->getMemberDecl());
+ OS << " " << (Node->isArrow() ? "->" : ".")
+ << Node->getMemberDecl()->getNameAsString() << " "
+ << (void*)Node->getMemberDecl();
}
void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
DumpExpr(Node);
- fprintf(F, " %s", Node->getAccessor().getNameStart());
+ OS << " " << Node->getAccessor().getNameStart();
}
void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) {
DumpExpr(Node);
- fprintf(F, " '%s'", BinaryOperator::getOpcodeStr(Node->getOpcode()));
+ OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
}
void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
DumpExpr(Node);
- fprintf(F, " '%s' ComputeLHSTy=",
- BinaryOperator::getOpcodeStr(Node->getOpcode()));
+ OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode())
+ << "' ComputeLHSTy=";
DumpType(Node->getComputationLHSType());
- fprintf(F, " ComputeResultTy=");
+ OS << " ComputeResultTy=";
DumpType(Node->getComputationResultType());
}
@@ -428,14 +432,15 @@ void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
DumpExpr(Node);
- fprintf(F, " %s %p", Node->getLabel()->getName(), (void*)Node->getLabel());
+ OS << " " << Node->getLabel()->getName()
+ << " " << (void*)Node->getLabel();
}
void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
DumpExpr(Node);
- fprintf(F, " ");
+ OS << " ";
DumpType(Node->getArgType1());
- fprintf(F, " ");
+ OS << " ";
DumpType(Node->getArgType2());
}
@@ -445,36 +450,35 @@ void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
DumpExpr(Node);
- fprintf(F, " %s<%s> <%s>", Node->getCastName(),
- Node->getTypeAsWritten().getAsString().c_str(),
- Node->getCastKindName());
+ OS << " " << Node->getCastName()
+ << "<" << Node->getTypeAsWritten().getAsString() << ">"
+ << " <" << Node->getCastKindName() << ">";
}
void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
DumpExpr(Node);
- fprintf(F, " %s", Node->getValue() ? "true" : "false");
+ OS << " " << (Node->getValue() ? "true" : "false");
}
void StmtDumper::VisitCXXThisExpr(CXXThisExpr *Node) {
DumpExpr(Node);
- fprintf(F, " this");
+ OS << " this";
}
void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
DumpExpr(Node);
- fprintf(F, " functional cast to %s",
- Node->getTypeAsWritten().getAsString().c_str());
+ OS << " functional cast to " << Node->getTypeAsWritten().getAsString();
}
void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) {
DumpExpr(Node);
if (Node->isElidable())
- fprintf(F, " elidable");
+ OS << " elidable";
}
void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
DumpExpr(Node);
- fprintf(F, " ");
+ OS << " ";
DumpCXXTemporary(Node->getTemporary());
}
@@ -482,7 +486,7 @@ void StmtDumper::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node) {
DumpExpr(Node);
++IndentLevel;
for (unsigned i = 0, e = Node->getNumTemporaries(); i != e; ++i) {
- fprintf(F, "\n");
+ OS << "\n";
Indent();
DumpCXXTemporary(Node->getTemporary(i));
}
@@ -490,7 +494,7 @@ void StmtDumper::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node) {
}
void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) {
- fprintf(F, "(CXXTemporary %p)", (void *)Temporary);
+ OS << "(CXXTemporary " << (void *)Temporary << ")";
}
//===----------------------------------------------------------------------===//
@@ -499,37 +503,34 @@ void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) {
void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
DumpExpr(Node);
- fprintf(F, " selector=%s", Node->getSelector().getAsString().c_str());
- IdentifierInfo* clsName = Node->getClassName();
- if (clsName) fprintf(F, " class=%s", clsName->getNameStart());
+ OS << " selector=" << Node->getSelector().getAsString();
+ if (IdentifierInfo *clsName = Node->getClassName())
+ OS << " class=" << clsName->getNameStart();
}
void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
DumpExpr(Node);
-
- fprintf(F, " ");
+ OS << " ";
DumpType(Node->getEncodedType());
}
void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
DumpExpr(Node);
- fprintf(F, " ");
- fprintf(F, "%s", Node->getSelector().getAsString().c_str());
+ OS << " " << Node->getSelector().getAsString();
}
void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
DumpExpr(Node);
- fprintf(F, " ");
- fprintf(F, "%s", Node->getProtocol()->getNameAsString().c_str());
+ OS << " " << Node->getProtocol()->getNameAsString();
}
void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
DumpExpr(Node);
- fprintf(F, " Kind=PropertyRef Property=\"%s\"",
- Node->getProperty()->getNameAsString().c_str());
+ OS << " Kind=PropertyRef Property=\""
+ << Node->getProperty()->getNameAsString() << "\"";
}
void StmtDumper::VisitObjCImplicitSetterGetterRefExpr(
@@ -538,14 +539,19 @@ void StmtDumper::VisitObjCImplicitSetterGetterRefExpr(
ObjCMethodDecl *Getter = Node->getGetterMethod();
ObjCMethodDecl *Setter = Node->getSetterMethod();
- fprintf(F, " Kind=MethodRef Getter=\"%s\" Setter=\"%s\"",
- Getter->getSelector().getAsString().c_str(),
- Setter ? Setter->getSelector().getAsString().c_str() : "(null)");
+ OS << " Kind=MethodRef Getter=\""
+ << Getter->getSelector().getAsString()
+ << "\" Setter=\"";
+ if (Setter)
+ OS << Setter->getSelector().getAsString();
+ else
+ OS << "(null)";
+ OS << "\"";
}
void StmtDumper::VisitObjCSuperExpr(ObjCSuperExpr *Node) {
DumpExpr(Node);
- fprintf(F, " super");
+ OS << " super";
}
//===----------------------------------------------------------------------===//
@@ -556,30 +562,30 @@ void StmtDumper::VisitObjCSuperExpr(ObjCSuperExpr *Node) {
/// specified node and a few nodes underneath it, but not the whole subtree.
/// This is useful in a debugger.
void Stmt::dump(SourceManager &SM) const {
- StmtDumper P(&SM, stderr, 4);
+ StmtDumper P(&SM, llvm::errs(), 4);
P.DumpSubTree(const_cast<Stmt*>(this));
- fprintf(stderr, "\n");
+ llvm::errs() << "\n";
}
/// dump - This does a local dump of the specified AST fragment. It dumps the
/// specified node and a few nodes underneath it, but not the whole subtree.
/// This is useful in a debugger.
void Stmt::dump() const {
- StmtDumper P(0, stderr, 4);
+ StmtDumper P(0, llvm::errs(), 4);
P.DumpSubTree(const_cast<Stmt*>(this));
- fprintf(stderr, "\n");
+ llvm::errs() << "\n";
}
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
void Stmt::dumpAll(SourceManager &SM) const {
- StmtDumper P(&SM, stderr, ~0U);
+ StmtDumper P(&SM, llvm::errs(), ~0U);
P.DumpSubTree(const_cast<Stmt*>(this));
- fprintf(stderr, "\n");
+ llvm::errs() << "\n";
}
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
void Stmt::dumpAll() const {
- StmtDumper P(0, stderr, ~0U);
+ StmtDumper P(0, llvm::errs(), ~0U);
P.DumpSubTree(const_cast<Stmt*>(this));
- fprintf(stderr, "\n");
+ llvm::errs() << "\n";
}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 205ea0d..a7e42af 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1145,17 +1145,19 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr(
void StmtPrinter::VisitCXXDependentScopeMemberExpr(
CXXDependentScopeMemberExpr *Node) {
- PrintExpr(Node->getBase());
- OS << (Node->isArrow() ? "->" : ".");
+ if (!Node->isImplicitAccess()) {
+ PrintExpr(Node->getBase());
+ OS << (Node->isArrow() ? "->" : ".");
+ }
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
- else if (Node->hasExplicitTemplateArgumentList())
+ else if (Node->hasExplicitTemplateArgs())
// FIXME: Track use of "template" keyword explicitly?
OS << "template ";
OS << Node->getMember().getAsString();
- if (Node->hasExplicitTemplateArgumentList()) {
+ if (Node->hasExplicitTemplateArgs()) {
OS << TemplateSpecializationType::PrintTemplateArgumentList(
Node->getTemplateArgs(),
Node->getNumTemplateArgs(),
@@ -1164,8 +1166,10 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr(
}
void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
- PrintExpr(Node->getBase());
- OS << (Node->isArrow() ? "->" : ".");
+ if (!Node->isImplicitAccess()) {
+ PrintExpr(Node->getBase());
+ OS << (Node->isArrow() ? "->" : ".");
+ }
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index d832a46..e2d772b 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -554,18 +554,24 @@ StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) {
void
StmtProfiler::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *S) {
- VisitExpr(S);
- ID.AddBoolean(S->isArrow());
+ ID.AddBoolean(S->isImplicitAccess());
+ if (!S->isImplicitAccess()) {
+ VisitExpr(S);
+ ID.AddBoolean(S->isArrow());
+ }
VisitNestedNameSpecifier(S->getQualifier());
VisitName(S->getMember());
- ID.AddBoolean(S->hasExplicitTemplateArgumentList());
- if (S->hasExplicitTemplateArgumentList())
+ ID.AddBoolean(S->hasExplicitTemplateArgs());
+ if (S->hasExplicitTemplateArgs())
VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
}
void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) {
- VisitExpr(S);
- ID.AddBoolean(S->isArrow());
+ ID.AddBoolean(S->isImplicitAccess());
+ if (!S->isImplicitAccess()) {
+ VisitExpr(S);
+ ID.AddBoolean(S->isArrow());
+ }
VisitNestedNameSpecifier(S->getQualifier());
VisitName(S->getMemberName());
ID.AddBoolean(S->hasExplicitTemplateArgs());
@@ -653,13 +659,6 @@ void StmtProfiler::VisitDecl(Decl *D) {
ID.AddInteger(TTP->getIndex());
return;
}
-
- if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) {
- // The Itanium C++ ABI mangles references to a set of overloaded
- // functions using just the function name, so we do the same here.
- VisitName(Ovl->getDeclName());
- return;
- }
}
ID.AddPointer(D? D->getCanonicalDecl() : 0);
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index f341b45..e9b1725 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -102,7 +102,7 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
return getSourceDeclExpression()->getSourceRange();
case TemplateArgument::Type:
- return getSourceDeclaratorInfo()->getTypeLoc().getFullSourceRange();
+ return getTypeSourceInfo()->getTypeLoc().getFullSourceRange();
case TemplateArgument::Template:
if (getTemplateQualifierRange().isValid())
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index 5b4cf0a..b56c0ceb 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -29,25 +29,14 @@ TemplateDecl *TemplateName::getAsTemplateDecl() const {
return 0;
}
-OverloadedFunctionDecl *TemplateName::getAsOverloadedFunctionDecl() const {
- if (OverloadedFunctionDecl *Ovl
- = Storage.dyn_cast<OverloadedFunctionDecl *>())
- return Ovl;
-
- if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName())
- return QTN->getOverloadedFunctionDecl();
-
- return 0;
-}
-
bool TemplateName::isDependent() const {
if (TemplateDecl *Template = getAsTemplateDecl()) {
return isa<TemplateTemplateParmDecl>(Template) ||
Template->getDeclContext()->isDependentContext();
}
- if (OverloadedFunctionDecl *Ovl = getAsOverloadedFunctionDecl())
- return Ovl->getDeclContext()->isDependentContext();
+ assert(!getAsOverloadedTemplate() &&
+ "overloaded templates shouldn't survive to here");
return true;
}
@@ -57,9 +46,6 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
bool SuppressNNS) const {
if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
OS << Template->getNameAsString();
- else if (OverloadedFunctionDecl *Ovl
- = Storage.dyn_cast<OverloadedFunctionDecl *>())
- OS << Ovl->getNameAsString();
else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
if (!SuppressNNS)
QTN->getQualifier()->print(OS, Policy);
@@ -84,13 +70,3 @@ void TemplateName::dump() const {
LO.Bool = true;
print(llvm::errs(), PrintingPolicy(LO));
}
-
-TemplateDecl *QualifiedTemplateName::getTemplateDecl() const {
- return dyn_cast<TemplateDecl>(Template);
-}
-
-OverloadedFunctionDecl *
-QualifiedTemplateName::getOverloadedFunctionDecl() const {
- return dyn_cast<OverloadedFunctionDecl>(Template);
-}
-
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 5a2434d..687beae 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -434,6 +434,18 @@ bool Type::isWideCharType() const {
return false;
}
+/// \brief Determine whether this type is any of the built-in character
+/// types.
+bool Type::isAnyCharacterType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return (BT->getKind() >= BuiltinType::Char_U &&
+ BT->getKind() <= BuiltinType::Char32) ||
+ (BT->getKind() >= BuiltinType::Char_S &&
+ BT->getKind() <= BuiltinType::WChar);
+
+ return false;
+}
+
/// isSignedIntegerType - Return true if this is an integer type that is
/// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..],
/// an enum decl which has a signed representation, or a vector of signed
@@ -639,6 +651,40 @@ bool Type::isPODType() const {
}
}
+bool Type::isLiteralType() const {
+ if (isIncompleteType())
+ return false;
+
+ // C++0x [basic.types]p10:
+ // A type is a literal type if it is:
+ switch (CanonicalType->getTypeClass()) {
+ // We're whitelisting
+ default: return false;
+
+ // -- a scalar type
+ case Builtin:
+ case Complex:
+ case Pointer:
+ case MemberPointer:
+ case Vector:
+ case ExtVector:
+ case ObjCObjectPointer:
+ case Enum:
+ return true;
+
+ // -- a class type with ...
+ case Record:
+ // FIXME: Do the tests
+ return false;
+
+ // -- an array of literal type
+ // Extension: variable arrays cannot be literal types, since they're
+ // runtime-sized.
+ case ConstantArray:
+ return cast<ArrayType>(CanonicalType)->getElementType()->isLiteralType();
+ }
+}
+
bool Type::isPromotableIntegerType() const {
if (const BuiltinType *BT = getAs<BuiltinType>())
switch (BT->getKind()) {
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 50a5120..3ccb7a9 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -94,3 +94,32 @@ void TypeLoc::initializeImpl(TypeLoc TL, SourceLocation Loc) {
TypeLocInitializer(Loc).Visit(TL);
} while ((TL = TL.getNextTypeLoc()));
}
+
+namespace {
+ struct TSTChecker : public TypeLocVisitor<TSTChecker, bool> {
+ // Overload resolution does the real work for us.
+ static bool isTypeSpec(TypeSpecTypeLoc _) { return true; }
+ static bool isTypeSpec(TypeLoc _) { return false; }
+
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
+ return isTypeSpec(TyLoc); \
+ }
+#include "clang/AST/TypeLocNodes.def"
+ };
+}
+
+
+/// \brief Determines if the given type loc corresponds to a
+/// TypeSpecTypeLoc. Since there is not actually a TypeSpecType in
+/// the type hierarchy, this is made somewhat complicated.
+///
+/// There are a lot of types that currently use TypeSpecTypeLoc
+/// because it's a convenient base class. Ideally we would not accept
+/// those here, but ideally we would have better implementations for
+/// them.
+bool TypeSpecTypeLoc::classof(const TypeLoc *TL) {
+ if (TL->getType().hasLocalQualifiers()) return false;
+ return TSTChecker().Visit(*TL);
+}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 562e830..4a2b956 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -242,12 +242,13 @@ void TypePrinter::PrintDependentSizedExtVector(
void TypePrinter::PrintVector(const VectorType *T, std::string &S) {
// FIXME: We prefer to print the size directly here, but have no way
// to get the size of the type.
- S += " __attribute__((__vector_size__(";
- S += llvm::utostr_32(T->getNumElements()); // convert back to bytes.
+ Print(T->getElementType(), S);
+ std::string V = "__attribute__((__vector_size__(";
+ V += llvm::utostr_32(T->getNumElements()); // convert back to bytes.
std::string ET;
Print(T->getElementType(), ET);
- S += " * sizeof(" + ET + "))))";
- Print(T->getElementType(), S);
+ V += " * sizeof(" + ET + ")))) ";
+ S = V + S;
}
void TypePrinter::PrintExtVector(const ExtVectorType *T, std::string &S) {
@@ -284,6 +285,23 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
}
S += ")";
+
+ if (T->hasExceptionSpec()) {
+ S += " throw(";
+ if (T->hasAnyExceptionSpec())
+ S += "...";
+ else
+ for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) {
+ if (I)
+ S += ", ";
+
+ std::string ExceptionType;
+ Print(T->getExceptionType(I), ExceptionType);
+ S += ExceptionType;
+ }
+ S += ")";
+ }
+
if (T->getNoReturnAttr())
S += " __attribute__((noreturn))";
Print(T->getResultType(), S);
@@ -302,6 +320,15 @@ void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T,
Print(T->getResultType(), S);
}
+void TypePrinter::PrintUnresolvedUsing(const UnresolvedUsingType *T,
+ std::string &S) {
+ IdentifierInfo *II = T->getDecl()->getIdentifier();
+ if (S.empty())
+ S = II->getName().str();
+ else
+ S = II->getName().str() + ' ' + S;
+}
+
void TypePrinter::PrintTypedef(const TypedefType *T, std::string &S) {
if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'.
S = ' ' + S;
@@ -683,9 +710,8 @@ void QualType::dump(const char *msg) const {
LangOptions LO;
getAsStringInternal(R, PrintingPolicy(LO));
if (msg)
- fprintf(stderr, "%s: %s\n", msg, R.c_str());
- else
- fprintf(stderr, "%s\n", R.c_str());
+ llvm::errs() << msg << ": ";
+ llvm::errs() << R << "\n";
}
void QualType::dump() const {
dump("");
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 339e2c9..05e5196 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Analysis/PathSensitive/MemRegion.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/CFG.h"
#include "clang/AST/Decl.h"
@@ -35,8 +36,10 @@ Stmt *AnalysisContext::getBody() {
return FD->getBody();
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
return MD->getBody();
+ else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
+ return BD->getBody();
- llvm::llvm_unreachable("unknown code decl");
+ llvm_unreachable("unknown code decl");
}
const ImplicitParamDecl *AnalysisContext::getSelfDecl() const {
@@ -80,73 +83,113 @@ AnalysisContext *AnalysisContextManager::getContext(const Decl *D) {
return AC;
}
-void LocationContext::Profile(llvm::FoldingSetNodeID &ID, ContextKind k,
- AnalysisContext *ctx,
- const LocationContext *parent) {
- ID.AddInteger(k);
+const BlockDecl *BlockInvocationContext::getBlockDecl() const {
+ return Data.is<const BlockDataRegion*>() ?
+ Data.get<const BlockDataRegion*>()->getDecl()
+ : Data.get<const BlockDecl*>();
+}
+
+//===----------------------------------------------------------------------===//
+// FoldingSet profiling.
+//===----------------------------------------------------------------------===//
+
+void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID,
+ ContextKind ck,
+ AnalysisContext *ctx,
+ const LocationContext *parent,
+ const void* data) {
+ ID.AddInteger(ck);
ID.AddPointer(ctx);
ID.AddPointer(parent);
+ ID.AddPointer(data);
}
-void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID,AnalysisContext *ctx,
- const LocationContext *parent, const Stmt *s) {
- LocationContext::Profile(ID, StackFrame, ctx, parent);
- ID.AddPointer(s);
+void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getAnalysisContext(), getParent(), CallSite);
}
-void ScopeContext::Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
- const LocationContext *parent, const Stmt *s) {
- LocationContext::Profile(ID, Scope, ctx, parent);
- ID.AddPointer(s);
+void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getAnalysisContext(), getParent(), Enter);
}
-LocationContextManager::~LocationContextManager() {
- clear();
+void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) {
+ if (const BlockDataRegion *BR = getBlockRegion())
+ Profile(ID, getAnalysisContext(), getParent(), BR);
+ else
+ Profile(ID, getAnalysisContext(), getParent(),
+ Data.get<const BlockDecl*>());
}
-void LocationContextManager::clear() {
- for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(),
- E = Contexts.end(); I != E; ) {
- LocationContext *LC = &*I;
- ++I;
- delete LC;
- }
+//===----------------------------------------------------------------------===//
+// LocationContext creation.
+//===----------------------------------------------------------------------===//
+
+template <typename LOC, typename DATA>
+const LOC*
+LocationContextManager::getLocationContext(AnalysisContext *ctx,
+ const LocationContext *parent,
+ const DATA *d) {
+ llvm::FoldingSetNodeID ID;
+ LOC::Profile(ID, ctx, parent, d);
+ void *InsertPos;
- Contexts.clear();
+ LOC *L = cast_or_null<LOC>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
+
+ if (!L) {
+ L = new LOC(ctx, parent, d);
+ Contexts.InsertNode(L, InsertPos);
+ }
+ return L;
}
-StackFrameContext*
+const StackFrameContext*
LocationContextManager::getStackFrame(AnalysisContext *ctx,
const LocationContext *parent,
const Stmt *s) {
- llvm::FoldingSetNodeID ID;
- StackFrameContext::Profile(ID, ctx, parent, s);
- void *InsertPos;
+ return getLocationContext<StackFrameContext, Stmt>(ctx, parent, s);
+}
- StackFrameContext *f =
- cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
- if (!f) {
- f = new StackFrameContext(ctx, parent, s);
- Contexts.InsertNode(f, InsertPos);
- }
- return f;
+const ScopeContext *
+LocationContextManager::getScope(AnalysisContext *ctx,
+ const LocationContext *parent,
+ const Stmt *s) {
+ return getLocationContext<ScopeContext, Stmt>(ctx, parent, s);
}
-ScopeContext *LocationContextManager::getScope(AnalysisContext *ctx,
- const LocationContext *parent,
- const Stmt *s) {
- llvm::FoldingSetNodeID ID;
- ScopeContext::Profile(ID, ctx, parent, s);
- void *InsertPos;
+const BlockInvocationContext *
+LocationContextManager::getBlockInvocation(AnalysisContext *ctx,
+ const LocationContext *parent,
+ const BlockDataRegion *BR) {
+ return getLocationContext<BlockInvocationContext, BlockDataRegion>(ctx,
+ parent,
+ BR);
+}
- ScopeContext *scope =
- cast_or_null<ScopeContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
+//===----------------------------------------------------------------------===//
+// LocationContext methods.
+//===----------------------------------------------------------------------===//
- if (!scope) {
- scope = new ScopeContext(ctx, parent, s);
- Contexts.InsertNode(scope, InsertPos);
+const StackFrameContext *LocationContext::getCurrentStackFrame() const {
+ const LocationContext *LC = this;
+ while (LC) {
+ if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LC))
+ return SFC;
+ LC = LC->getParent();
}
- return scope;
+ return NULL;
+}
+
+const StackFrameContext *
+LocationContext::getStackFrameForDeclContext(const DeclContext *DC) const {
+ const LocationContext *LC = this;
+ while (LC) {
+ if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LC)) {
+ if (cast<DeclContext>(SFC->getDecl()) == DC)
+ return SFC;
+ }
+ LC = LC->getParent();
+ }
+ return NULL;
}
//===----------------------------------------------------------------------===//
@@ -220,3 +263,21 @@ AnalysisContextManager::~AnalysisContextManager() {
for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
delete I->second;
}
+
+LocationContext::~LocationContext() {}
+
+LocationContextManager::~LocationContextManager() {
+ clear();
+}
+
+void LocationContextManager::clear() {
+ for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(),
+ E = Contexts.end(); I != E; ) {
+ LocationContext *LC = &*I;
+ ++I;
+ delete LC;
+ }
+
+ Contexts.clear();
+}
+
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp
index 45fc11a..a38aaa7 100644
--- a/lib/Analysis/BasicStore.cpp
+++ b/lib/Analysis/BasicStore.cpp
@@ -68,14 +68,14 @@ public:
}
const GRState *BindCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr* cl,
+ const CompoundLiteralExpr*,
+ const LocationContext*,
SVal val) {
return state;
}
SVal getLValueVar(const VarDecl *VD, const LocationContext *LC);
SVal getLValueString(const StringLiteral *S);
- SVal getLValueCompoundLiteral(const CompoundLiteralExpr *CL);
SVal getLValueIvar(const ObjCIvarDecl* D, SVal Base);
SVal getLValueField(const FieldDecl *D, SVal Base);
SVal getLValueElement(QualType elementType, SVal Offset, SVal Base);
@@ -130,10 +130,6 @@ SVal BasicStoreManager::getLValueString(const StringLiteral* S) {
return ValMgr.makeLoc(MRMgr.getStringRegion(S));
}
-SVal BasicStoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL){
- return ValMgr.makeLoc(MRMgr.getCompoundLiteralRegion(CL));
-}
-
SVal BasicStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) {
if (Base.isUnknownOrUndef())
@@ -368,7 +364,7 @@ BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
// Iterate over the variable bindings.
for (BindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) {
if (const VarRegion *VR = dyn_cast<VarRegion>(I.getKey())) {
- if (SymReaper.isLive(Loc, VR->getDecl()))
+ if (SymReaper.isLive(Loc, VR))
RegionRoots.push_back(VR);
else
continue;
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index c26a60a..e648269 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -204,10 +204,19 @@ PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream& os,
os << "Execution continues on line "
<< getSourceManager().getInstantiationLineNumber(Loc.asLocation())
<< '.';
- else
- os << "Execution jumps to the end of the "
- << (isa<ObjCMethodDecl>(N->getLocationContext()->getDecl()) ?
- "method" : "function") << '.';
+ else {
+ os << "Execution jumps to the end of the ";
+ const Decl *D = N->getLocationContext()->getDecl();
+ if (isa<ObjCMethodDecl>(D))
+ os << "method";
+ else if (isa<FunctionDecl>(D))
+ os << "function";
+ else {
+ assert(isa<BlockDecl>(D));
+ os << "anonymous block";
+ }
+ os << '.';
+ }
return Loc;
}
diff --git a/lib/Analysis/BuiltinFunctionChecker.cpp b/lib/Analysis/BuiltinFunctionChecker.cpp
new file mode 100644
index 0000000..a89ad21
--- /dev/null
+++ b/lib/Analysis/BuiltinFunctionChecker.cpp
@@ -0,0 +1,76 @@
+//=== BuiltinFunctionChecker.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker evaluates clang builtin functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Basic/Builtins.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+
+namespace {
+
+class BuiltinFunctionChecker : public Checker {
+public:
+ static void *getTag() { static int tag = 0; return &tag; }
+ virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+
+}
+
+void clang::RegisterBuiltinFunctionChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new BuiltinFunctionChecker());
+}
+
+bool BuiltinFunctionChecker::EvalCallExpr(CheckerContext &C,const CallExpr *CE){
+ const GRState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = state->getSVal(Callee);
+ const FunctionDecl *FD = L.getAsFunctionDecl();
+
+ if (!FD)
+ return false;
+
+ unsigned id = FD->getBuiltinID();
+
+ if (!id)
+ return false;
+
+ switch (id) {
+ case Builtin::BI__builtin_expect: {
+ // For __builtin_expect, just return the value of the subexpression.
+ assert (CE->arg_begin() != CE->arg_end());
+ SVal X = state->getSVal(*(CE->arg_begin()));
+ C.GenerateNode(state->BindExpr(CE, X));
+ return true;
+ }
+
+ case Builtin::BI__builtin_alloca: {
+ // FIXME: Refactor into StoreManager itself?
+ MemRegionManager& RM = C.getStoreManager().getRegionManager();
+ const MemRegion* R =
+ RM.getAllocaRegion(CE, C.getNodeBuilder().getCurrentBlockCount(),
+ C.getPredecessor()->getLocationContext());
+
+ // Set the extent of the region in bytes. This enables us to use the
+ // SVal of the argument directly. If we save the extent in bits, we
+ // cannot represent values like symbol*8.
+ SVal Extent = state->getSVal(*(CE->arg_begin()));
+ state = C.getStoreManager().setExtent(state, R, Extent);
+ C.GenerateNode(state->BindExpr(CE, loc::MemRegionVal(R)));
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index c97692f..e1a1e72 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -87,7 +87,6 @@ private:
CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd);
CFGBlock *VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd);
CFGBlock *VisitBlockExpr(BlockExpr* E, bool alwaysAdd);
- CFGBlock *VisitBlockDeclRefExpr(BlockDeclRefExpr* E, bool alwaysAdd);
CFGBlock *VisitBreakStmt(BreakStmt *B);
CFGBlock *VisitCallExpr(CallExpr *C, bool alwaysAdd);
CFGBlock *VisitCaseStmt(CaseStmt *C);
@@ -95,7 +94,9 @@ private:
CFGBlock *VisitCompoundStmt(CompoundStmt *C);
CFGBlock *VisitConditionalOperator(ConditionalOperator *C);
CFGBlock *VisitContinueStmt(ContinueStmt *C);
+ CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S) { return NYS(); }
CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
+ CFGBlock *VisitCXXTryStmt(CXXTryStmt *S) { return NYS(); }
CFGBlock *VisitDeclStmt(DeclStmt *DS);
CFGBlock *VisitDeclSubExpr(Decl* D);
CFGBlock *VisitDefaultStmt(DefaultStmt *D);
@@ -292,9 +293,6 @@ tryAgain:
case Stmt::BlockExprClass:
return VisitBlockExpr(cast<BlockExpr>(S), alwaysAdd);
- case Stmt::BlockDeclRefExprClass:
- return VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(S), alwaysAdd);
-
case Stmt::BreakStmtClass:
return VisitBreakStmt(cast<BreakStmt>(S));
@@ -468,12 +466,6 @@ CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, bool alwaysAdd) {
return Block;
}
-CFGBlock *CFGBuilder::VisitBlockDeclRefExpr(BlockDeclRefExpr* E,
- bool alwaysAdd) {
- // FIXME
- return NYS();
-}
-
CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
// "break" is a control-flow statement. Thus we stop processing the current
// block.
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index b95f981..9639ad9 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -675,11 +675,9 @@ template <> struct DenseMapInfo<ObjCSummaryKey> {
RHS.getSelector());
}
- static bool isPod() {
- return DenseMapInfo<ObjCInterfaceDecl*>::isPod() &&
- DenseMapInfo<Selector>::isPod();
- }
};
+template <>
+struct isPodLike<ObjCSummaryKey> { static const bool value = true; };
} // end llvm namespace
namespace {
@@ -1984,8 +1982,9 @@ public:
Expr* Ex,
Expr* Receiver,
const RetainSummary& Summ,
+ const MemRegion *Callee,
ExprIterator arg_beg, ExprIterator arg_end,
- ExplodedNode* Pred);
+ ExplodedNode* Pred, const GRState *state);
virtual void EvalCall(ExplodedNodeSet& Dst,
GRExprEngine& Eng,
@@ -1998,7 +1997,8 @@ public:
GRExprEngine& Engine,
GRStmtNodeBuilder& Builder,
ObjCMessageExpr* ME,
- ExplodedNode* Pred);
+ ExplodedNode* Pred,
+ const GRState *state);
bool EvalObjCMessageExprAux(ExplodedNodeSet& Dst,
GRExprEngine& Engine,
@@ -2776,11 +2776,9 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
Expr* Ex,
Expr* Receiver,
const RetainSummary& Summ,
+ const MemRegion *Callee,
ExprIterator arg_beg, ExprIterator arg_end,
- ExplodedNode* Pred) {
-
- // Get the state.
- const GRState *state = Builder.GetState(Pred);
+ ExplodedNode* Pred, const GRState *state) {
// Evaluate the effect of the arguments.
RefVal::Kind hasErr = (RefVal::Kind) 0;
@@ -2788,6 +2786,8 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
Expr* ErrorExpr = NULL;
SymbolRef ErrorSym = 0;
+ llvm::SmallVector<const MemRegion*, 10> RegionsToInvalidate;
+
for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) {
SVal V = state->getSValAsScalarOrLoc(*I);
SymbolRef Sym = V.getAsLocSymbol();
@@ -2810,16 +2810,8 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
continue;
// Invalidate the value of the variable passed by reference.
-
- // FIXME: We can have collisions on the conjured symbol if the
- // expression *I also creates conjured symbols. We probably want
- // to identify conjured symbols by an expression pair: the enclosing
- // expression (the context) and the expression itself. This should
- // disambiguate conjured symbols.
- unsigned Count = Builder.getCurrentBlockCount();
- StoreManager& StoreMgr = Eng.getStateManager().getStoreManager();
-
const MemRegion *R = MR->getRegion();
+
// Are we dealing with an ElementRegion? If the element type is
// a basic integer type (e.g., char, int) and the underying region
// is a variable region then strip off the ElementRegion.
@@ -2843,14 +2835,11 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
}
// FIXME: What about layers of ElementRegions?
}
-
- StoreManager::InvalidatedSymbols IS;
- state = StoreMgr.InvalidateRegion(state, R, *I, Count, &IS);
- for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(),
- E = IS.end(); I!=E; ++I) {
- // Remove any existing reference-count binding.
- state = state->remove<RefBindings>(*I);
- }
+
+ // Mark this region for invalidation. We batch invalidate regions
+ // below for efficiency.
+ RegionsToInvalidate.push_back(R);
+ continue;
}
else {
// Nuke all other arguments passed by reference.
@@ -2866,6 +2855,36 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
goto tryAgain;
}
}
+
+ // Block calls result in all captured values passed-via-reference to be
+ // invalidated.
+ if (const BlockDataRegion *BR = dyn_cast_or_null<BlockDataRegion>(Callee)) {
+ RegionsToInvalidate.push_back(BR);
+ }
+
+ // Invalidate regions we designed for invalidation use the batch invalidation
+ // API.
+ if (!RegionsToInvalidate.empty()) {
+ // FIXME: We can have collisions on the conjured symbol if the
+ // expression *I also creates conjured symbols. We probably want
+ // to identify conjured symbols by an expression pair: the enclosing
+ // expression (the context) and the expression itself. This should
+ // disambiguate conjured symbols.
+ unsigned Count = Builder.getCurrentBlockCount();
+ StoreManager& StoreMgr = Eng.getStateManager().getStoreManager();
+
+
+ StoreManager::InvalidatedSymbols IS;
+ state = StoreMgr.InvalidateRegions(state, RegionsToInvalidate.data(),
+ RegionsToInvalidate.data() +
+ RegionsToInvalidate.size(),
+ Ex, Count, &IS);
+ for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(),
+ E = IS.end(); I!=E; ++I) {
+ // Remove any existing reference-count binding.
+ state = state->remove<RefBindings>(*I);
+ }
+ }
// Evaluate the effect on the message receiver.
if (!ErrorExpr && Receiver) {
@@ -3012,35 +3031,24 @@ void CFRefCount::EvalCall(ExplodedNodeSet& Dst,
}
assert(Summ);
- EvalSummary(Dst, Eng, Builder, CE, 0, *Summ,
- CE->arg_begin(), CE->arg_end(), Pred);
+ EvalSummary(Dst, Eng, Builder, CE, 0, *Summ, L.getAsRegion(),
+ CE->arg_begin(), CE->arg_end(), Pred, Builder.GetState(Pred));
}
void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
GRExprEngine& Eng,
GRStmtNodeBuilder& Builder,
ObjCMessageExpr* ME,
- ExplodedNode* Pred) {
- // FIXME: Since we moved the nil check into a checker, we could get nil
- // receiver here. Need a better way to check such case.
- if (Expr* Receiver = ME->getReceiver()) {
- const GRState *state = Pred->getState();
- DefinedOrUnknownSVal L=cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
- if (!state->Assume(L, true)) {
- Dst.Add(Pred);
- return;
- }
- }
-
+ ExplodedNode* Pred,
+ const GRState *state) {
RetainSummary *Summ =
ME->getReceiver()
- ? Summaries.getInstanceMethodSummary(ME, Builder.GetState(Pred),
- Pred->getLocationContext())
+ ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext())
: Summaries.getClassMethodSummary(ME);
assert(Summ && "RetainSummary is null");
- EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ,
- ME->arg_begin(), ME->arg_end(), Pred);
+ EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, NULL,
+ ME->arg_begin(), ME->arg_end(), Pred, state);
}
namespace {
@@ -3671,7 +3679,24 @@ void RetainReleaseChecker::PostVisitBlockExpr(CheckerContext &C,
if (I == E)
return;
- state = state->scanReachableSymbols<StopTrackingCallback>(I, E).getState();
+ // FIXME: For now we invalidate the tracking of all symbols passed to blocks
+ // via captured variables, even though captured variables result in a copy
+ // and in implicit increment/decrement of a retain count.
+ llvm::SmallVector<const MemRegion*, 10> Regions;
+ const LocationContext *LC = C.getPredecessor()->getLocationContext();
+ MemRegionManager &MemMgr = C.getValueManager().getRegionManager();
+
+ for ( ; I != E; ++I) {
+ const VarRegion *VR = *I;
+ if (VR->getSuperRegion() == R) {
+ VR = MemMgr.getVarRegion(VR->getDecl(), LC);
+ }
+ Regions.push_back(VR);
+ }
+
+ state =
+ state->scanReachableSymbols<StopTrackingCallback>(Regions.data(),
+ Regions.data() + Regions.size()).getState();
C.addTransition(state);
}
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index 409292d..521f1be 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -10,10 +10,10 @@ add_clang_library(clangAnalysis
BasicValueFactory.cpp
BugReporter.cpp
BugReporterVisitors.cpp
+ BuiltinFunctionChecker.cpp
CFG.cpp
CFRefCount.cpp
CallAndMessageChecker.cpp
- CallGraph.cpp
CallInliner.cpp
CastToStructChecker.cpp
CheckDeadStores.cpp
@@ -37,8 +37,10 @@ add_clang_library(clangAnalysis
MallocChecker.cpp
ManagerRegistry.cpp
MemRegion.cpp
+ NoReturnFunctionChecker.cpp
NSAutoreleasePoolChecker.cpp
NSErrorChecker.cpp
+ OSAtomicChecker.cpp
PathDiagnostic.cpp
PointerArithChecker.cpp
PointerSubChecker.cpp
diff --git a/lib/Analysis/CallAndMessageChecker.cpp b/lib/Analysis/CallAndMessageChecker.cpp
index d8dd16c..c287354 100644
--- a/lib/Analysis/CallAndMessageChecker.cpp
+++ b/lib/Analysis/CallAndMessageChecker.cpp
@@ -41,6 +41,7 @@ public:
void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+ bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
private:
void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
@@ -148,28 +149,12 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
}
}
}
+}
- // Check if the receiver was nil and then returns a value that may
- // be garbage.
- if (const Expr *Receiver = ME->getReceiver()) {
- DefinedOrUnknownSVal receiverVal =
- cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
-
- const GRState *notNullState, *nullState;
- llvm::tie(notNullState, nullState) = state->Assume(receiverVal);
-
- if (nullState && !notNullState) {
- HandleNilReceiver(C, nullState, ME);
- C.setDoneEvaluating(); // FIXME: eventually remove.
- return;
- }
-
- assert(notNullState);
- state = notNullState;
- }
-
- // Add a state transition if the state has changed.
- C.addTransition(state);
+bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C,
+ const ObjCMessageExpr *ME) {
+ HandleNilReceiver(C, C.getState(), ME);
+ return true; // Nil receiver is not handled elsewhere.
}
void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp
index ad63eb4..db9016f 100644
--- a/lib/Analysis/CheckDeadStores.cpp
+++ b/lib/Analysis/CheckDeadStores.cpp
@@ -84,7 +84,8 @@ public:
const LiveVariables::AnalysisDataTy& AD,
const LiveVariables::ValTy& Live) {
- if (VD->hasLocalStorage() && !Live(VD, AD) && !VD->getAttr<UnusedAttr>())
+ if (VD->hasLocalStorage() && !Live(VD, AD) &&
+ !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>()))
Report(VD, dsk, Ex->getSourceRange().getBegin(),
Val->getSourceRange());
}
@@ -185,6 +186,10 @@ public:
if (V->hasLocalStorage())
if (Expr* E = V->getInit()) {
+ // Don't warn on C++ objects (yet) until we can show that their
+ // constructors/destructors don't have side effects.
+ if (isa<CXXConstructExpr>(E))
+ return;
// A dead initialization is a variable that is dead after it
// is initialized. We don't flag warnings for those variables
// marked 'unused'.
diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
index e6ab17a..3214101 100644
--- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
@@ -23,6 +23,7 @@ class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
IdentifierInfo *II_gets;
IdentifierInfo *II_getpw;
+ IdentifierInfo *II_mktemp;
enum { num_rands = 9 };
IdentifierInfo *II_rand[num_rands];
IdentifierInfo *II_random;
@@ -31,7 +32,8 @@ class WalkAST : public StmtVisitor<WalkAST> {
public:
WalkAST(BugReporter &br) : BR(br),
- II_gets(0), II_getpw(0), II_rand(), II_random(0), II_setid() {}
+ II_gets(0), II_getpw(0), II_mktemp(0),
+ II_rand(), II_random(0), II_setid() {}
// Statement visitor methods.
void VisitCallExpr(CallExpr *CE);
@@ -48,6 +50,7 @@ public:
void CheckLoopConditionForFloat(const ForStmt *FS);
void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD);
void CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
+ void CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
void CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD);
void CheckCall_random(const CallExpr *CE, const FunctionDecl *FD);
void CheckUncheckedReturnValue(CallExpr *CE);
@@ -79,6 +82,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
if (const FunctionDecl *FD = CE->getDirectCallee()) {
CheckCall_gets(CE, FD);
CheckCall_getpw(CE, FD);
+ CheckCall_mktemp(CE, FD);
CheckCall_rand(CE, FD);
CheckCall_random(CE, FD);
}
@@ -288,6 +292,42 @@ void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
}
//===----------------------------------------------------------------------===//
+// Check: Any use of 'mktemp' is insecure.It is obsoleted by mkstemp().
+// CWE-377: Insecure Temporary File
+//===----------------------------------------------------------------------===//
+
+void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
+ if (FD->getIdentifier() != GetIdentifier(II_mktemp, "mktemp"))
+ return;
+
+ const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType());
+ if(!FPT)
+ return;
+
+ // Verify that the funcion takes a single argument.
+ if (FPT->getNumArgs() != 1)
+ return;
+
+ // Verify that the argument is Pointer Type.
+ const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
+ if (!PT)
+ return;
+
+ // Verify that the argument is a 'char*'.
+ if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
+ return;
+
+ // Issue a waring.
+ SourceRange R = CE->getCallee()->getSourceRange();
+ BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'",
+ "Security",
+ "Call to function 'mktemp' is insecure as it always "
+ "creates or uses insecure temporary file",
+ CE->getLocStart(), &R, 1);
+}
+
+
+//===----------------------------------------------------------------------===//
// Check: Linear congruent random number generators should not be used
// Originally: <rdar://problem/63371000>
// CWE-338: Use of cryptographically weak prng
diff --git a/lib/Analysis/Checker.cpp b/lib/Analysis/Checker.cpp
index 0d907e5..fb9d04d 100644
--- a/lib/Analysis/Checker.cpp
+++ b/lib/Analysis/Checker.cpp
@@ -24,10 +24,10 @@ CheckerContext::~CheckerContext() {
// if we are building sinks or we generated a node and decided to not
// add it as a transition.
if (Dst.size() == size && !B.BuildSinks && !B.HasGeneratedNode) {
- if (state && state != B.GetState(Pred)) {
+ if (ST && ST != B.GetState(Pred)) {
static int autoTransitionTag = 0;
B.Tag = &autoTransitionTag;
- addTransition(state);
+ addTransition(ST);
}
else
Dst.Add(Pred);
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 20820d4..51e6a54 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -116,53 +116,91 @@ public:
// Checker worklist routines.
//===----------------------------------------------------------------------===//
-bool GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
+void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
ExplodedNodeSet &Src, bool isPrevisit) {
if (Checkers.empty()) {
Dst.insert(Src);
- return false;
+ return;
}
ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
- bool stopProcessingAfterCurrentChecker = false;
-
- for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
- {
- ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst
- : (PrevSet == &Tmp) ? &Src : &Tmp;
- CurrSet->clear();
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){
+ ExplodedNodeSet *CurrSet = 0;
+ if (I+1 == E)
+ CurrSet = &Dst;
+ else {
+ CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
+ CurrSet->clear();
+ }
void *tag = I->first;
Checker *checker = I->second;
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
- NI != NE; ++NI) {
- // FIXME: Halting evaluation of the checkers is something we may
- // not support later. The design is still evolving.
- if (checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI,
- tag, isPrevisit)) {
- if (CurrSet != &Dst)
- Dst.insert(*CurrSet);
-
- stopProcessingAfterCurrentChecker = true;
- continue;
- }
- assert(stopProcessingAfterCurrentChecker == false &&
- "Inconsistent setting of 'stopProcessingAfterCurrentChecker'");
- }
-
- if (stopProcessingAfterCurrentChecker)
- return true;
-
- // Continue on to the next checker. Update the current NodeSet.
+ NI != NE; ++NI)
+ checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit);
PrevSet = CurrSet;
}
// Don't autotransition. The CheckerContext objects should do this
// automatically.
- return false;
+}
+
+void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
+ ExplodedNodeSet &Dst,
+ const GRState *state,
+ ExplodedNode *Pred) {
+ bool Evaluated = false;
+ ExplodedNodeSet DstTmp;
+
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
+ void *tag = I->first;
+ Checker *checker = I->second;
+
+ if (checker->GR_EvalNilReceiver(DstTmp, *Builder, *this, ME, Pred, state,
+ tag)) {
+ Evaluated = true;
+ break;
+ } else
+ // The checker didn't evaluate the expr. Restore the Dst.
+ DstTmp.clear();
+ }
+
+ if (Evaluated)
+ Dst.insert(DstTmp);
+ else
+ Dst.insert(Pred);
+}
+
+// CheckerEvalCall returns true if one of the checkers processed the node.
+// This may return void when all call evaluation logic goes to some checker
+// in the future.
+bool GRExprEngine::CheckerEvalCall(const CallExpr *CE,
+ ExplodedNodeSet &Dst,
+ ExplodedNode *Pred) {
+ bool Evaluated = false;
+ ExplodedNodeSet DstTmp;
+
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
+ void *tag = I->first;
+ Checker *checker = I->second;
+
+ if (checker->GR_EvalCallExpr(DstTmp, *Builder, *this, CE, Pred, tag)) {
+ Evaluated = true;
+ break;
+ } else
+ // The checker didn't evaluate the expr. Restore the DstTmp set.
+ DstTmp.clear();
+ }
+
+ if (Evaluated)
+ Dst.insert(DstTmp);
+ else
+ Dst.insert(Pred);
+
+ return Evaluated;
}
// FIXME: This is largely copy-paste from CheckerVisit(). Need to
@@ -173,7 +211,7 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
SVal location, SVal val, bool isPrevisit) {
if (Checkers.empty()) {
- Dst = Src;
+ Dst.insert(Src);
return;
}
@@ -182,10 +220,14 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
{
- ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst
- : (PrevSet == &Tmp) ? &Src : &Tmp;
+ ExplodedNodeSet *CurrSet = 0;
+ if (I+1 == E)
+ CurrSet = &Dst;
+ else {
+ CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
+ CurrSet->clear();
+ }
- CurrSet->clear();
void *tag = I->first;
Checker *checker = I->second;
@@ -227,6 +269,11 @@ static void RegisterInternalChecks(GRExprEngine &Eng) {
RegisterUndefinedAssignmentChecker(Eng);
RegisterUndefBranchChecker(Eng);
RegisterUndefResultChecker(Eng);
+
+ // This is not a checker yet.
+ RegisterNoReturnFunctionChecker(Eng);
+ RegisterBuiltinFunctionChecker(Eng);
+ RegisterOSAtomicChecker(Eng);
}
GRExprEngine::GRExprEngine(AnalysisManager &mgr)
@@ -347,8 +394,9 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
Builder->setAuditor(BatchAuditor.get());
// Create the cleaned state.
- SymbolReaper SymReaper(Builder->getBasePredecessor()->getLiveVariables(),
- SymMgr);
+ const ExplodedNode *BasePred = Builder->getBasePredecessor();
+ SymbolReaper SymReaper(BasePred->getLiveVariables(), SymMgr,
+ BasePred->getLocationContext()->getCurrentStackFrame());
CleanedState = AMgr.shouldPurgeDead()
? StateMgr.RemoveDeadBindings(EntryNode->getState(), CurrentStmt, SymReaper)
: EntryNode->getState();
@@ -371,16 +419,20 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
CleanedState, SymReaper);
if (Checkers.empty())
- Tmp = Tmp2;
+ Tmp.insert(Tmp2);
else {
ExplodedNodeSet Tmp3;
ExplodedNodeSet *SrcSet = &Tmp2;
for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
I != E; ++I) {
- ExplodedNodeSet *DstSet = (I+1 == E) ? &Tmp
- : (SrcSet == &Tmp2) ? &Tmp3
- : &Tmp2;
- DstSet->clear();
+ ExplodedNodeSet *DstSet = 0;
+ if (I+1 == E)
+ DstSet = &Tmp;
+ else {
+ DstSet = (SrcSet == &Tmp2) ? &Tmp3 : &Tmp2;
+ DstSet->clear();
+ }
+
void *tag = I->first;
Checker *checker = I->second;
for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end();
@@ -441,6 +493,41 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
}
switch (S->getStmtClass()) {
+ // C++ stuff we don't support yet.
+ case Stmt::CXXMemberCallExprClass:
+ 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::CXXThisExprClass:
+ 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::CXXBindTemporaryExprClass:
+ case Stmt::CXXExprWithTemporariesClass:
+ case Stmt::CXXTemporaryObjectExprClass:
+ case Stmt::CXXUnresolvedConstructExprClass:
+ case Stmt::CXXDependentScopeMemberExprClass:
+ 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:
@@ -456,6 +543,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
case Stmt::AsmStmtClass:
VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
break;
+
+ case Stmt::BlockDeclRefExprClass:
+ VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(S), Pred, Dst, false);
+ break;
case Stmt::BlockExprClass:
VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
@@ -627,6 +718,10 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(Ex), Pred, Dst, true);
return;
+ case Stmt::BlockDeclRefExprClass:
+ VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(Ex), Pred, Dst, true);
+ return;
+
case Stmt::DeclRefExprClass:
VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true);
return;
@@ -1118,9 +1213,20 @@ void GRExprEngine::VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred,
void GRExprEngine::VisitDeclRefExpr(DeclRefExpr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst, bool asLValue) {
+ VisitCommonDeclRefExpr(Ex, Ex->getDecl(), Pred, Dst, asLValue);
+}
+
+void GRExprEngine::VisitBlockDeclRefExpr(BlockDeclRefExpr *Ex,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst, bool asLValue) {
+ VisitCommonDeclRefExpr(Ex, Ex->getDecl(), Pred, Dst, asLValue);
+}
+
+void GRExprEngine::VisitCommonDeclRefExpr(Expr *Ex, const NamedDecl *D,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst, bool asLValue) {
const GRState *state = GetState(Pred);
- const NamedDecl *D = Ex->getDecl();
if (const VarDecl* VD = dyn_cast<VarDecl>(D)) {
@@ -1354,10 +1460,14 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
{
- ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst
- : (PrevSet == &Tmp) ? &Src : &Tmp;
+ ExplodedNodeSet *CurrSet = 0;
+ if (I+1 == E)
+ CurrSet = &Dst;
+ else {
+ CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
+ CurrSet->clear();
+ }
- CurrSet->clear();
void *tag = I->first;
Checker *checker = I->second;
@@ -1376,232 +1486,8 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
}
//===----------------------------------------------------------------------===//
-// Transfer function: OSAtomics.
-//
-// FIXME: Eventually refactor into a more "plugin" infrastructure.
-//===----------------------------------------------------------------------===//
-
-// Mac OS X:
-// http://developer.apple.com/documentation/Darwin/Reference/Manpages/man3
-// atomic.3.html
-//
-static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet& Dst,
- GRExprEngine& Engine,
- GRStmtNodeBuilder& Builder,
- CallExpr* CE, ExplodedNode* Pred) {
-
- // Not enough arguments to match OSAtomicCompareAndSwap?
- if (CE->getNumArgs() != 3)
- return false;
-
- ASTContext &C = Engine.getContext();
- Expr *oldValueExpr = CE->getArg(0);
- QualType oldValueType = C.getCanonicalType(oldValueExpr->getType());
-
- Expr *newValueExpr = CE->getArg(1);
- QualType newValueType = C.getCanonicalType(newValueExpr->getType());
-
- // Do the types of 'oldValue' and 'newValue' match?
- if (oldValueType != newValueType)
- return false;
-
- Expr *theValueExpr = CE->getArg(2);
- const PointerType *theValueType =
- theValueExpr->getType()->getAs<PointerType>();
-
- // theValueType not a pointer?
- if (!theValueType)
- return false;
-
- QualType theValueTypePointee =
- C.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
-
- // The pointee must match newValueType and oldValueType.
- if (theValueTypePointee != newValueType)
- return false;
-
- static unsigned magic_load = 0;
- static unsigned magic_store = 0;
-
- const void *OSAtomicLoadTag = &magic_load;
- const void *OSAtomicStoreTag = &magic_store;
-
- // Load 'theValue'.
- const GRState *state = Pred->getState();
- ExplodedNodeSet Tmp;
- SVal location = state->getSVal(theValueExpr);
- // Here we should use the value type of the region as the load type.
- const MemRegion *R = location.getAsRegion();
- QualType LoadTy;
- if (R)
- LoadTy = cast<TypedRegion>(R)->getValueType(C);
- Engine.EvalLoad(Tmp, theValueExpr, Pred, state, location, OSAtomicLoadTag,
- LoadTy);
-
- for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
- I != E; ++I) {
-
- ExplodedNode *N = *I;
- const GRState *stateLoad = N->getState();
- SVal theValueVal_untested = stateLoad->getSVal(theValueExpr);
- SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
-
- // FIXME: Issue an error.
- if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
- return false;
- }
-
- DefinedOrUnknownSVal theValueVal =
- cast<DefinedOrUnknownSVal>(theValueVal_untested);
- DefinedOrUnknownSVal oldValueVal =
- cast<DefinedOrUnknownSVal>(oldValueVal_untested);
-
- SValuator &SVator = Engine.getSValuator();
-
- // Perform the comparison.
- DefinedOrUnknownSVal Cmp = SVator.EvalEQ(stateLoad, theValueVal,
- oldValueVal);
-
- const GRState *stateEqual = stateLoad->Assume(Cmp, true);
-
- // Were they equal?
- if (stateEqual) {
- // Perform the store.
- ExplodedNodeSet TmpStore;
- SVal val = stateEqual->getSVal(newValueExpr);
-
- // Handle implicit value casts.
- if (const TypedRegion *R =
- dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
- llvm::tie(state, val) = SVator.EvalCast(val, state, R->getValueType(C),
- newValueExpr->getType());
- }
-
- Engine.EvalStore(TmpStore, NULL, theValueExpr, N, stateEqual, location,
- val, OSAtomicStoreTag);
-
- // Now bind the result of the comparison.
- for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
- E2 = TmpStore.end(); I2 != E2; ++I2) {
- ExplodedNode *predNew = *I2;
- const GRState *stateNew = predNew->getState();
- SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType());
- Engine.MakeNode(Dst, CE, predNew, stateNew->BindExpr(CE, Res));
- }
- }
-
- // Were they not equal?
- if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) {
- SVal Res = Engine.getValueManager().makeTruthVal(false, CE->getType());
- Engine.MakeNode(Dst, CE, N, stateNotEqual->BindExpr(CE, Res));
- }
- }
-
- return true;
-}
-
-static bool EvalOSAtomic(ExplodedNodeSet& Dst,
- GRExprEngine& Engine,
- GRStmtNodeBuilder& Builder,
- CallExpr* CE, SVal L,
- ExplodedNode* Pred) {
- const FunctionDecl* FD = L.getAsFunctionDecl();
- if (!FD)
- return false;
-
- const char *FName = FD->getNameAsCString();
-
- // Check for compare and swap.
- if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 ||
- strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0)
- return EvalOSAtomicCompareAndSwap(Dst, Engine, Builder, CE, Pred);
-
- // FIXME: Other atomics.
- return false;
-}
-
-//===----------------------------------------------------------------------===//
// Transfer function: Function calls.
//===----------------------------------------------------------------------===//
-static void MarkNoReturnFunction(const FunctionDecl *FD, CallExpr *CE,
- const GRState *state,
- GRStmtNodeBuilder *Builder) {
- if (!FD)
- return;
-
- if (FD->getAttr<NoReturnAttr>() ||
- FD->getAttr<AnalyzerNoReturnAttr>())
- Builder->BuildSinks = true;
- else {
- // HACK: Some functions are not marked noreturn, and don't return.
- // Here are a few hardwired ones. If this takes too long, we can
- // potentially cache these results.
- using llvm::StringRef;
- bool BuildSinks
- = llvm::StringSwitch<bool>(StringRef(FD->getIdentifier()->getName()))
- .Case("exit", true)
- .Case("panic", true)
- .Case("error", true)
- .Case("Assert", true)
- // FIXME: This is just a wrapper around throwing an exception.
- // Eventually inter-procedural analysis should handle this easily.
- .Case("ziperr", true)
- .Case("assfail", true)
- .Case("db_error", true)
- .Case("__assert", true)
- .Case("__assert_rtn", true)
- .Case("__assert_fail", true)
- .Case("dtrace_assfail", true)
- .Case("yy_fatal_error", true)
- .Case("_XCAssertionFailureHandler", true)
- .Case("_DTAssertionFailureHandler", true)
- .Case("_TSAssertionFailureHandler", true)
- .Default(false);
-
- if (BuildSinks)
- Builder->BuildSinks = true;
- }
-}
-
-bool GRExprEngine::EvalBuiltinFunction(const FunctionDecl *FD, CallExpr *CE,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- if (!FD)
- return false;
-
- unsigned id = FD->getBuiltinID();
- if (!id)
- return false;
-
- const GRState *state = Pred->getState();
-
- switch (id) {
- case Builtin::BI__builtin_expect: {
- // For __builtin_expect, just return the value of the subexpression.
- assert (CE->arg_begin() != CE->arg_end());
- SVal X = state->getSVal(*(CE->arg_begin()));
- MakeNode(Dst, CE, Pred, state->BindExpr(CE, X));
- return true;
- }
-
- case Builtin::BI__builtin_alloca: {
- // FIXME: Refactor into StoreManager itself?
- MemRegionManager& RM = getStateManager().getRegionManager();
- const MemRegion* R =
- RM.getAllocaRegion(CE, Builder->getCurrentBlockCount());
-
- // Set the extent of the region in bytes. This enables us to use the
- // SVal of the argument directly. If we save the extent in bits, we
- // cannot represent values like symbol*8.
- SVal Extent = state->getSVal(*(CE->arg_begin()));
- state = getStoreManager().setExtent(state, R, Extent);
- MakeNode(Dst, CE, Pred, state->BindExpr(CE, loc::MemRegionVal(R)));
- return true;
- }
- }
-
- return false;
-}
void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
CallExpr::arg_iterator AI,
@@ -1659,6 +1545,8 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred,
}
// Finally, evaluate the function call.
+ ExplodedNodeSet DstTmp3;
+
for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
DI != DE; ++DI) {
@@ -1667,39 +1555,39 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred,
// FIXME: Add support for symbolic function calls (calls involving
// function pointer values that are symbolic).
-
- // Check for the "noreturn" attribute.
-
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- const FunctionDecl* FD = L.getAsFunctionDecl();
-
- MarkNoReturnFunction(FD, CE, state, Builder);
-
- // Evaluate the call.
- if (EvalBuiltinFunction(FD, CE, *DI, Dst))
- continue;
-
- // Dispatch to the plug-in transfer function.
- SaveOr OldHasGen(Builder->HasGeneratedNode);
- Pred = *DI;
+ ExplodedNodeSet DstChecker;
- // Dispatch to transfer function logic to handle the call itself.
- // FIXME: Allow us to chain together transfer functions.
- assert(Builder && "GRStmtNodeBuilder must be defined.");
- ExplodedNodeSet DstTmp;
+ // If the callee is processed by a checker, skip the rest logic.
+ if (CheckerEvalCall(CE, DstChecker, *DI))
+ DstTmp3.insert(DstChecker);
+ else {
+ for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(),
+ DE_Checker = DstChecker.end();
+ DI_Checker != DE_Checker; ++DI_Checker) {
+
+ // Dispatch to the plug-in transfer function.
+ unsigned OldSize = DstTmp3.size();
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
+ Pred = *DI_Checker;
+
+ // Dispatch to transfer function logic to handle the call itself.
+ // FIXME: Allow us to chain together transfer functions.
+ assert(Builder && "GRStmtNodeBuilder must be defined.");
- if (!EvalOSAtomic(DstTmp, *this, *Builder, CE, L, Pred))
- getTF().EvalCall(DstTmp, *this, *Builder, CE, L, Pred);
+ getTF().EvalCall(DstTmp3, *this, *Builder, CE, L, Pred);
- // Handle the case where no nodes where generated. Auto-generate that
- // contains the updated state if we aren't generating sinks.
- if (!Builder->BuildSinks && DstTmp.empty() &&
- !Builder->HasGeneratedNode)
- MakeNode(DstTmp, CE, Pred, state);
-
- // Perform the post-condition check of the CallExpr.
- CheckerVisit(CE, Dst, DstTmp, false);
+ // Handle the case where no nodes where generated. Auto-generate that
+ // contains the updated state if we aren't generating sinks.
+ if (!Builder->BuildSinks && DstTmp3.size() == OldSize &&
+ !Builder->HasGeneratedNode)
+ MakeNode(DstTmp3, CE, Pred, state);
+ }
+ }
}
+
+ // Perform the post-condition check of the CallExpr.
+ CheckerVisit(CE, Dst, DstTmp3, false);
}
//===----------------------------------------------------------------------===//
@@ -1922,10 +1810,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
ExplodedNodeSet Src, DstTmp;
Src.Add(Pred);
- if (CheckerVisit(ME, DstTmp, Src, true)) {
- Dst.insert(DstTmp);
- return;
- }
+ CheckerVisit(ME, DstTmp, Src, true);
unsigned size = Dst.size();
@@ -1934,10 +1819,38 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
Pred = *DI;
bool RaisesException = false;
- if (ME->getReceiver()) {
+ if (const Expr *Receiver = ME->getReceiver()) {
+ const GRState *state = Pred->getState();
+
+ // Bifurcate the state into nil and non-nil ones.
+ DefinedOrUnknownSVal receiverVal =
+ cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
+
+ const GRState *notNilState, *nilState;
+ llvm::tie(notNilState, nilState) = state->Assume(receiverVal);
+
+ // There are three cases: can be nil or non-nil, must be nil, must be
+ // non-nil. We handle must be nil, and merge the rest two into non-nil.
+ if (nilState && !notNilState) {
+ CheckerEvalNilReceiver(ME, Dst, nilState, Pred);
+ return;
+ }
+
+ assert(notNilState);
+
// Check if the "raise" message was sent.
if (ME->getSelector() == RaiseSel)
RaisesException = true;
+
+ // Check if we raise an exception. For now treat these as sinks.
+ // Eventually we will want to handle exceptions properly.
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+ if (RaisesException)
+ Builder->BuildSinks = true;
+
+ // Dispatch to plug-in transfer function.
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
+ EvalObjCMessageExpr(Dst, ME, Pred, notNilState);
}
else {
@@ -1984,17 +1897,17 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
RaisesException = true; break;
}
}
- }
- // Check if we raise an exception. For now treat these as sinks. Eventually
- // we will want to handle exceptions properly.
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- if (RaisesException)
- Builder->BuildSinks = true;
+ // Check if we raise an exception. For now treat these as sinks.
+ // Eventually we will want to handle exceptions properly.
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+ if (RaisesException)
+ Builder->BuildSinks = true;
- // Dispatch to plug-in transfer function.
- SaveOr OldHasGen(Builder->HasGeneratedNode);
- EvalObjCMessageExpr(Dst, ME, Pred);
+ // Dispatch to plug-in transfer function.
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
+ EvalObjCMessageExpr(Dst, ME, Pred, Builder->GetState(Pred));
+ }
}
// Handle the case where no nodes where generated. Auto-generate that
@@ -2052,10 +1965,12 @@ void GRExprEngine::VisitCompoundLiteralExpr(CompoundLiteralExpr* CL,
for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) {
const GRState* state = GetState(*I);
SVal ILV = state->getSVal(ILE);
- state = state->bindCompoundLiteral(CL, ILV);
+ const LocationContext *LC = (*I)->getLocationContext();
+ state = state->bindCompoundLiteral(CL, LC, ILV);
- if (asLValue)
- MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL)));
+ if (asLValue) {
+ MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL, LC)));
+ }
else
MakeNode(Dst, CL, *I, state->BindExpr(CL, ILV));
}
diff --git a/lib/Analysis/GRExprEngineInternalChecks.h b/lib/Analysis/GRExprEngineInternalChecks.h
index 5b7a757..e2354ed 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.h
+++ b/lib/Analysis/GRExprEngineInternalChecks.h
@@ -37,5 +37,8 @@ void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng);
void RegisterUndefBranchChecker(GRExprEngine &Eng);
void RegisterUndefResultChecker(GRExprEngine &Eng);
+void RegisterNoReturnFunctionChecker(GRExprEngine &Eng);
+void RegisterBuiltinFunctionChecker(GRExprEngine &Eng);
+void RegisterOSAtomicChecker(GRExprEngine &Eng);
} // end clang namespace
#endif
diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp
index a56859d..7415fa5 100644
--- a/lib/Analysis/GRState.cpp
+++ b/lib/Analysis/GRState.cpp
@@ -312,10 +312,10 @@ bool GRState::scanReachableSymbols(const SVal *I, const SVal *E,
SymbolVisitor &visitor) const {
ScanReachableSymbols S(this, visitor);
for ( ; I != E; ++I) {
- if (S.scan(*I))
- return true;
+ if (!S.scan(*I))
+ return false;
}
- return false;
+ return true;
}
bool GRState::scanReachableSymbols(const MemRegion * const *I,
@@ -323,10 +323,10 @@ bool GRState::scanReachableSymbols(const MemRegion * const *I,
SymbolVisitor &visitor) const {
ScanReachableSymbols S(this, visitor);
for ( ; I != E; ++I) {
- if (S.scan(*I))
- return true;
+ if (!S.scan(*I))
+ return false;
}
- return false;
+ return true;
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp
index 204c7b3..2ed070a 100644
--- a/lib/Analysis/MallocChecker.cpp
+++ b/lib/Analysis/MallocChecker.cpp
@@ -22,10 +22,11 @@ using namespace clang;
namespace {
-struct RefState {
+class RefState {
enum Kind { Allocated, Released, Escaped } K;
const Stmt *S;
+public:
RefState(Kind k, const Stmt *s) : K(k), S(s) {}
bool isAllocated() const { return K == Allocated; }
@@ -51,19 +52,25 @@ class RegionState {};
class MallocChecker : public CheckerVisitor<MallocChecker> {
BuiltinBug *BT_DoubleFree;
BuiltinBug *BT_Leak;
- IdentifierInfo *II_malloc;
- IdentifierInfo *II_free;
+ IdentifierInfo *II_malloc, *II_free, *II_realloc;
public:
- MallocChecker() : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0) {}
+ MallocChecker()
+ : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0), II_realloc(0) {}
static void *getTag();
- void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper);
void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng);
void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
private:
void MallocMem(CheckerContext &C, const CallExpr *CE);
+ const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
+ const GRState *state);
void FreeMem(CheckerContext &C, const CallExpr *CE);
+ const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE,
+ const GRState *state);
+
+ void ReallocMem(CheckerContext &C, const CallExpr *CE);
};
} // end anonymous namespace
@@ -84,39 +91,71 @@ void *MallocChecker::getTag() {
return &x;
}
-void MallocChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
- const FunctionDecl *FD = CE->getDirectCallee();
+bool MallocChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) {
+ const GRState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = state->getSVal(Callee);
+
+ const FunctionDecl *FD = L.getAsFunctionDecl();
if (!FD)
- return;
+ return false;
ASTContext &Ctx = C.getASTContext();
if (!II_malloc)
II_malloc = &Ctx.Idents.get("malloc");
if (!II_free)
II_free = &Ctx.Idents.get("free");
+ if (!II_realloc)
+ II_realloc = &Ctx.Idents.get("realloc");
if (FD->getIdentifier() == II_malloc) {
MallocMem(C, CE);
- return;
+ return true;
}
if (FD->getIdentifier() == II_free) {
FreeMem(C, CE);
- return;
+ return true;
+ }
+
+ if (FD->getIdentifier() == II_realloc) {
+ ReallocMem(C, CE);
+ return true;
}
+
+ return false;
}
void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- SVal CallVal = state->getSVal(CE);
- SymbolRef Sym = CallVal.getAsLocSymbol();
+ const GRState *state = MallocMemAux(C, CE, C.getState());
+ C.addTransition(state);
+}
+
+const GRState *MallocChecker::MallocMemAux(CheckerContext &C,
+ const CallExpr *CE,
+ const GRState *state) {
+ unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ ValueManager &ValMgr = C.getValueManager();
+
+ SVal RetVal = ValMgr.getConjuredSymbolVal(NULL, CE, CE->getType(), Count);
+
+ state = state->BindExpr(CE, RetVal);
+
+ SymbolRef Sym = RetVal.getAsLocSymbol();
assert(Sym);
// Set the symbol's state to Allocated.
- C.addTransition(state->set<RegionState>(Sym, RefState::getAllocated(CE)));
+ return state->set<RegionState>(Sym, RefState::getAllocated(CE));
}
void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
+ const GRState *state = FreeMemAux(C, CE, C.getState());
+
+ if (state)
+ C.addTransition(state);
+}
+
+const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
+ const GRState *state) {
SVal ArgVal = state->getSVal(CE->getArg(0));
SymbolRef Sym = ArgVal.getAsLocSymbol();
assert(Sym);
@@ -136,13 +175,59 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
BT_DoubleFree->getDescription(), N);
C.EmitReport(R);
}
- return;
+ return NULL;
}
// Normal free.
- const GRState *FreedState
- = state->set<RegionState>(Sym, RefState::getReleased(CE));
- C.addTransition(FreedState);
+ return state->set<RegionState>(Sym, RefState::getReleased(CE));
+}
+
+void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) {
+ const GRState *state = C.getState();
+ const Expr *Arg0 = CE->getArg(0);
+ DefinedOrUnknownSVal Arg0Val=cast<DefinedOrUnknownSVal>(state->getSVal(Arg0));
+
+ ValueManager &ValMgr = C.getValueManager();
+ SValuator &SVator = C.getSValuator();
+
+ DefinedOrUnknownSVal PtrEQ = SVator.EvalEQ(state, Arg0Val, ValMgr.makeNull());
+
+ // If the ptr is NULL, the call is equivalent to malloc(size).
+ if (const GRState *stateEqual = state->Assume(PtrEQ, true)) {
+ // Hack: set the NULL symbolic region to released to suppress false warning.
+ // In the future we should add more states for allocated regions, e.g.,
+ // CheckedNull, CheckedNonNull.
+
+ SymbolRef Sym = Arg0Val.getAsLocSymbol();
+ if (Sym)
+ stateEqual = stateEqual->set<RegionState>(Sym, RefState::getReleased(CE));
+
+ const GRState *stateMalloc = MallocMemAux(C, CE, stateEqual);
+ C.addTransition(stateMalloc);
+ }
+
+ if (const GRState *stateNotEqual = state->Assume(PtrEQ, false)) {
+ const Expr *Arg1 = CE->getArg(1);
+ DefinedOrUnknownSVal Arg1Val =
+ cast<DefinedOrUnknownSVal>(stateNotEqual->getSVal(Arg1));
+ DefinedOrUnknownSVal SizeZero = SVator.EvalEQ(stateNotEqual, Arg1Val,
+ ValMgr.makeIntValWithPtrWidth(0, false));
+
+ if (const GRState *stateSizeZero = stateNotEqual->Assume(SizeZero, true)) {
+ const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero);
+ if (stateFree)
+ C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true));
+ }
+
+ if (const GRState *stateSizeNotZero=stateNotEqual->Assume(SizeZero,false)) {
+ const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero);
+ if (stateFree) {
+ // FIXME: We should copy the content of the original buffer.
+ const GRState *stateRealloc = MallocMemAux(C, CE, stateFree);
+ C.addTransition(stateRealloc);
+ }
+ }
+ }
}
void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp
index af8bd16..bc3a5b7 100644
--- a/lib/Analysis/MemRegion.cpp
+++ b/lib/Analysis/MemRegion.cpp
@@ -22,6 +22,110 @@
using namespace clang;
//===----------------------------------------------------------------------===//
+// MemRegion Construction.
+//===----------------------------------------------------------------------===//
+
+template<typename RegionTy> struct MemRegionManagerTrait;
+
+template <typename RegionTy, typename A1>
+RegionTy* MemRegionManager::getRegion(const A1 a1) {
+
+ const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion =
+ MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1);
+
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, a1, superRegion);
+ void* InsertPos;
+ RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+ InsertPos));
+
+ if (!R) {
+ R = (RegionTy*) A.Allocate<RegionTy>();
+ new (R) RegionTy(a1, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+template <typename RegionTy, typename A1>
+RegionTy* MemRegionManager::getSubRegion(const A1 a1,
+ const MemRegion *superRegion) {
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, a1, superRegion);
+ void* InsertPos;
+ RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+ InsertPos));
+
+ if (!R) {
+ R = (RegionTy*) A.Allocate<RegionTy>();
+ new (R) RegionTy(a1, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+template <typename RegionTy, typename A1, typename A2>
+RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) {
+
+ const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion =
+ MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1, a2);
+
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, a1, a2, superRegion);
+ void* InsertPos;
+ RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+ InsertPos));
+
+ if (!R) {
+ R = (RegionTy*) A.Allocate<RegionTy>();
+ new (R) RegionTy(a1, a2, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+template <typename RegionTy, typename A1, typename A2>
+RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2,
+ const MemRegion *superRegion) {
+
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, a1, a2, superRegion);
+ void* InsertPos;
+ RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+ InsertPos));
+
+ if (!R) {
+ R = (RegionTy*) A.Allocate<RegionTy>();
+ new (R) RegionTy(a1, a2, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+template <typename RegionTy, typename A1, typename A2, typename A3>
+RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, const A3 a3,
+ const MemRegion *superRegion) {
+
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, a1, a2, a3, superRegion);
+ void* InsertPos;
+ RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+ InsertPos));
+
+ if (!R) {
+ R = (RegionTy*) A.Allocate<RegionTy>();
+ new (R) RegionTy(a1, a2, a3, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+//===----------------------------------------------------------------------===//
// Object destruction.
//===----------------------------------------------------------------------===//
@@ -61,10 +165,24 @@ MemRegionManager* SubRegion::getMemRegionManager() const {
} while (1);
}
+const StackFrameContext *VarRegion::getStackFrame() const {
+ const StackSpaceRegion *SSR = dyn_cast<StackSpaceRegion>(getMemorySpace());
+ return SSR ? SSR->getStackFrame() : NULL;
+}
+
+//===----------------------------------------------------------------------===//
+// FoldingSet profiling.
+//===----------------------------------------------------------------------===//
+
void MemSpaceRegion::Profile(llvm::FoldingSetNodeID& ID) const {
ID.AddInteger((unsigned)getKind());
}
+void StackSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger((unsigned)getKind());
+ ID.AddPointer(getStackFrame());
+}
+
void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const StringLiteral* Str,
const MemRegion* superRegion) {
@@ -109,7 +227,7 @@ void DeclRegion::Profile(llvm::FoldingSetNodeID& ID) const {
}
void VarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- VarRegion::ProfileRegion(ID, getDecl(), LC, superRegion);
+ VarRegion::ProfileRegion(ID, getDecl(), superRegion);
}
void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym,
@@ -148,27 +266,29 @@ void FunctionTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
}
void BlockTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const BlockDecl *BD, CanQualType,
- const MemRegion*) {
+ const BlockDecl *BD, CanQualType,
+ const AnalysisContext *AC,
+ const MemRegion*) {
ID.AddInteger(MemRegion::BlockTextRegionKind);
ID.AddPointer(BD);
}
void BlockTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- BlockTextRegion::ProfileRegion(ID, BD, locTy, superRegion);
+ BlockTextRegion::ProfileRegion(ID, BD, locTy, AC, superRegion);
}
void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const BlockTextRegion *BC,
const LocationContext *LC,
- const MemRegion *) {
+ const MemRegion *sReg) {
ID.AddInteger(MemRegion::BlockDataRegionKind);
ID.AddPointer(BC);
ID.AddPointer(LC);
+ ID.AddPointer(sReg);
}
void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- BlockDataRegion::ProfileRegion(ID, BC, LC, NULL);
+ BlockDataRegion::ProfileRegion(ID, BC, LC, getSuperRegion());
}
//===----------------------------------------------------------------------===//
@@ -249,36 +369,58 @@ void RegionRawOffset::dumpToStream(llvm::raw_ostream& os) const {
// MemRegionManager methods.
//===----------------------------------------------------------------------===//
-MemSpaceRegion* MemRegionManager::LazyAllocate(MemSpaceRegion*& region) {
+template <typename REG>
+const REG *MemRegionManager::LazyAllocate(REG*& region) {
if (!region) {
- region = (MemSpaceRegion*) A.Allocate<MemSpaceRegion>();
- new (region) MemSpaceRegion(this);
+ region = (REG*) A.Allocate<REG>();
+ new (region) REG(this);
}
return region;
}
-MemSpaceRegion* MemRegionManager::getStackRegion() {
- return LazyAllocate(stack);
+template <typename REG, typename ARG>
+const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) {
+ if (!region) {
+ region = (REG*) A.Allocate<REG>();
+ new (region) REG(this, a);
+ }
+
+ return region;
}
-MemSpaceRegion* MemRegionManager::getStackArgumentsRegion() {
- return LazyAllocate(stackArguments);
+const StackLocalsSpaceRegion*
+MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) {
+ assert(STC);
+ if (STC == cachedStackLocalsFrame)
+ return cachedStackLocalsRegion;
+ cachedStackLocalsFrame = STC;
+ return LazyAllocate(cachedStackLocalsRegion, STC);
}
-MemSpaceRegion* MemRegionManager::getGlobalsRegion() {
+const StackArgumentsSpaceRegion *
+MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) {
+ assert(STC);
+ if (STC == cachedStackArgumentsFrame)
+ return cachedStackArgumentsRegion;
+
+ cachedStackArgumentsFrame = STC;
+ return LazyAllocate(cachedStackArgumentsRegion, STC);
+}
+
+const GlobalsSpaceRegion *MemRegionManager::getGlobalsRegion() {
return LazyAllocate(globals);
}
-MemSpaceRegion* MemRegionManager::getHeapRegion() {
+const HeapSpaceRegion *MemRegionManager::getHeapRegion() {
return LazyAllocate(heap);
}
-MemSpaceRegion* MemRegionManager::getUnknownRegion() {
+const MemSpaceRegion *MemRegionManager::getUnknownRegion() {
return LazyAllocate(unknown);
}
-MemSpaceRegion* MemRegionManager::getCodeRegion() {
+const MemSpaceRegion *MemRegionManager::getCodeRegion() {
return LazyAllocate(code);
}
@@ -286,40 +428,79 @@ MemSpaceRegion* MemRegionManager::getCodeRegion() {
// Constructing regions.
//===----------------------------------------------------------------------===//
-StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) {
- return getRegion<StringRegion>(Str);
+const StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) {
+ return getSubRegion<StringRegion>(Str, getGlobalsRegion());
}
-VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
- const LocationContext *LC) {
+const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
+ const LocationContext *LC) {
+ const MemRegion *sReg = 0;
- // FIXME: Once we implement scope handling, we will need to properly lookup
- // 'D' to the proper LocationContext. For now, just strip down to the
- // StackFrame.
- while (!isa<StackFrameContext>(LC))
- LC = LC->getParent();
+ if (D->hasLocalStorage()) {
+ // FIXME: Once we implement scope handling, we will need to properly lookup
+ // 'D' to the proper LocationContext.
+ const DeclContext *DC = D->getDeclContext();
+ const StackFrameContext *STC = LC->getStackFrameForDeclContext(DC);
- return getRegion<VarRegion>(D, LC);
+ if (!STC)
+ sReg = getUnknownRegion();
+ else {
+ sReg = isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)
+ ? static_cast<const MemRegion*>(getStackArgumentsRegion(STC))
+ : static_cast<const MemRegion*>(getStackLocalsRegion(STC));
+ }
+ }
+ else {
+ sReg = getGlobalsRegion();
+ }
+
+ return getSubRegion<VarRegion>(D, sReg);
}
-BlockDataRegion *MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
- const LocationContext *LC)
-{
- // FIXME: Once we implement scope handling, we will need to properly lookup
- // 'D' to the proper LocationContext. For now, just strip down to the
- // StackFrame.
- while (!isa<StackFrameContext>(LC))
- LC = LC->getParent();
+const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D,
+ const MemRegion *superR) {
+ return getSubRegion<VarRegion>(D, superR);
+}
+
+const BlockDataRegion *
+MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
+ const LocationContext *LC) {
+ const MemRegion *sReg = 0;
- return getSubRegion<BlockDataRegion>(BC, LC, getStackRegion());
+ if (LC) {
+ // FIXME: Once we implement scope handling, we want the parent region
+ // to be the scope.
+ const StackFrameContext *STC = LC->getCurrentStackFrame();
+ assert(STC);
+ sReg = getStackLocalsRegion(STC);
+ }
+ else {
+ // We allow 'LC' to be NULL for cases where want BlockDataRegions
+ // without context-sensitivity.
+ sReg = getUnknownRegion();
+ }
+
+ return getSubRegion<BlockDataRegion>(BC, LC, sReg);
}
-CompoundLiteralRegion*
-MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) {
- return getRegion<CompoundLiteralRegion>(CL);
+const CompoundLiteralRegion*
+MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL,
+ const LocationContext *LC) {
+
+ const MemRegion *sReg = 0;
+
+ if (CL->isFileScope())
+ sReg = getGlobalsRegion();
+ else {
+ const StackFrameContext *STC = LC->getCurrentStackFrame();
+ assert(STC);
+ sReg = getStackLocalsRegion(STC);
+ }
+
+ return getSubRegion<CompoundLiteralRegion>(CL, sReg);
}
-ElementRegion*
+const ElementRegion*
MemRegionManager::getElementRegion(QualType elementType, SVal Idx,
const MemRegion* superRegion,
ASTContext& Ctx){
@@ -342,41 +523,47 @@ MemRegionManager::getElementRegion(QualType elementType, SVal Idx,
return R;
}
-FunctionTextRegion *
+const FunctionTextRegion *
MemRegionManager::getFunctionTextRegion(const FunctionDecl *FD) {
- return getRegion<FunctionTextRegion>(FD);
+ return getSubRegion<FunctionTextRegion>(FD, getCodeRegion());
}
-BlockTextRegion *MemRegionManager::getBlockTextRegion(const BlockDecl *BD,
- CanQualType locTy) {
- return getRegion<BlockTextRegion>(BD, locTy);
+const BlockTextRegion *
+MemRegionManager::getBlockTextRegion(const BlockDecl *BD, CanQualType locTy,
+ AnalysisContext *AC) {
+ return getSubRegion<BlockTextRegion>(BD, locTy, AC, getCodeRegion());
}
/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
-SymbolicRegion* MemRegionManager::getSymbolicRegion(SymbolRef sym) {
- return getRegion<SymbolicRegion>(sym);
+const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) {
+ return getSubRegion<SymbolicRegion>(sym, getUnknownRegion());
}
-FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d,
- const MemRegion* superRegion) {
+const FieldRegion *
+MemRegionManager::getFieldRegion(const FieldDecl* d,
+ const MemRegion* superRegion){
return getSubRegion<FieldRegion>(d, superRegion);
}
-ObjCIvarRegion*
+const ObjCIvarRegion*
MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
const MemRegion* superRegion) {
return getSubRegion<ObjCIvarRegion>(d, superRegion);
}
-ObjCObjectRegion*
+const ObjCObjectRegion*
MemRegionManager::getObjCObjectRegion(const ObjCInterfaceDecl* d,
const MemRegion* superRegion) {
return getSubRegion<ObjCObjectRegion>(d, superRegion);
}
-AllocaRegion* MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt) {
- return getRegion<AllocaRegion>(E, cnt);
+const AllocaRegion*
+MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt,
+ const LocationContext *LC) {
+ const StackFrameContext *STC = LC->getCurrentStackFrame();
+ assert(STC);
+ return getSubRegion<AllocaRegion>(E, cnt, getStackLocalsRegion(STC));
}
const MemSpaceRegion *MemRegion::getMemorySpace() const {
@@ -392,52 +579,30 @@ const MemSpaceRegion *MemRegion::getMemorySpace() const {
}
bool MemRegion::hasStackStorage() const {
- if (const MemSpaceRegion *MS = getMemorySpace()) {
- MemRegionManager *Mgr = getMemRegionManager();
- return MS == Mgr->getStackRegion() || MS == Mgr->getStackArgumentsRegion();
- }
-
- return false;
+ return isa<StackSpaceRegion>(getMemorySpace());
}
bool MemRegion::hasHeapStorage() const {
- if (const MemSpaceRegion *MS = getMemorySpace())
- return MS == getMemRegionManager()->getHeapRegion();
-
- return false;
+ return isa<HeapSpaceRegion>(getMemorySpace());
}
bool MemRegion::hasHeapOrStackStorage() const {
- if (const MemSpaceRegion *MS = getMemorySpace()) {
- MemRegionManager *Mgr = getMemRegionManager();
- return MS == Mgr->getHeapRegion()
- || MS == Mgr->getStackRegion()
- || MS == Mgr->getStackArgumentsRegion();
- }
- return false;
+ const MemSpaceRegion *MS = getMemorySpace();
+ return isa<StackSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS);
}
bool MemRegion::hasGlobalsStorage() const {
- if (const MemSpaceRegion *MS = getMemorySpace())
- return MS == getMemRegionManager()->getGlobalsRegion();
-
- return false;
+ return isa<GlobalsSpaceRegion>(getMemorySpace());
}
bool MemRegion::hasParametersStorage() const {
- if (const MemSpaceRegion *MS = getMemorySpace())
- return MS == getMemRegionManager()->getStackArgumentsRegion();
-
- return false;
+ return isa<StackArgumentsSpaceRegion>(getMemorySpace());
}
bool MemRegion::hasGlobalsOrParametersStorage() const {
- if (const MemSpaceRegion *MS = getMemorySpace()) {
- MemRegionManager *Mgr = getMemRegionManager();
- return MS == Mgr->getGlobalsRegion()
- || MS == Mgr->getStackArgumentsRegion();
- }
- return false;
+ const MemSpaceRegion *MS = getMemorySpace();
+ return isa<StackArgumentsSpaceRegion>(MS) ||
+ isa<GlobalsSpaceRegion>(MS);
}
// getBaseRegion strips away all elements and fields, and get the base region
@@ -543,7 +708,7 @@ void BlockDataRegion::LazyInitializeReferencedVars() {
if (ReferencedVars)
return;
- AnalysisContext *AC = LC->getAnalysisContext();
+ AnalysisContext *AC = getCodeRegion()->getAnalysisContext();
AnalysisContext::referenced_decls_iterator I, E;
llvm::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl());
@@ -558,10 +723,25 @@ void BlockDataRegion::LazyInitializeReferencedVars() {
typedef BumpVector<const MemRegion*> VarVec;
VarVec *BV = (VarVec*) A.Allocate<VarVec>();
- new (BV) VarVec(BC, (E - I) / sizeof(*I));
+ new (BV) VarVec(BC, E - I);
- for ( ; I != E; ++I)
- BV->push_back(MemMgr.getVarRegion(*I, LC), BC);
+ for ( ; I != E; ++I) {
+ const VarDecl *VD = *I;
+ const VarRegion *VR = 0;
+
+ if (!VD->getAttr<BlocksAttr>())
+ VR = MemMgr.getVarRegion(VD, this);
+ else {
+ if (LC)
+ VR = MemMgr.getVarRegion(VD, LC);
+ else {
+ VR = MemMgr.getVarRegion(VD, MemMgr.getUnknownRegion());
+ }
+ }
+
+ assert(VR);
+ BV->push_back(VR, BC);
+ }
ReferencedVars = BV;
}
@@ -573,7 +753,8 @@ BlockDataRegion::referenced_vars_begin() const {
BumpVector<const MemRegion*> *Vec =
static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
- return Vec == (void*) 0x1 ? NULL : Vec->begin();
+ return BlockDataRegion::referenced_vars_iterator(Vec == (void*) 0x1 ?
+ NULL : Vec->begin());
}
BlockDataRegion::referenced_vars_iterator
@@ -583,5 +764,6 @@ BlockDataRegion::referenced_vars_end() const {
BumpVector<const MemRegion*> *Vec =
static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
- return Vec == (void*) 0x1 ? NULL : Vec->end();
+ return BlockDataRegion::referenced_vars_iterator(Vec == (void*) 0x1 ?
+ NULL : Vec->end());
}
diff --git a/lib/Analysis/NoReturnFunctionChecker.cpp b/lib/Analysis/NoReturnFunctionChecker.cpp
new file mode 100644
index 0000000..6806273
--- /dev/null
+++ b/lib/Analysis/NoReturnFunctionChecker.cpp
@@ -0,0 +1,80 @@
+//=== NoReturnFunctionChecker.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines NoReturnFunctionChecker, which evaluates functions that do not
+// return to the caller.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/Checker.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+
+namespace {
+
+class NoReturnFunctionChecker : public Checker {
+public:
+ static void *getTag() { static int tag = 0; return &tag; }
+ virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+
+}
+
+void clang::RegisterNoReturnFunctionChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new NoReturnFunctionChecker());
+}
+
+bool NoReturnFunctionChecker::EvalCallExpr(CheckerContext &C,
+ const CallExpr *CE) {
+ const GRState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = state->getSVal(Callee);
+ const FunctionDecl *FD = L.getAsFunctionDecl();
+ if (!FD)
+ return false;
+
+ bool BuildSinks = false;
+
+ if (FD->getAttr<NoReturnAttr>() || FD->getAttr<AnalyzerNoReturnAttr>())
+ BuildSinks = true;
+ else {
+ // HACK: Some functions are not marked noreturn, and don't return.
+ // Here are a few hardwired ones. If this takes too long, we can
+ // potentially cache these results.
+ using llvm::StringRef;
+ BuildSinks
+ = llvm::StringSwitch<bool>(StringRef(FD->getIdentifier()->getName()))
+ .Case("exit", true)
+ .Case("panic", true)
+ .Case("error", true)
+ .Case("Assert", true)
+ // FIXME: This is just a wrapper around throwing an exception.
+ // Eventually inter-procedural analysis should handle this easily.
+ .Case("ziperr", true)
+ .Case("assfail", true)
+ .Case("db_error", true)
+ .Case("__assert", true)
+ .Case("__assert_rtn", true)
+ .Case("__assert_fail", true)
+ .Case("dtrace_assfail", true)
+ .Case("yy_fatal_error", true)
+ .Case("_XCAssertionFailureHandler", true)
+ .Case("_DTAssertionFailureHandler", true)
+ .Case("_TSAssertionFailureHandler", true)
+ .Default(false);
+ }
+
+ if (!BuildSinks)
+ return false;
+
+ C.GenerateSink(CE);
+ return true;
+}
diff --git a/lib/Analysis/OSAtomicChecker.cpp b/lib/Analysis/OSAtomicChecker.cpp
new file mode 100644
index 0000000..5a89345
--- /dev/null
+++ b/lib/Analysis/OSAtomicChecker.cpp
@@ -0,0 +1,196 @@
+//=== OSAtomicChecker.cpp - OSAtomic functions evaluator --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker evaluates OSAtomic functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Basic/Builtins.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+
+namespace {
+
+class OSAtomicChecker : public Checker {
+public:
+ static void *getTag() { static int tag = 0; return &tag; }
+ virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
+
+private:
+ bool EvalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE);
+};
+
+}
+
+void clang::RegisterOSAtomicChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new OSAtomicChecker());
+}
+
+bool OSAtomicChecker::EvalCallExpr(CheckerContext &C,const CallExpr *CE) {
+ const GRState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = state->getSVal(Callee);
+
+ const FunctionDecl* FD = L.getAsFunctionDecl();
+ if (!FD)
+ return false;
+
+ const char *FName = FD->getNameAsCString();
+
+ // Check for compare and swap.
+ if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 ||
+ strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0)
+ return EvalOSAtomicCompareAndSwap(C, CE);
+
+ // FIXME: Other atomics.
+ return false;
+}
+
+bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C,
+ const CallExpr *CE) {
+ // Not enough arguments to match OSAtomicCompareAndSwap?
+ if (CE->getNumArgs() != 3)
+ return false;
+
+ ASTContext &Ctx = C.getASTContext();
+ const Expr *oldValueExpr = CE->getArg(0);
+ QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
+
+ const Expr *newValueExpr = CE->getArg(1);
+ QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType());
+
+ // Do the types of 'oldValue' and 'newValue' match?
+ if (oldValueType != newValueType)
+ return false;
+
+ const Expr *theValueExpr = CE->getArg(2);
+ const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>();
+
+ // theValueType not a pointer?
+ if (!theValueType)
+ return false;
+
+ QualType theValueTypePointee =
+ Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
+
+ // The pointee must match newValueType and oldValueType.
+ if (theValueTypePointee != newValueType)
+ return false;
+
+ static unsigned magic_load = 0;
+ static unsigned magic_store = 0;
+
+ const void *OSAtomicLoadTag = &magic_load;
+ const void *OSAtomicStoreTag = &magic_store;
+
+ // Load 'theValue'.
+ GRExprEngine &Engine = C.getEngine();
+ const GRState *state = C.getState();
+ ExplodedNodeSet Tmp;
+ SVal location = state->getSVal(theValueExpr);
+ // Here we should use the value type of the region as the load type.
+ QualType LoadTy;
+ if (const MemRegion *R = location.getAsRegion()) {
+ // We must be careful, as SymbolicRegions aren't typed.
+ const MemRegion *strippedR = R->StripCasts();
+ // FIXME: This isn't quite the right solution. One test case in 'test/Analysis/NSString.m'
+ // is giving the wrong result.
+ const TypedRegion *typedR =
+ isa<SymbolicRegion>(strippedR) ? cast<TypedRegion>(R) :
+ dyn_cast<TypedRegion>(strippedR);
+
+ if (typedR) {
+ LoadTy = typedR->getValueType(Ctx);
+ location = loc::MemRegionVal(typedR);
+ }
+ }
+ Engine.EvalLoad(Tmp, const_cast<Expr *>(theValueExpr), C.getPredecessor(),
+ state, location, OSAtomicLoadTag, LoadTy);
+
+ if (Tmp.empty()) {
+ // If no nodes were generated, other checkers must generated sinks. But
+ // since the builder state was restored, we set it manually to prevent
+ // auto transition.
+ // FIXME: there should be a better approach.
+ C.getNodeBuilder().BuildSinks = true;
+ return true;
+ }
+
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
+ I != E; ++I) {
+
+ ExplodedNode *N = *I;
+ const GRState *stateLoad = N->getState();
+ SVal theValueVal_untested = stateLoad->getSVal(theValueExpr);
+ SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
+
+ // FIXME: Issue an error.
+ if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
+ return false;
+ }
+
+ DefinedOrUnknownSVal theValueVal =
+ cast<DefinedOrUnknownSVal>(theValueVal_untested);
+ DefinedOrUnknownSVal oldValueVal =
+ cast<DefinedOrUnknownSVal>(oldValueVal_untested);
+
+ SValuator &SVator = Engine.getSValuator();
+
+ // Perform the comparison.
+ DefinedOrUnknownSVal Cmp = SVator.EvalEQ(stateLoad,theValueVal,oldValueVal);
+
+ const GRState *stateEqual = stateLoad->Assume(Cmp, true);
+
+ // Were they equal?
+ if (stateEqual) {
+ // Perform the store.
+ ExplodedNodeSet TmpStore;
+ SVal val = stateEqual->getSVal(newValueExpr);
+
+ // Handle implicit value casts.
+ if (const TypedRegion *R =
+ dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
+ llvm::tie(state, val) = SVator.EvalCast(val, state,R->getValueType(Ctx),
+ newValueExpr->getType());
+ }
+
+ Engine.EvalStore(TmpStore, NULL, const_cast<Expr *>(theValueExpr), N,
+ stateEqual, location, val, OSAtomicStoreTag);
+
+ if (TmpStore.empty()) {
+ // If no nodes were generated, other checkers must generated sinks. But
+ // since the builder state was restored, we set it manually to prevent
+ // auto transition.
+ // FIXME: there should be a better approach.
+ C.getNodeBuilder().BuildSinks = true;
+ return true;
+ }
+
+ // Now bind the result of the comparison.
+ for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
+ E2 = TmpStore.end(); I2 != E2; ++I2) {
+ ExplodedNode *predNew = *I2;
+ const GRState *stateNew = predNew->getState();
+ SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType());
+ C.GenerateNode(stateNew->BindExpr(CE, Res), predNew);
+ }
+ }
+
+ // Were they not equal?
+ if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) {
+ SVal Res = Engine.getValueManager().makeTruthVal(false, CE->getType());
+ C.GenerateNode(stateNotEqual->BindExpr(CE, Res), N);
+ }
+ }
+
+ return true;
+}
diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Analysis/PathDiagnostic.cpp
index 800496a..734570a 100644
--- a/lib/Analysis/PathDiagnostic.cpp
+++ b/lib/Analysis/PathDiagnostic.cpp
@@ -36,30 +36,16 @@ bool PathDiagnosticMacroPiece::containsEvent() const {
return false;
}
-static size_t GetNumCharsToLastNonPeriod(const char *s) {
- const char *start = s;
- const char *lastNonPeriod = 0;
-
- for ( ; *s != '\0' ; ++s)
- if (*s != '.') lastNonPeriod = s;
-
- if (!lastNonPeriod)
- return 0;
-
- return (lastNonPeriod - start) + 1;
-}
-
-static inline size_t GetNumCharsToLastNonPeriod(const std::string &s) {
- return s.empty () ? 0 : GetNumCharsToLastNonPeriod(&s[0]);
+static llvm::StringRef StripTrailingDots(llvm::StringRef s) {
+ for (llvm::StringRef::size_type i = s.size(); i != 0; --i)
+ if (s[i - 1] != '.')
+ return s.substr(0, i);
+ return "";
}
-PathDiagnosticPiece::PathDiagnosticPiece(const std::string& s,
+PathDiagnosticPiece::PathDiagnosticPiece(llvm::StringRef s,
Kind k, DisplayHint hint)
- : str(s, 0, GetNumCharsToLastNonPeriod(s)), kind(k), Hint(hint) {}
-
-PathDiagnosticPiece::PathDiagnosticPiece(const char* s, Kind k,
- DisplayHint hint)
- : str(s, GetNumCharsToLastNonPeriod(s)), kind(k), Hint(hint) {}
+ : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
: kind(k), Hint(hint) {}
@@ -89,20 +75,12 @@ void PathDiagnostic::resetPath(bool deletePieces) {
}
-PathDiagnostic::PathDiagnostic(const char* bugtype, const char* desc,
- const char* category)
- : Size(0),
- BugType(bugtype, GetNumCharsToLastNonPeriod(bugtype)),
- Desc(desc, GetNumCharsToLastNonPeriod(desc)),
- Category(category, GetNumCharsToLastNonPeriod(category)) {}
-
-PathDiagnostic::PathDiagnostic(const std::string& bugtype,
- const std::string& desc,
- const std::string& category)
+PathDiagnostic::PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc,
+ llvm::StringRef category)
: Size(0),
- BugType(bugtype, 0, GetNumCharsToLastNonPeriod(bugtype)),
- Desc(desc, 0, GetNumCharsToLastNonPeriod(desc)),
- Category(category, 0, GetNumCharsToLastNonPeriod(category)) {}
+ BugType(StripTrailingDots(bugtype)),
+ Desc(StripTrailingDots(desc)),
+ Category(StripTrailingDots(category)) {}
void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
const DiagnosticInfo &Info) {
@@ -126,8 +104,7 @@ void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
Info.FormatDiagnostic(StrC);
PathDiagnosticPiece *P =
- new PathDiagnosticEventPiece(Info.getLocation(),
- std::string(StrC.begin(), StrC.end()));
+ new PathDiagnosticEventPiece(Info.getLocation(), StrC.str());
for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
P->addRange(Info.getRange(i));
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index e645172..b5eeb1e 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -269,7 +269,15 @@ public:
const GRState *InvalidateRegion(const GRState *state, const MemRegion *R,
const Expr *E, unsigned Count,
- InvalidatedSymbols *IS);
+ InvalidatedSymbols *IS) {
+ return RegionStoreManager::InvalidateRegions(state, &R, &R+1, E, Count, IS);
+ }
+
+ const GRState *InvalidateRegions(const GRState *state,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End,
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS);
private:
void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R,
@@ -279,7 +287,9 @@ public:
const GRState *Bind(const GRState *state, Loc LV, SVal V);
const GRState *BindCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr* CL, SVal V);
+ const CompoundLiteralExpr* CL,
+ const LocationContext *LC,
+ SVal V);
const GRState *BindDecl(const GRState *ST, const VarRegion *VR,
SVal InitVal);
@@ -460,16 +470,14 @@ void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B,
B = RBFactory.Remove(B, R);
}
-const GRState *RegionStoreManager::InvalidateRegion(const GRState *state,
- const MemRegion *R,
- const Expr *Ex,
- unsigned Count,
- InvalidatedSymbols *IS) {
+const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
+ const MemRegion * const *I,
+ const MemRegion * const *E,
+ const Expr *Ex,
+ unsigned Count,
+ InvalidatedSymbols *IS) {
ASTContext& Ctx = StateMgr.getContext();
- // Strip away casts.
- R = R->StripCasts();
-
// Get the mapping of regions -> subregions.
llvm::OwningPtr<RegionStoreSubRegionMap>
SubRegions(getRegionStoreSubRegionMap(state->getStore()));
@@ -478,10 +486,14 @@ const GRState *RegionStoreManager::InvalidateRegion(const GRState *state,
llvm::DenseMap<const MemRegion *, unsigned> Visited;
llvm::SmallVector<const MemRegion *, 10> WorkList;
- WorkList.push_back(R);
+
+ for ( ; I != E; ++I) {
+ // Strip away casts.
+ WorkList.push_back((*I)->StripCasts());
+ }
while (!WorkList.empty()) {
- R = WorkList.back();
+ const MemRegion *R = WorkList.back();
WorkList.pop_back();
// Have we visited this region before?
@@ -512,6 +524,19 @@ const GRState *RegionStoreManager::InvalidateRegion(const GRState *state,
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
IS->insert(SR->getSymbol());
}
+
+ // BlockDataRegion? If so, invalidate captured variables that are passed
+ // by reference.
+ if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
+ for (BlockDataRegion::referenced_vars_iterator
+ I = BR->referenced_vars_begin(), E = BR->referenced_vars_end() ;
+ I != E; ++I) {
+ const VarRegion *VR = *I;
+ if (VR->getDecl()->getAttr<BlocksAttr>())
+ WorkList.push_back(VR);
+ }
+ continue;
+ }
// Handle the region itself.
if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R) ||
@@ -592,15 +617,6 @@ SVal RegionStoreManager::getLValueVar(const VarDecl *VD,
return loc::MemRegionVal(MRMgr.getVarRegion(VD, LC));
}
-/// getLValueCompoundLiteral - Returns an SVal representing the lvalue
-/// of a compound literal. Within RegionStore a compound literal
-/// has an associated region, and the lvalue of the compound literal
-/// is the lvalue of that region.
-SVal
-RegionStoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL) {
- return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL));
-}
-
SVal RegionStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) {
return getLValueFieldOrIvar(D, Base);
}
@@ -707,7 +723,12 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
const MemRegion *R) {
switch (R->getKind()) {
- case MemRegion::MemSpaceRegionKind:
+ case MemRegion::GenericMemSpaceRegionKind:
+ case MemRegion::StackLocalsSpaceRegionKind:
+ case MemRegion::StackArgumentsSpaceRegionKind:
+ case MemRegion::HeapSpaceRegionKind:
+ case MemRegion::GlobalsSpaceRegionKind:
+ case MemRegion::UnknownSpaceRegionKind:
assert(0 && "Cannot index into a MemSpace");
return UnknownVal();
@@ -752,13 +773,6 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
// essentially are arrays of size 1.
return ValMgr.makeIntVal(1, false);
}
-
- case MemRegion::BEG_DECL_REGIONS:
- case MemRegion::END_DECL_REGIONS:
- case MemRegion::BEG_TYPED_REGIONS:
- case MemRegion::END_TYPED_REGIONS:
- assert(0 && "Infeasible region");
- return UnknownVal();
}
assert(0 && "Unreachable");
@@ -797,9 +811,8 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array) {
T = AT->getElementType();
SVal ZeroIdx = ValMgr.makeZeroArrayIndex();
- ElementRegion* ER = MRMgr.getElementRegion(T, ZeroIdx, ArrayR, getContext());
-
- return loc::MemRegionVal(ER);
+ return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, ArrayR,
+ getContext()));
}
//===----------------------------------------------------------------------===//
@@ -864,16 +877,14 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
// Technically this can happen if people do funny things with casts.
return UnknownVal();
- case MemRegion::MemSpaceRegionKind:
+ case MemRegion::GenericMemSpaceRegionKind:
+ case MemRegion::StackLocalsSpaceRegionKind:
+ case MemRegion::StackArgumentsSpaceRegionKind:
+ case MemRegion::HeapSpaceRegionKind:
+ case MemRegion::GlobalsSpaceRegionKind:
+ case MemRegion::UnknownSpaceRegionKind:
assert(0 && "Cannot perform pointer arithmetic on a MemSpace");
return UnknownVal();
-
- case MemRegion::BEG_DECL_REGIONS:
- case MemRegion::END_DECL_REGIONS:
- case MemRegion::BEG_TYPED_REGIONS:
- case MemRegion::END_TYPED_REGIONS:
- assert(0 && "Infeasible region");
- return UnknownVal();
}
SVal Idx = ER->getIndex();
@@ -1283,7 +1294,8 @@ SVal RegionStoreManager::RetrieveVar(const GRState *state,
// Lazily derive a value for the VarRegion.
const VarDecl *VD = R->getDecl();
- if (R->hasGlobalsOrParametersStorage())
+ if (R->hasGlobalsOrParametersStorage() ||
+ isa<UnknownSpaceRegion>(R->getMemorySpace()))
return ValMgr.getRegionValueSymbolValOrUnknown(R, VD->getType());
return UndefinedVal();
@@ -1440,11 +1452,11 @@ const GRState *RegionStoreManager::BindDecl(const GRState *ST,
// FIXME: this method should be merged into Bind().
const GRState *
RegionStoreManager::BindCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr* CL,
+ const CompoundLiteralExpr *CL,
+ const LocationContext *LC,
SVal V) {
-
- CompoundLiteralRegion* R = MRMgr.getCompoundLiteralRegion(CL);
- return Bind(state, loc::MemRegionVal(R), V);
+ return Bind(state, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)),
+ V);
}
const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state,
@@ -1497,8 +1509,8 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
break;
SVal Idx = ValMgr.makeArrayIndex(i);
- ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R,
- getContext());
+ const ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R,
+ getContext());
SVal V = ValMgr.makeIntVal(str[j], sizeof(char)*8, true);
state = Bind(state, loc::MemRegionVal(ER), V);
@@ -1526,7 +1538,7 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
break;
SVal Idx = ValMgr.makeArrayIndex(i);
- ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext());
+ const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext());
if (CAT->getElementType()->isStructureType())
state = BindStruct(state, ER, *VI);
@@ -1677,7 +1689,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
IntermediateVisited.insert(R);
if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
- if (SymReaper.isLive(Loc, VR->getDecl()))
+ if (SymReaper.isLive(Loc, VR))
WorkList.push_back(std::make_pair(&state, VR));
continue;
}
@@ -1753,14 +1765,16 @@ tryAgain:
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
SymReaper.markLive(SymR->getSymbol());
- // For BlockDataRegions, enqueue all VarRegions for that are referenced
+ // For BlockDataRegions, enqueue the VarRegions for variables marked
+ // with __block (passed-by-reference).
// via BlockDeclRefExprs.
if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(R)) {
for (BlockDataRegion::referenced_vars_iterator
RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end();
- RI != RE; ++RI)
- WorkList.push_back(std::make_pair(state_N, *RI));
-
+ RI != RE; ++RI) {
+ if ((*RI)->getDecl()->getAttr<BlocksAttr>())
+ WorkList.push_back(std::make_pair(state_N, *RI));
+ }
// No possible data bindings on a BlockDataRegion. Continue to the
// next region in the worklist.
continue;
@@ -1846,8 +1860,7 @@ GRState const *RegionStoreManager::EnterStackFrame(GRState const *state,
// Copy the arg expression value to the arg variables.
for (; AI != AE; ++AI, ++PI) {
SVal ArgVal = state->getSVal(*AI);
- MemRegion *R = MRMgr.getVarRegion(*PI, frame);
- state = Bind(state, ValMgr.makeLoc(R), ArgVal);
+ state = Bind(state, ValMgr.makeLoc(MRMgr.getVarRegion(*PI, frame)), ArgVal);
}
return state;
diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp
index 2fd573c..e6ff6e5 100644
--- a/lib/Analysis/Store.cpp
+++ b/lib/Analysis/Store.cpp
@@ -77,11 +77,12 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
// Process region cast according to the kind of the region being cast.
switch (R->getKind()) {
- case MemRegion::BEG_TYPED_REGIONS:
- case MemRegion::MemSpaceRegionKind:
- case MemRegion::BEG_DECL_REGIONS:
- case MemRegion::END_DECL_REGIONS:
- case MemRegion::END_TYPED_REGIONS: {
+ case MemRegion::GenericMemSpaceRegionKind:
+ case MemRegion::StackLocalsSpaceRegionKind:
+ case MemRegion::StackArgumentsSpaceRegionKind:
+ case MemRegion::HeapSpaceRegionKind:
+ case MemRegion::UnknownSpaceRegionKind:
+ case MemRegion::GlobalsSpaceRegionKind: {
assert(0 && "Invalid region cast");
break;
}
@@ -199,9 +200,33 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
QualType castTy) {
if (castTy.isNull())
return V;
-
+
assert(ValMgr.getContext().hasSameUnqualifiedType(castTy,
R->getValueType(ValMgr.getContext())));
return V;
}
+const GRState *StoreManager::InvalidateRegions(const GRState *state,
+ const MemRegion * const *I,
+ const MemRegion * const *End,
+ const Expr *E,
+ unsigned Count,
+ InvalidatedSymbols *IS) {
+ for ( ; I != End ; ++I)
+ state = InvalidateRegion(state, *I, E, Count, IS);
+
+ return state;
+}
+
+//===----------------------------------------------------------------------===//
+// Common getLValueXXX methods.
+//===----------------------------------------------------------------------===//
+
+/// getLValueCompoundLiteral - Returns an SVal representing the lvalue
+/// of a compound literal. Within RegionStore a compound literal
+/// has an associated region, and the lvalue of the compound literal
+/// is the lvalue of that region.
+SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL,
+ const LocationContext *LC) {
+ return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
+}
diff --git a/lib/Analysis/SymbolManager.cpp b/lib/Analysis/SymbolManager.cpp
index 22e1101..3fe36b0 100644
--- a/lib/Analysis/SymbolManager.cpp
+++ b/lib/Analysis/SymbolManager.cpp
@@ -220,4 +220,9 @@ bool SymbolReaper::isLive(SymbolRef sym) {
return isa<SymbolRegionValue>(sym);
}
+bool SymbolReaper::isLive(const Stmt *Loc, const VarRegion *VR) const {
+ const StackFrameContext *SFC = VR->getStackFrame();
+ return SFC == CurrentStackFrame ? Liveness.isLive(Loc, VR->getDecl()) : true;
+}
+
SymbolVisitor::~SymbolVisitor() {}
diff --git a/lib/Analysis/ValueManager.cpp b/lib/Analysis/ValueManager.cpp
index 22a8211..d091373 100644
--- a/lib/Analysis/ValueManager.cpp
+++ b/lib/Analysis/ValueManager.cpp
@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/ValueManager.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
using namespace clang;
using namespace llvm;
@@ -138,15 +139,15 @@ ValueManager::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
}
DefinedSVal ValueManager::getFunctionPointer(const FunctionDecl* FD) {
- CodeTextRegion *R = MemMgr.getFunctionTextRegion(FD);
- return loc::MemRegionVal(R);
+ return loc::MemRegionVal(MemMgr.getFunctionTextRegion(FD));
}
DefinedSVal ValueManager::getBlockPointer(const BlockDecl *D,
CanQualType locTy,
const LocationContext *LC) {
- BlockTextRegion *BC = MemMgr.getBlockTextRegion(D, locTy);
- BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, LC);
+ const BlockTextRegion *BC =
+ MemMgr.getBlockTextRegion(D, locTy, LC->getAnalysisContext());
+ const BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, LC);
return loc::MemRegionVal(BD);
}
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index fbc7313..8d0d813 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -163,7 +163,7 @@ namespace clang {
return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
}
- unsigned getOrCreateDiagID(Diagnostic::Level L, const char *Message,
+ unsigned getOrCreateDiagID(Diagnostic::Level L, llvm::StringRef Message,
Diagnostic &Diags) {
DiagDesc D(L, Message);
// Check to see if it already exists.
@@ -210,7 +210,7 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
ErrorOccurred = false;
FatalErrorOccurred = false;
NumDiagnostics = 0;
-
+
NumErrors = 0;
CustomDiagInfo = 0;
CurDiagID = ~0U;
@@ -246,7 +246,7 @@ bool Diagnostic::popMappings() {
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
/// and level. If this is the first request for this diagnosic, it is
/// registered and created, otherwise the existing ID is returned.
-unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) {
+unsigned Diagnostic::getCustomDiagID(Level L, llvm::StringRef Message) {
if (CustomDiagInfo == 0)
CustomDiagInfo = new diag::CustomDiagInfo();
return CustomDiagInfo->getOrCreateDiagID(L, Message, *this);
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index ee4309d..434ff39 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -147,6 +147,12 @@ FileManager::FileManager()
FileManager::~FileManager() {
delete &UniqueDirs;
delete &UniqueFiles;
+ for (llvm::SmallVectorImpl<FileEntry *>::iterator
+ V = VirtualFileEntries.begin(),
+ VEnd = VirtualFileEntries.end();
+ V != VEnd;
+ ++V)
+ delete *V;
}
void FileManager::addStatCache(StatSysCallCache *statCache, bool AtBeginning) {
@@ -184,6 +190,30 @@ void FileManager::removeStatCache(StatSysCallCache *statCache) {
assert(false && "Stat cache not found for removal");
}
+/// \brief Retrieve the directory that the given file name resides in.
+static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
+ const char *NameStart,
+ const char *NameEnd) {
+ // Figure out what directory it is in. If the string contains a / in it,
+ // strip off everything after it.
+ // FIXME: this logic should be in sys::Path.
+ const char *SlashPos = NameEnd-1;
+ while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0]))
+ --SlashPos;
+ // Ignore duplicate //'s.
+ while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1]))
+ --SlashPos;
+
+ if (SlashPos < NameStart) {
+ // Use the current directory if file has no path component.
+ const char *Name = ".";
+ return FileMgr.getDirectory(Name, Name+1);
+ } else if (SlashPos == NameEnd-1)
+ return 0; // If filename ends with a /, it's a directory.
+ else
+ return FileMgr.getDirectory(NameStart, SlashPos);
+}
+
/// getDirectory - Lookup, cache, and verify the specified directory. This
/// returns null if the directory doesn't exist.
///
@@ -252,33 +282,16 @@ const FileEntry *FileManager::getFile(const char *NameStart,
// By default, initialize it to invalid.
NamedFileEnt.setValue(NON_EXISTENT_FILE);
- // Figure out what directory it is in. If the string contains a / in it,
- // strip off everything after it.
- // FIXME: this logic should be in sys::Path.
- const char *SlashPos = NameEnd-1;
- while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0]))
- --SlashPos;
- // Ignore duplicate //'s.
- while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1]))
- --SlashPos;
-
- const DirectoryEntry *DirInfo;
- if (SlashPos < NameStart) {
- // Use the current directory if file has no path component.
- const char *Name = ".";
- DirInfo = getDirectory(Name, Name+1);
- } else if (SlashPos == NameEnd-1)
- return 0; // If filename ends with a /, it's a directory.
- else
- DirInfo = getDirectory(NameStart, SlashPos);
-
- if (DirInfo == 0) // Directory doesn't exist, file can't exist.
- return 0;
// Get the null-terminated file name as stored as the key of the
// FileEntries map.
const char *InterndFileName = NamedFileEnt.getKeyData();
+ const DirectoryEntry *DirInfo
+ = getDirectoryFromFile(*this, NameStart, NameEnd);
+ if (DirInfo == 0) // Directory doesn't exist, file can't exist.
+ return 0;
+
// FIXME: Use the directory info to prune this, before doing the stat syscall.
// FIXME: This will reduce the # syscalls.
@@ -312,6 +325,44 @@ const FileEntry *FileManager::getFile(const char *NameStart,
return &UFE;
}
+const FileEntry *
+FileManager::getVirtualFile(const llvm::StringRef &Filename,
+ off_t Size, time_t ModificationTime) {
+ const char *NameStart = Filename.begin(), *NameEnd = Filename.end();
+
+ ++NumFileLookups;
+
+ // See if there is already an entry in the map.
+ llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
+ FileEntries.GetOrCreateValue(NameStart, NameEnd);
+
+ // See if there is already an entry in the map.
+ if (NamedFileEnt.getValue())
+ return NamedFileEnt.getValue() == NON_EXISTENT_FILE
+ ? 0 : NamedFileEnt.getValue();
+
+ ++NumFileCacheMisses;
+
+ // By default, initialize it to invalid.
+ NamedFileEnt.setValue(NON_EXISTENT_FILE);
+
+ const DirectoryEntry *DirInfo
+ = getDirectoryFromFile(*this, NameStart, NameEnd);
+ if (DirInfo == 0) // Directory doesn't exist, file can't exist.
+ return 0;
+
+ FileEntry *UFE = new FileEntry();
+ VirtualFileEntries.push_back(UFE);
+ NamedFileEnt.setValue(UFE);
+
+ UFE->Name = NamedFileEnt.getKeyData();
+ UFE->Size = Size;
+ UFE->ModTime = ModificationTime;
+ UFE->Dir = DirInfo;
+ UFE->UID = NextFileUID++;
+ return UFE;
+}
+
void FileManager::PrintStats() const {
llvm::errs() << "\n*** File Manager Stats:\n";
llvm::errs() << UniqueFiles.size() << " files found, "
@@ -327,17 +378,16 @@ void FileManager::PrintStats() const {
int MemorizeStatCalls::stat(const char *path, struct stat *buf) {
int result = StatSysCallCache::stat(path, buf);
- if (result != 0) {
- // Cache failed 'stat' results.
- struct stat empty;
- memset(&empty, 0, sizeof(empty));
- StatCalls[path] = StatResult(result, empty);
- }
- else if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) {
- // Cache file 'stat' results and directories with absolutely
- // paths.
+ // Do not cache failed stats, it is easy to construct common inconsistent
+ // situations if we do, and they are not important for PCH performance (which
+ // currently only needs the stats to construct the initial FileManager
+ // entries).
+ if (result != 0)
+ return result;
+
+ // Cache file 'stat' results and directories with absolutely paths.
+ if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute())
StatCalls[path] = StatResult(result, *buf);
- }
return result;
}
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index a85bef0..354bf7b 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -41,64 +41,42 @@ unsigned ContentCache::getSizeBytesMapped() const {
/// getSize - Returns the size of the content encapsulated by this ContentCache.
/// This can be the size of the source file or the size of an arbitrary
/// scratch buffer. If the ContentCache encapsulates a source file, that
-/// file is not lazily brought in from disk to satisfy this query unless it
-/// needs to be truncated due to a truncateAt() call.
+/// file is not lazily brought in from disk to satisfy this query.
unsigned ContentCache::getSize() const {
return Buffer ? Buffer->getBufferSize() : Entry->getSize();
}
-const llvm::MemoryBuffer *ContentCache::getBuffer() const {
- // Lazily create the Buffer for ContentCaches that wrap files.
- if (!Buffer && Entry) {
- // FIXME: Should we support a way to not have to do this check over
- // and over if we cannot open the file?
- Buffer = MemoryBuffer::getFile(Entry->getName(), 0, Entry->getSize());
- if (isTruncated())
- const_cast<ContentCache *>(this)->truncateAt(TruncateAtLine,
- TruncateAtColumn);
- }
- return Buffer;
+void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) {
+ assert(B != Buffer);
+
+ delete Buffer;
+ Buffer = B;
}
-void ContentCache::truncateAt(unsigned Line, unsigned Column) {
- TruncateAtLine = Line;
- TruncateAtColumn = Column;
-
- if (!isTruncated() || !Buffer)
- return;
-
- // Find the byte position of the truncation point.
- const char *Position = Buffer->getBufferStart();
- for (unsigned Line = 1; Line < TruncateAtLine; ++Line) {
- for (; *Position; ++Position) {
- if (*Position != '\r' && *Position != '\n')
- continue;
-
- // Eat \r\n or \n\r as a single line.
- if ((Position[1] == '\r' || Position[1] == '\n') &&
- Position[0] != Position[1])
- ++Position;
- ++Position;
- break;
+const llvm::MemoryBuffer *ContentCache::getBuffer(std::string *ErrorStr) const {
+ // Lazily create the Buffer for ContentCaches that wrap files.
+ if (!Buffer && Entry) {
+ Buffer = MemoryBuffer::getFile(Entry->getName(), ErrorStr,Entry->getSize());
+
+ // If we were unable to open the file, then we are in an inconsistent
+ // situation where the content cache referenced a file which no longer
+ // exists. Most likely, we were using a stat cache with an invalid entry but
+ // the file could also have been removed during processing. Since we can't
+ // really deal with this situation, just create an empty buffer.
+ //
+ // FIXME: This is definitely not ideal, but our immediate clients can't
+ // currently handle returning a null entry here. Ideally we should detect
+ // that we are in an inconsistent situation and error out as quickly as
+ // possible.
+ if (!Buffer) {
+ const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n");
+ Buffer = MemoryBuffer::getNewMemBuffer(Entry->getSize(), "<invalid>");
+ char *Ptr = const_cast<char*>(Buffer->getBufferStart());
+ for (unsigned i = 0, e = Entry->getSize(); i != e; ++i)
+ Ptr[i] = FillStr[i % FillStr.size()];
}
}
-
- for (unsigned Column = 1; Column < TruncateAtColumn; ++Column, ++Position) {
- if (!*Position)
- break;
-
- if (*Position == '\t')
- Column += 7;
- }
-
- // Truncate the buffer.
- if (Position != Buffer->getBufferEnd()) {
- MemoryBuffer *TruncatedBuffer
- = MemoryBuffer::getMemBufferCopy(Buffer->getBufferStart(), Position,
- Buffer->getBufferIdentifier());
- delete Buffer;
- Buffer = TruncatedBuffer;
- }
+ return Buffer;
}
unsigned LineTableInfo::getLineTableFilenameID(const char *Ptr, unsigned Len) {
@@ -332,16 +310,6 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) {
EntryAlign = std::max(8U, EntryAlign);
Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign);
new (Entry) ContentCache(FileEnt);
-
- if (FileEnt == TruncateFile) {
- // If we had queued up a file truncation request, perform the truncation
- // now.
- Entry->truncateAt(TruncateAtLine, TruncateAtColumn);
- TruncateFile = 0;
- TruncateAtLine = 0;
- TruncateAtColumn = 0;
- }
-
return Entry;
}
@@ -413,8 +381,6 @@ FileID SourceManager::createFileID(const ContentCache *File,
= SLocEntry::get(Offset, FileInfo::get(IncludePos, File, FileCharacter));
SLocEntryLoaded[PreallocatedID] = true;
FileID FID = FileID::get(PreallocatedID);
- if (File->FirstFID.isInvalid())
- File->FirstFID = FID;
return LastFileIDLookup = FID;
}
@@ -428,8 +394,6 @@ FileID SourceManager::createFileID(const ContentCache *File,
// Set LastFileIDLookup to the newly created file. The next getFileID call is
// almost guaranteed to be from that file.
FileID FID = FileID::get(SLocEntryTable.size()-1);
- if (File->FirstFID.isInvalid())
- File->FirstFID = FID;
return LastFileIDLookup = FID;
}
@@ -461,6 +425,25 @@ SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc,
return SourceLocation::getMacroLoc(NextOffset-(TokLength+1));
}
+const llvm::MemoryBuffer *
+SourceManager::getMemoryBufferForFile(const FileEntry *File) {
+ const SrcMgr::ContentCache *IR = getOrCreateContentCache(File);
+ if (IR == 0)
+ return 0;
+
+ return IR->getBuffer();
+}
+
+bool SourceManager::overrideFileContents(const FileEntry *SourceFile,
+ const llvm::MemoryBuffer *Buffer) {
+ const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile);
+ if (IR == 0)
+ return true;
+
+ const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer);
+ return false;
+}
+
/// getBufferData - Return a pointer to the start and end of the source buffer
/// data for the specified FileID.
std::pair<const char*, const char*>
@@ -1007,8 +990,33 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
if (i < Col-1)
return SourceLocation();
- return getLocForStartOfFile(Content->FirstFID).
- getFileLocWithOffset(FilePos + Col - 1);
+ // Find the first file ID that corresponds to the given file.
+ FileID FirstFID;
+
+ // First, check the main file ID, since it is common to look for a
+ // location in the main file.
+ if (!MainFileID.isInvalid()) {
+ const SLocEntry &MainSLoc = getSLocEntry(MainFileID);
+ if (MainSLoc.isFile() && MainSLoc.getFile().getContentCache() == Content)
+ FirstFID = MainFileID;
+ }
+
+ if (FirstFID.isInvalid()) {
+ // The location we're looking for isn't in the main file; look
+ // through all of the source locations.
+ for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) {
+ const SLocEntry &SLoc = getSLocEntry(I);
+ if (SLoc.isFile() && SLoc.getFile().getContentCache() == Content) {
+ FirstFID = FileID::get(I);
+ break;
+ }
+ }
+ }
+
+ if (FirstFID.isInvalid())
+ return SourceLocation();
+
+ return getLocForStartOfFile(FirstFID).getFileLocWithOffset(FilePos + Col - 1);
}
/// \brief Determines the order of 2 source locations in the translation unit.
@@ -1087,52 +1095,20 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
return LastResForBeforeTUCheck = LOffs.second < I->second;
}
- // No common ancestor.
- // Now we are getting into murky waters. Most probably this is because one
- // location is in the predefines buffer.
-
- const FileEntry *LEntry =
- getSLocEntry(LOffs.first).getFile().getContentCache()->Entry;
- const FileEntry *REntry =
- getSLocEntry(ROffs.first).getFile().getContentCache()->Entry;
-
- // If the locations are in two memory buffers we give up, we can't answer
- // which one should be considered first.
- // FIXME: Should there be a way to "include" memory buffers in the translation
- // unit ?
- assert((LEntry != 0 || REntry != 0) && "Locations in memory buffers.");
- (void) REntry;
-
- // Consider the memory buffer as coming before the file in the translation
- // unit.
- if (LEntry == 0)
- return LastResForBeforeTUCheck = true;
- else {
- assert(REntry == 0 && "Locations in not #included files ?");
- return LastResForBeforeTUCheck = false;
- }
-}
+ // There is no common ancestor, most probably because one location is in the
+ // predefines buffer.
+ //
+ // FIXME: We should rearrange the external interface so this simply never
+ // happens; it can't conceptually happen. Also see PR5662.
-void SourceManager::truncateFileAt(const FileEntry *Entry, unsigned Line,
- unsigned Column) {
- llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>::iterator FI
- = FileInfos.find(Entry);
- if (FI != FileInfos.end()) {
- FI->second->truncateAt(Line, Column);
- return;
- }
-
- // We cannot perform the truncation until we actually see the file, so
- // save the truncation information.
- assert(TruncateFile == 0 && "Can't queue up multiple file truncations!");
- TruncateFile = Entry;
- TruncateAtLine = Line;
- TruncateAtColumn = Column;
-}
+ // If exactly one location is a memory buffer, assume it preceeds the other.
+ bool LIsMB = !getSLocEntry(LOffs.first).getFile().getContentCache()->Entry;
+ bool RIsMB = !getSLocEntry(ROffs.first).getFile().getContentCache()->Entry;
+ if (LIsMB != RIsMB)
+ return LastResForBeforeTUCheck = LIsMB;
-/// \brief Determine whether this file was truncated.
-bool SourceManager::isTruncatedFile(FileID FID) const {
- return getSLocEntry(FID).getFile().getContentCache()->isTruncated();
+ // Otherwise, just assume FileIDs were created in order.
+ return LastResForBeforeTUCheck = (LOffs.first < ROffs.first);
}
/// PrintStats - Print statistics to stderr.
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 2df779c..9e44db0 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -296,7 +296,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
++helpersize;
continue;
} else
- E = new (getContext()) DeclRefExpr (cast<NamedDecl>(VD),
+ E = new (getContext()) DeclRefExpr (VD,
VD->getType(),
SourceLocation());
}
@@ -1136,36 +1136,38 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
}
llvm::Constant *BlockFunction::BuildbyrefCopyHelper(const llvm::Type *T,
- int flag, unsigned Align) {
- // All alignments below that of pointer alignment collpase down to just
+ int Flag, unsigned Align) {
+ // All alignments below that of pointer alignment collapse down to just
// pointer alignment, as we always have at least that much alignment to begin
// with.
Align /= unsigned(CGF.Target.getPointerAlign(0)/8);
+
// As an optimization, we only generate a single function of each kind we
// might need. We need a different one for each alignment and for each
// setting of flags. We mix Align and flag to get the kind.
- uint64_t kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + flag;
- llvm::Constant *& Entry = CGM.AssignCache[kind];
+ uint64_t Kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + Flag;
+ llvm::Constant *&Entry = CGM.AssignCache[Kind];
if (Entry)
return Entry;
- return Entry=CodeGenFunction(CGM).GeneratebyrefCopyHelperFunction(T, flag);
+ return Entry = CodeGenFunction(CGM).GeneratebyrefCopyHelperFunction(T, Flag);
}
llvm::Constant *BlockFunction::BuildbyrefDestroyHelper(const llvm::Type *T,
- int flag,
+ int Flag,
unsigned Align) {
// All alignments below that of pointer alignment collpase down to just
// pointer alignment, as we always have at least that much alignment to begin
// with.
Align /= unsigned(CGF.Target.getPointerAlign(0)/8);
+
// As an optimization, we only generate a single function of each kind we
// might need. We need a different one for each alignment and for each
// setting of flags. We mix Align and flag to get the kind.
- uint64_t kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + flag;
- llvm::Constant *& Entry = CGM.DestroyCache[kind];
+ uint64_t Kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + Flag;
+ llvm::Constant *&Entry = CGM.DestroyCache[Kind];
if (Entry)
return Entry;
- return Entry=CodeGenFunction(CGM).GeneratebyrefDestroyHelperFunction(T, flag);
+ return Entry=CodeGenFunction(CGM).GeneratebyrefDestroyHelperFunction(T, Flag);
}
llvm::Value *BlockFunction::getBlockObjectDispose() {
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index be4c27c..c704432 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -204,7 +204,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Builder.CreateCall(F, ArgValue, "tmp"));
}
case Builtin::BI__builtin_object_size: {
-#if 1
// We pass this builtin onto the optimizer so that it can
// figure out the object size in more complex cases.
const llvm::Type *ResType[] = {
@@ -214,15 +213,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Builder.CreateCall2(F,
EmitScalarExpr(E->getArg(0)),
EmitScalarExpr(E->getArg(1))));
-#else
- // FIXME: Remove after testing.
- llvm::APSInt TypeArg = E->getArg(1)->EvaluateAsInt(CGM.getContext());
- const llvm::Type *ResType = ConvertType(E->getType());
- // bool UseSubObject = TypeArg.getZExtValue() & 1;
- bool UseMinimum = TypeArg.getZExtValue() & 2;
- return RValue::get(
- llvm::ConstantInt::get(ResType, UseMinimum ? 0 : -1LL));
-#endif
}
case Builtin::BI__builtin_prefetch: {
Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
@@ -815,13 +805,44 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Ops[0] = Builder.CreateBitCast(Ops[0], PtrTy);
return Builder.CreateStore(Ops[1], Ops[0]);
}
- case X86::BI__builtin_ia32_palignr128:
case X86::BI__builtin_ia32_palignr: {
- Function *F = CGM.getIntrinsic(BuiltinID == X86::BI__builtin_ia32_palignr128 ?
- Intrinsic::x86_ssse3_palign_r_128 :
- Intrinsic::x86_ssse3_palign_r);
+ Function *F = CGM.getIntrinsic(Intrinsic::x86_ssse3_palign_r);
return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size());
}
+ case X86::BI__builtin_ia32_palignr128: {
+ unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
+
+ // If palignr is shifting the pair of input vectors less than 17 bytes,
+ // emit a shuffle instruction.
+ if (shiftVal <= 16) {
+ const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext);
+
+ llvm::SmallVector<llvm::Constant*, 16> Indices;
+ for (unsigned i = 0; i != 16; ++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 16 but less
+ // than 32 bytes, emit a logical right shift of the destination.
+ if (shiftVal < 32) {
+ const llvm::Type *EltTy = llvm::Type::getInt64Ty(VMContext);
+ const llvm::Type *VecTy = llvm::VectorType::get(EltTy, 2);
+ const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext);
+
+ Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast");
+ Ops[1] = llvm::ConstantInt::get(IntTy, (shiftVal-16) * 8);
+
+ // create i32 constant
+ llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_psrl_dq);
+ 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()));
+ }
}
}
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 34d1c8d..0d11be2 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -26,168 +26,6 @@
using namespace clang;
using namespace CodeGen;
-void
-CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
- llvm::Constant *DeclPtr) {
- const llvm::Type *Int8PtrTy =
- llvm::Type::getInt8Ty(VMContext)->getPointerTo();
-
- std::vector<const llvm::Type *> Params;
- Params.push_back(Int8PtrTy);
-
- // Get the destructor function type
- const llvm::Type *DtorFnTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false);
- DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy);
-
- Params.clear();
- Params.push_back(DtorFnTy);
- Params.push_back(Int8PtrTy);
- Params.push_back(Int8PtrTy);
-
- // Get the __cxa_atexit function type
- // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d );
- const llvm::FunctionType *AtExitFnTy =
- llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false);
-
- llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy,
- "__cxa_atexit");
-
- llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy,
- "__dso_handle");
- llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy),
- llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy),
- llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) };
- Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args));
-}
-
-void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
- llvm::Constant *DeclPtr) {
- assert(D.hasGlobalStorage() &&
- "VarDecl must have global storage!");
-
- const Expr *Init = D.getInit();
- QualType T = D.getType();
- bool isVolatile = getContext().getCanonicalType(T).isVolatileQualified();
-
- if (T->isReferenceType()) {
- ErrorUnsupported(Init, "global variable that binds to a reference");
- } else if (!hasAggregateLLVMType(T)) {
- llvm::Value *V = EmitScalarExpr(Init);
- EmitStoreOfScalar(V, DeclPtr, isVolatile, T);
- } else if (T->isAnyComplexType()) {
- EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile);
- } else {
- EmitAggExpr(Init, DeclPtr, isVolatile);
- // Avoid generating destructor(s) for initialized objects.
- if (!isa<CXXConstructExpr>(Init))
- return;
- const ConstantArrayType *Array = getContext().getAsConstantArrayType(T);
- if (Array)
- T = getContext().getBaseElementType(Array);
-
- if (const RecordType *RT = T->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (!RD->hasTrivialDestructor()) {
- llvm::Constant *DtorFn;
- if (Array) {
- DtorFn = CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(
- RD->getDestructor(getContext()),
- Array, DeclPtr);
- DeclPtr =
- llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext));
- }
- else
- DtorFn = CGM.GetAddrOfCXXDestructor(RD->getDestructor(getContext()),
- Dtor_Complete);
- EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr);
- }
- }
- }
-}
-
-void
-CodeGenModule::EmitCXXGlobalInitFunc() {
- if (CXXGlobalInits.empty())
- return;
-
- const llvm::FunctionType *FTy
- = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- false);
-
- // Create our global initialization function.
- // FIXME: Should this be tweakable by targets?
- llvm::Function *Fn =
- llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
- "__cxx_global_initialization", &TheModule);
-
- CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
- &CXXGlobalInits[0],
- CXXGlobalInits.size());
- AddGlobalCtor(Fn);
-}
-
-void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
- const VarDecl **Decls,
- unsigned NumDecls) {
- StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
- SourceLocation());
-
- for (unsigned i = 0; i != NumDecls; ++i) {
- const VarDecl *D = Decls[i];
-
- llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
- EmitCXXGlobalVarDeclInit(*D, DeclPtr);
- }
- FinishFunction();
-}
-
-void
-CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
- llvm::GlobalVariable *GV) {
- // FIXME: This should use __cxa_guard_{acquire,release}?
-
- assert(!getContext().getLangOptions().ThreadsafeStatics &&
- "thread safe statics are currently not supported!");
-
- llvm::SmallString<256> GuardVName;
- CGM.getMangleContext().mangleGuardVariable(&D, GuardVName);
-
- // Create the guard variable.
- llvm::GlobalValue *GuardV =
- new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext),
- false, GV->getLinkage(),
- llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)),
- GuardVName.str());
-
- // Load the first byte of the guard variable.
- const llvm::Type *PtrTy
- = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
- llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy),
- "tmp");
-
- // Compare it against 0.
- llvm::Value *nullValue
- = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext));
- llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool");
-
- llvm::BasicBlock *InitBlock = createBasicBlock("init");
- llvm::BasicBlock *EndBlock = createBasicBlock("init.end");
-
- // If the guard variable is 0, jump to the initializer code.
- Builder.CreateCondBr(ICmp, InitBlock, EndBlock);
-
- EmitBlock(InitBlock);
-
- EmitCXXGlobalVarDeclInit(D, GV);
-
- Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext),
- 1),
- Builder.CreateBitCast(GuardV, PtrTy));
-
- EmitBlock(EndBlock);
-}
-
RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
llvm::Value *Callee,
llvm::Value *This,
@@ -241,10 +79,10 @@ static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) {
}
RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
- if (isa<BinaryOperator>(CE->getCallee()))
+ if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens()))
return EmitCXXMemberPointerCallExpr(CE);
- const MemberExpr *ME = cast<MemberExpr>(CE->getCallee());
+ const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens());
const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
if (MD->isStatic()) {
@@ -307,7 +145,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
RValue
CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E) {
- const BinaryOperator *BO = cast<BinaryOperator>(E->getCallee());
+ const BinaryOperator *BO =
+ cast<BinaryOperator>(E->getCallee()->IgnoreParens());
const Expr *BaseExpr = BO->getLHS();
const Expr *MemFnExpr = BO->getRHS();
@@ -519,7 +358,7 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
// C++ [class.temporary]p4:
// There are two contexts in which temporaries are destroyed at a different
- // point than the end of the full- expression. The first context is when a
+ // point than the end of the full-expression. The first context is when a
// default constructor is called to initialize an element of an array.
// If the constructor has one or more default arguments, the destruction of
// every temporary created in a default argument expression is sequenced
@@ -558,8 +397,9 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
assert(CA && "Do we support VLA for destruction ?");
uint64_t ElementCount = getContext().getConstantArrayElementCount(CA);
- llvm::Value* ElementCountPtr =
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), ElementCount);
+
+ const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
+ llvm::Value* ElementCountPtr = llvm::ConstantInt::get(SizeLTy, ElementCount);
EmitCXXAggrDestructorCall(D, ElementCountPtr, This);
}
@@ -569,13 +409,14 @@ void
CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
llvm::Value *UpperCount,
llvm::Value *This) {
- llvm::Value *One = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- 1);
+ const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
+ llvm::Value *One = llvm::ConstantInt::get(SizeLTy, 1);
+
// Create a temporary for the loop index and initialize it with count of
// array elements.
- llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
- "loop.index");
- // Index = ElementCount;
+ llvm::Value *IndexPtr = CreateTempAlloca(SizeLTy, "loop.index");
+
+ // Store the number of elements in the index pointer.
Builder.CreateStore(UpperCount, IndexPtr);
// Start the loop with a block that tests the condition.
@@ -589,7 +430,7 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
// Generate: if (loop-index != 0 fall to the loop body,
// otherwise, go to the block after the for-loop.
llvm::Value* zeroConstant =
- llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
+ llvm::Constant::getNullValue(SizeLTy);
llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant,
"isne");
@@ -626,7 +467,6 @@ llvm::Constant *
CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
const ArrayType *Array,
llvm::Value *This) {
- static int UniqueCount;
FunctionArgList Args;
ImplicitParamDecl *Dst =
ImplicitParamDecl::Create(getContext(), 0,
@@ -635,16 +475,15 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
Args.push_back(std::make_pair(Dst, Dst->getType()));
llvm::SmallString<16> Name;
- llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueCount);
+ llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount);
QualType R = getContext().VoidTy;
const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args);
const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
- Name.c_str(),
+ Name.str(),
&CGM.getModule());
- IdentifierInfo *II
- = &CGM.getContext().Idents.get(Name.c_str());
+ IdentifierInfo *II = &CGM.getContext().Idents.get(Name.str());
FunctionDecl *FD = FunctionDecl::Create(getContext(),
getContext().getTranslationUnitDecl(),
SourceLocation(), II, R, 0,
@@ -691,21 +530,29 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
EmitCXXMemberCall(D, Callee, This, ArgBeg, ArgEnd);
}
-void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *D,
+void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
CXXDtorType Type,
llvm::Value *This) {
- if (D->isVirtual()) {
- const llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(D),
- /*isVariadic=*/false);
+ llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
+
+ CallArgList Args;
+
+ // Push the this ptr.
+ Args.push_back(std::make_pair(RValue::get(This),
+ DD->getThisType(getContext())));
+
+ // Add a VTT parameter if necessary.
+ // FIXME: This should not be a dummy null parameter!
+ if (Type == Dtor_Base && DD->getParent()->getNumVBases() != 0) {
+ QualType T = getContext().getPointerType(getContext().VoidPtrTy);
- llvm::Value *Callee = BuildVirtualCall(D, Dtor_Deleting, This, Ty);
- EmitCXXMemberCall(D, Callee, This, 0, 0);
- return;
+ Args.push_back(std::make_pair(RValue::get(CGM.EmitNullConstant(T)), T));
}
- llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(D, Type);
- EmitCXXMemberCall(D, Callee, This, 0, 0);
+ // FIXME: We should try to share this code with EmitCXXMemberCall.
+
+ QualType ResultType = DD->getType()->getAs<FunctionType>()->getResultType();
+ EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, Args, DD);
}
void
@@ -793,9 +640,9 @@ const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D,
void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) {
if (D->isVirtual())
- EmitGlobalDefinition(GlobalDecl(D, Dtor_Deleting));
- EmitGlobalDefinition(GlobalDecl(D, Dtor_Complete));
- EmitGlobalDefinition(GlobalDecl(D, Dtor_Base));
+ EmitGlobal(GlobalDecl(D, Dtor_Deleting));
+ EmitGlobal(GlobalDecl(D, Dtor_Complete));
+ EmitGlobal(GlobalDecl(D, Dtor_Base));
}
void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D,
@@ -829,10 +676,10 @@ const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D,
}
llvm::Constant *
-CodeGenFunction::GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD,
+CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
bool Extern,
const ThunkAdjustment &ThisAdjustment) {
- return GenerateCovariantThunk(Fn, MD, Extern,
+ return GenerateCovariantThunk(Fn, GD, Extern,
CovariantThunkAdjustment(ThisAdjustment,
ThunkAdjustment()));
}
@@ -875,8 +722,9 @@ CodeGenFunction::DynamicTypeAdjust(llvm::Value *V,
llvm::Constant *
CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
- const CXXMethodDecl *MD, bool Extern,
+ GlobalDecl GD, bool Extern,
const CovariantThunkAdjustment &Adjustment) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
FunctionArgList Args;
@@ -906,7 +754,8 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
const llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
FPT->isVariadic());
- llvm::Value *Callee = CGM.GetAddrOfFunction(MD, Ty);
+ llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty);
+
CallArgList CallArgs;
bool ShouldAdjustReturnPointer = true;
@@ -922,7 +771,7 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
CovariantThunkAdjustment(ThunkAdjustment(),
Adjustment.ReturnAdjustment);
- Callee = CGM.BuildCovariantThunk(MD, Extern, ReturnAdjustment);
+ Callee = CGM.BuildCovariantThunk(GD, Extern, ReturnAdjustment);
Callee = Builder.CreateBitCast(Callee, OrigTy);
ShouldAdjustReturnPointer = false;
@@ -938,7 +787,8 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
QualType ArgType = D->getType();
// llvm::Value *Arg = CGF.GetAddrOfLocalVar(Dst);
- Expr *Arg = new (getContext()) DeclRefExpr(D, ArgType, SourceLocation());
+ Expr *Arg = new (getContext()) DeclRefExpr(D, ArgType.getNonReferenceType(),
+ SourceLocation());
CallArgs.push_back(std::make_pair(EmitCallArg(Arg, ArgType), ArgType));
}
@@ -983,11 +833,117 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
}
llvm::Constant *
-CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern,
+CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
+ const ThunkAdjustment &ThisAdjustment) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ // Compute mangled name
+ llvm::SmallString<256> OutName;
+ if (const CXXDestructorDecl* DD = dyn_cast<CXXDestructorDecl>(MD))
+ getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), ThisAdjustment,
+ OutName);
+ else
+ getMangleContext().mangleThunk(MD, ThisAdjustment, OutName);
+ OutName += '\0';
+ const char* Name = UniqueMangledName(OutName.begin(), OutName.end());
+
+ // Get function for mangled name
+ const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
+ return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl());
+}
+
+llvm::Constant *
+CodeGenModule::GetAddrOfCovariantThunk(GlobalDecl GD,
+ const CovariantThunkAdjustment &Adjustment) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ // Compute mangled name
+ llvm::SmallString<256> OutName;
+ getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName);
+ OutName += '\0';
+ const char* Name = UniqueMangledName(OutName.begin(), OutName.end());
+
+ // Get function for mangled name
+ const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
+ return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl());
+}
+
+void CodeGenModule::BuildThunksForVirtual(GlobalDecl GD) {
+ CGVtableInfo::AdjustmentVectorTy *AdjPtr = getVtableInfo().getAdjustments(GD);
+ if (!AdjPtr)
+ return;
+ CGVtableInfo::AdjustmentVectorTy &Adj = *AdjPtr;
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ for (unsigned i = 0; i < Adj.size(); i++) {
+ GlobalDecl OGD = Adj[i].first;
+ const CXXMethodDecl *OMD = cast<CXXMethodDecl>(OGD.getDecl());
+ QualType nc_oret = OMD->getType()->getAs<FunctionType>()->getResultType();
+ CanQualType oret = getContext().getCanonicalType(nc_oret);
+ QualType nc_ret = MD->getType()->getAs<FunctionType>()->getResultType();
+ CanQualType ret = getContext().getCanonicalType(nc_ret);
+ ThunkAdjustment ReturnAdjustment;
+ if (oret != ret) {
+ QualType qD = nc_ret->getPointeeType();
+ QualType qB = nc_oret->getPointeeType();
+ CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
+ CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
+ ReturnAdjustment = ComputeThunkAdjustment(D, B);
+ }
+ ThunkAdjustment ThisAdjustment = Adj[i].second;
+ bool Extern = !cast<CXXRecordDecl>(OMD->getDeclContext())->isInAnonymousNamespace();
+ if (!ReturnAdjustment.isEmpty() || !ThisAdjustment.isEmpty()) {
+ CovariantThunkAdjustment CoAdj(ThisAdjustment, ReturnAdjustment);
+ llvm::Constant *FnConst;
+ if (!ReturnAdjustment.isEmpty())
+ FnConst = GetAddrOfCovariantThunk(GD, CoAdj);
+ else
+ FnConst = GetAddrOfThunk(GD, ThisAdjustment);
+ if (!isa<llvm::Function>(FnConst)) {
+ llvm::Constant *SubExpr =
+ cast<llvm::ConstantExpr>(FnConst)->getOperand(0);
+ llvm::Function *OldFn = cast<llvm::Function>(SubExpr);
+ std::string Name = OldFn->getNameStr();
+ GlobalDeclMap.erase(UniqueMangledName(Name.data(),
+ Name.data() + Name.size() + 1));
+ llvm::Constant *NewFnConst;
+ if (!ReturnAdjustment.isEmpty())
+ NewFnConst = GetAddrOfCovariantThunk(GD, CoAdj);
+ else
+ NewFnConst = GetAddrOfThunk(GD, ThisAdjustment);
+ llvm::Function *NewFn = cast<llvm::Function>(NewFnConst);
+ NewFn->takeName(OldFn);
+ llvm::Constant *NewPtrForOldDecl =
+ llvm::ConstantExpr::getBitCast(NewFn, OldFn->getType());
+ OldFn->replaceAllUsesWith(NewPtrForOldDecl);
+ OldFn->eraseFromParent();
+ FnConst = NewFn;
+ }
+ llvm::Function *Fn = cast<llvm::Function>(FnConst);
+ if (Fn->isDeclaration()) {
+ llvm::GlobalVariable::LinkageTypes linktype;
+ linktype = llvm::GlobalValue::WeakAnyLinkage;
+ if (!Extern)
+ linktype = llvm::GlobalValue::InternalLinkage;
+ Fn->setLinkage(linktype);
+ if (!Features.Exceptions && !Features.ObjCNonFragileABI)
+ Fn->addFnAttr(llvm::Attribute::NoUnwind);
+ Fn->setAlignment(2);
+ CodeGenFunction(*this).GenerateCovariantThunk(Fn, GD, Extern, CoAdj);
+ }
+ }
+ }
+}
+
+llvm::Constant *
+CodeGenModule::BuildThunk(GlobalDecl GD, bool Extern,
const ThunkAdjustment &ThisAdjustment) {
-
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
llvm::SmallString<256> OutName;
- getMangleContext().mangleThunk(MD, ThisAdjustment, OutName);
+ if (const CXXDestructorDecl *D = dyn_cast<CXXDestructorDecl>(MD)) {
+ getMangleContext().mangleCXXDtorThunk(D, GD.getDtorType(), ThisAdjustment,
+ OutName);
+ } else
+ getMangleContext().mangleThunk(MD, ThisAdjustment, OutName);
llvm::GlobalVariable::LinkageTypes linktype;
linktype = llvm::GlobalValue::WeakAnyLinkage;
@@ -1001,14 +957,15 @@ CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern,
llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(),
&getModule());
- CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, ThisAdjustment);
+ CodeGenFunction(*this).GenerateThunk(Fn, GD, Extern, ThisAdjustment);
llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
return m;
}
llvm::Constant *
-CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern,
+CodeGenModule::BuildCovariantThunk(const GlobalDecl &GD, bool Extern,
const CovariantThunkAdjustment &Adjustment) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
llvm::SmallString<256> OutName;
getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName);
llvm::GlobalVariable::LinkageTypes linktype;
@@ -1453,6 +1410,8 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType());
}
}
+
+ InitializeVtablePtrs(ClassDecl);
FinishFunction();
}
@@ -1537,8 +1496,16 @@ void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD,
// Do a built-in assignment of scalar data members.
LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
- RValue RVRHS = EmitLoadOfLValue(RHS, FieldType);
- EmitStoreThroughLValue(RVRHS, LHS, FieldType);
+ 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;
@@ -1666,8 +1633,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
const CXXRecordDecl *ClassDecl = CD->getParent();
// FIXME: Add vbase initialization
- llvm::Value *LoadOfThis = 0;
-
+
for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(),
E = CD->init_end();
B != E; ++B) {
@@ -1686,18 +1652,28 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
PopCXXTemporary();
}
- // Initialize the vtable pointer
- if (ClassDecl->isDynamicClass()) {
- if (!LoadOfThis)
- LoadOfThis = LoadCXXThis();
- llvm::Value *VtableField;
- llvm::Type *Ptr8Ty, *PtrPtr8Ty;
- Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
- PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0);
- VtableField = Builder.CreateBitCast(LoadOfThis, PtrPtr8Ty);
- llvm::Value *vtable = CGM.getVtableInfo().getVtable(ClassDecl);
- Builder.CreateStore(vtable, VtableField);
- }
+ InitializeVtablePtrs(ClassDecl);
+}
+
+void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) {
+ if (!ClassDecl->isDynamicClass())
+ return;
+
+ // Initialize the vtable pointer.
+ // FIXME: This needs to initialize secondary vtable pointers too.
+ llvm::Value *ThisPtr = LoadCXXThis();
+
+ llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl);
+ uint64_t AddressPoint = CGM.getVtableInfo().getVtableAddressPoint(ClassDecl);
+
+ llvm::Value *VtableAddressPoint =
+ Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint);
+
+ llvm::Value *VtableField =
+ Builder.CreateBitCast(ThisPtr,
+ VtableAddressPoint->getType()->getPointerTo());
+
+ Builder.CreateStore(VtableAddressPoint, VtableField);
}
/// EmitDtorEpilogue - Emit all code that comes at the end of class's
@@ -1808,9 +1784,12 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
}
// If we have a deleting destructor, emit a call to the delete operator.
- if (DtorType == Dtor_Deleting)
+ if (DtorType == Dtor_Deleting) {
+ assert(DD->getOperatorDelete() &&
+ "operator delete missing - EmitDtorEpilogue");
EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(),
getContext().getTagDeclType(ClassDecl));
+ }
}
void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor,
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index decc73c..4856f54 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -561,6 +561,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const ABIArgInfo &AI = it->info;
unsigned Attributes = 0;
+ if (ParamType.isRestrictQualified())
+ Attributes |= llvm::Attribute::NoAlias;
+
switch (AI.getKind()) {
case ABIArgInfo::Coerce:
break;
@@ -764,7 +767,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
ComplexPairTy RT = LoadComplexFromAddr(ReturnValue, false);
StoreComplexToAddr(RT, CurFn->arg_begin(), false);
} else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
- EmitAggregateCopy(CurFn->arg_begin(), ReturnValue, RetTy);
+ // Do nothing; aggregrates get evaluated directly into the destination.
} else {
EmitStoreOfScalar(Builder.CreateLoad(ReturnValue), CurFn->arg_begin(),
false, RetTy);
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index b3c2b98..fd2afe7 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -112,6 +112,42 @@ static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
return NonVirtualOffset;
}
+// FIXME: This probably belongs in CGVtable, but it relies on
+// the static function ComputeNonVirtualBaseClassOffset, so we should make that
+// a CodeGenModule member function as well.
+ThunkAdjustment
+CodeGenModule::ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/false,
+ /*RecordPaths=*/true, /*DetectVirtual=*/false);
+ if (!const_cast<CXXRecordDecl *>(ClassDecl)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
+ assert(false && "Class must be derived from the passed in base class!");
+ return ThunkAdjustment();
+ }
+
+ unsigned Start = 0;
+ uint64_t VirtualOffset = 0;
+
+ const CXXBasePath &Path = Paths.front();
+ 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());
+ }
+ }
+ if (VBase)
+ VirtualOffset =
+ getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl);
+
+ uint64_t Offset =
+ ComputeNonVirtualBaseClassOffset(getContext(), Paths, Start);
+ return ThunkAdjustment(Offset, VirtualOffset);
+}
+
llvm::Value *
CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
const CXXRecordDecl *ClassDecl,
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 317da7e..2238c89 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -35,8 +35,8 @@
using namespace clang;
using namespace clang::CodeGen;
-CGDebugInfo::CGDebugInfo(CodeGenModule *m)
- : M(m), isMainCompileUnitCreated(false), DebugFactory(M->getModule()),
+CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
+ : CGM(CGM), isMainCompileUnitCreated(false), DebugFactory(CGM.getModule()),
BlockLiteralGenericSet(false) {
}
@@ -46,7 +46,7 @@ CGDebugInfo::~CGDebugInfo() {
void CGDebugInfo::setLocation(SourceLocation Loc) {
if (Loc.isValid())
- CurLoc = M->getContext().getSourceManager().getInstantiationLoc(Loc);
+ CurLoc = CGM.getContext().getSourceManager().getInstantiationLoc(Loc);
}
/// getContext - Get context info for the decl.
@@ -70,7 +70,7 @@ llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl,
llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
// Get source file information.
const char *FileName = "<unknown>";
- SourceManager &SM = M->getContext().getSourceManager();
+ SourceManager &SM = CGM.getContext().getSourceManager();
unsigned FID = 0;
if (Loc.isValid()) {
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
@@ -84,18 +84,14 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
// Get absolute path name.
llvm::sys::Path AbsFileName(FileName);
- if (!AbsFileName.isAbsolute()) {
- llvm::sys::Path tmp = llvm::sys::Path::GetCurrentDirectory();
- tmp.appendComponent(FileName);
- AbsFileName = tmp;
- }
+ AbsFileName.makeAbsolute();
// See if thie compile unit is representing main source file. Each source
// file has corresponding compile unit. There is only one main source
// file at a time.
bool isMain = false;
- const LangOptions &LO = M->getLangOptions();
- const CodeGenOptions &CGO = M->getCodeGenOpts();
+ const LangOptions &LO = CGM.getLangOptions();
+ const CodeGenOptions &CGO = CGM.getCodeGenOpts();
if (isMainCompileUnitCreated == false) {
if (!CGO.MainFileName.empty()) {
if (AbsFileName.getLast() == CGO.MainFileName)
@@ -122,7 +118,7 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
LangTag = llvm::dwarf::DW_LANG_C89;
}
- std::string Producer =
+ const char *Producer =
#ifdef CLANG_VENDOR
CLANG_VENDOR
#endif
@@ -137,9 +133,9 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
// Create new compile unit.
return Unit = DebugFactory.CreateCompileUnit(LangTag,
- AbsFileName.getLast().c_str(),
- AbsFileName.getDirname().c_str(),
- Producer.c_str(), isMain,
+ AbsFileName.getLast(),
+ AbsFileName.getDirname(),
+ Producer, isMain,
isOptimized, Flags, RuntimeVers);
}
@@ -170,13 +166,13 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT,
case BuiltinType::Double: Encoding = llvm::dwarf::DW_ATE_float; break;
}
// Bit size, align and offset of the type.
- uint64_t Size = M->getContext().getTypeSize(BT);
- uint64_t Align = M->getContext().getTypeAlign(BT);
+ uint64_t Size = CGM.getContext().getTypeSize(BT);
+ uint64_t Align = CGM.getContext().getTypeAlign(BT);
uint64_t Offset = 0;
llvm::DIType DbgTy =
DebugFactory.CreateBasicType(Unit,
- BT->getName(M->getContext().getLangOptions()),
+ BT->getName(CGM.getContext().getLangOptions()),
Unit, 0, Size, Align,
Offset, /*flags*/ 0, Encoding);
return DbgTy;
@@ -189,8 +185,8 @@ llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty,
if (Ty->isComplexIntegerType())
Encoding = llvm::dwarf::DW_ATE_lo_user;
- uint64_t Size = M->getContext().getTypeSize(Ty);
- uint64_t Align = M->getContext().getTypeAlign(Ty);
+ uint64_t Size = CGM.getContext().getTypeSize(Ty);
+ uint64_t Align = CGM.getContext().getTypeAlign(Ty);
uint64_t Offset = 0;
llvm::DIType DbgTy =
@@ -262,8 +258,8 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
// Size is always the size of a pointer. We can't use getTypeSize here
// because that does not return the correct value for references.
uint64_t Size =
- M->getContext().Target.getPointerWidth(PointeeTy.getAddressSpace());
- uint64_t Align = M->getContext().getTypeAlign(Ty);
+ CGM.getContext().Target.getPointerWidth(PointeeTy.getAddressSpace());
+ uint64_t Align = CGM.getContext().getTypeAlign(Ty);
return
DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(),
@@ -291,10 +287,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
llvm::DIType EltTy, DescTy;
FieldOffset = 0;
- FType = M->getContext().UnsignedLongTy;
+ FType = CGM.getContext().UnsignedLongTy;
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"reserved", DefUnit,
0, FieldSize, FieldAlign,
@@ -302,10 +298,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = M->getContext().UnsignedLongTy;
+ FType = CGM.getContext().UnsignedLongTy;
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"Size", DefUnit,
0, FieldSize, FieldAlign,
@@ -323,18 +319,18 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
llvm::DIType(), Elements);
// Bit size, align and offset of the type.
- uint64_t Size = M->getContext().getTypeSize(Ty);
- uint64_t Align = M->getContext().getTypeAlign(Ty);
+ uint64_t Size = CGM.getContext().getTypeSize(Ty);
+ uint64_t Align = CGM.getContext().getTypeAlign(Ty);
DescTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type,
Unit, "", llvm::DICompileUnit(),
0, Size, Align, 0, 0, EltTy);
FieldOffset = 0;
- FType = M->getContext().getPointerType(M->getContext().VoidTy);
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__isa", DefUnit,
0, FieldSize, FieldAlign,
@@ -342,10 +338,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = M->getContext().IntTy;
+ FType = CGM.getContext().IntTy;
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__flags", DefUnit,
0, FieldSize, FieldAlign,
@@ -353,10 +349,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = M->getContext().IntTy;
+ FType = CGM.getContext().IntTy;
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__reserved", DefUnit,
0, FieldSize, FieldAlign,
@@ -364,10 +360,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = M->getContext().getPointerType(M->getContext().VoidTy);
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__FuncPtr", DefUnit,
0, FieldSize, FieldAlign,
@@ -375,10 +371,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = M->getContext().getPointerType(M->getContext().VoidTy);
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = DescTy;
- FieldSize = M->getContext().getTypeSize(Ty);
- FieldAlign = M->getContext().getTypeAlign(Ty);
+ FieldSize = CGM.getContext().getTypeSize(Ty);
+ FieldAlign = CGM.getContext().getTypeAlign(Ty);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__descriptor", DefUnit,
0, FieldSize, FieldAlign,
@@ -411,7 +407,7 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
SourceLocation DefLoc = Ty->getDecl()->getLocation();
llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc);
- SourceManager &SM = M->getContext().getSourceManager();
+ SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(DefLoc);
unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine();
@@ -464,7 +460,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
Tag = llvm::dwarf::DW_TAG_class_type;
}
- SourceManager &SM = M->getContext().getSourceManager();
+ SourceManager &SM = CGM.getContext().getSourceManager();
// Get overall information about the record type for the debug info.
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
@@ -487,7 +483,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
llvm::DIType(), llvm::DIArray());
// If this is just a forward declaration, return it.
- if (!Decl->getDefinition(M->getContext()))
+ if (!Decl->getDefinition(CGM.getContext()))
return FwdDecl;
llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode();
@@ -498,7 +494,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
// Convert all the elements.
llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
- const ASTRecordLayout &RL = M->getContext().getASTRecordLayout(Decl);
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(Decl);
unsigned FieldNo = 0;
for (RecordDecl::field_iterator I = Decl->field_begin(),
@@ -530,12 +526,12 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
if (!FType->isIncompleteArrayType()) {
// Bit size, align and offset of the type.
- FieldSize = M->getContext().getTypeSize(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
Expr *BitWidth = Field->getBitWidth();
if (BitWidth)
- FieldSize = BitWidth->EvaluateAsInt(M->getContext()).getZExtValue();
+ FieldSize = BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue();
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
}
uint64_t FieldOffset = RL.getFieldOffset(FieldNo);
@@ -554,8 +550,8 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
// Bit size, align and offset of the type.
- uint64_t Size = M->getContext().getTypeSize(Ty);
- uint64_t Align = M->getContext().getTypeAlign(Ty);
+ uint64_t Size = CGM.getContext().getTypeSize(Ty);
+ uint64_t Align = CGM.getContext().getTypeAlign(Ty);
llvm::DICompositeType RealDecl =
DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(),
@@ -575,7 +571,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
ObjCInterfaceDecl *Decl = Ty->getDecl();
unsigned Tag = llvm::dwarf::DW_TAG_structure_type;
- SourceManager &SM = M->getContext().getSourceManager();
+ SourceManager &SM = CGM.getContext().getSourceManager();
// Get overall information about the record type for the debug info.
llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(Decl->getLocation());
@@ -612,7 +608,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
ObjCInterfaceDecl *SClass = Decl->getSuperClass();
if (SClass) {
llvm::DIType SClassTy =
- getOrCreateType(M->getContext().getObjCInterfaceType(SClass), Unit);
+ getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit);
llvm::DIType InhTag =
DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_inheritance,
Unit, "", llvm::DICompileUnit(), 0, 0, 0,
@@ -620,7 +616,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
EltTys.push_back(InhTag);
}
- const ASTRecordLayout &RL = M->getContext().getASTObjCInterfaceLayout(Decl);
+ const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(Decl);
unsigned FieldNo = 0;
for (ObjCInterfaceDecl::ivar_iterator I = Decl->ivar_begin(),
@@ -648,12 +644,12 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
if (!FType->isIncompleteArrayType()) {
// Bit size, align and offset of the type.
- FieldSize = M->getContext().getTypeSize(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
Expr *BitWidth = Field->getBitWidth();
if (BitWidth)
- FieldSize = BitWidth->EvaluateAsInt(M->getContext()).getZExtValue();
+ FieldSize = BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue();
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
}
uint64_t FieldOffset = RL.getFieldOffset(FieldNo);
@@ -678,8 +674,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
// Bit size, align and offset of the type.
- uint64_t Size = M->getContext().getTypeSize(Ty);
- uint64_t Align = M->getContext().getTypeAlign(Ty);
+ uint64_t Size = CGM.getContext().getTypeSize(Ty);
+ uint64_t Align = CGM.getContext().getTypeAlign(Ty);
llvm::DICompositeType RealDecl =
DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), DefUnit,
@@ -713,7 +709,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
SourceLocation DefLoc = Decl->getLocation();
llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc);
- SourceManager &SM = M->getContext().getSourceManager();
+ SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(DefLoc);
unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine();
@@ -722,8 +718,8 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
uint64_t Size = 0;
unsigned Align = 0;
if (!Ty->isIncompleteType()) {
- Size = M->getContext().getTypeSize(Ty);
- Align = M->getContext().getTypeAlign(Ty);
+ Size = CGM.getContext().getTypeSize(Ty);
+ Align = CGM.getContext().getTypeAlign(Ty);
}
llvm::DIType DbgTy =
@@ -754,14 +750,14 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(Ty)) {
Size = 0;
Align =
- M->getContext().getTypeAlign(M->getContext().getBaseElementType(VAT));
+ CGM.getContext().getTypeAlign(CGM.getContext().getBaseElementType(VAT));
} else if (Ty->isIncompleteArrayType()) {
Size = 0;
- Align = M->getContext().getTypeAlign(Ty->getElementType());
+ Align = CGM.getContext().getTypeAlign(Ty->getElementType());
} else {
// Size and align of the whole array, not the element type.
- Size = M->getContext().getTypeSize(Ty);
- Align = M->getContext().getTypeAlign(Ty);
+ Size = CGM.getContext().getTypeSize(Ty);
+ Align = CGM.getContext().getTypeAlign(Ty);
}
// Add the dimensions of the array. FIXME: This loses CV qualifiers from
@@ -797,6 +793,47 @@ llvm::DIType CGDebugInfo::CreateType(const LValueReferenceType *Ty,
Ty, Ty->getPointeeType(), Unit);
}
+llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
+ llvm::DICompileUnit U) {
+ QualType PointerDiffTy = CGM.getContext().getPointerDiffType();
+ llvm::DIType PointerDiffDITy = getOrCreateType(PointerDiffTy, U);
+
+ if (!Ty->getPointeeType()->isFunctionType()) {
+ // We have a data member pointer type.
+ return PointerDiffDITy;
+ }
+
+ // We have a member function pointer type. Treat it as a struct with two
+ // ptrdiff_t members.
+ std::pair<uint64_t, unsigned> Info = CGM.getContext().getTypeInfo(Ty);
+
+ uint64_t FieldOffset = 0;
+ llvm::DIDescriptor ElementTypes[2];
+
+ // FIXME: This should probably be a function type instead.
+ ElementTypes[0] =
+ DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, U,
+ "ptr", llvm::DICompileUnit(), 0,
+ Info.first, Info.second, FieldOffset, 0,
+ PointerDiffDITy);
+ FieldOffset += Info.first;
+
+ ElementTypes[1] =
+ DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, U,
+ "ptr", llvm::DICompileUnit(), 0,
+ Info.first, Info.second, FieldOffset, 0,
+ PointerDiffDITy);
+
+ llvm::DIArray Elements =
+ DebugFactory.GetOrCreateArray(&ElementTypes[0],
+ llvm::array_lengthof(ElementTypes));
+
+ return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_structure_type,
+ U, llvm::StringRef("test"),
+ llvm::DICompileUnit(), 0, FieldOffset,
+ 0, 0, 0, llvm::DIType(), Elements);
+}
+
static QualType CanonicalizeTypeForDebugInfo(QualType T) {
switch (T->getTypeClass()) {
default:
@@ -895,25 +932,27 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
case Type::LValueReference:
return CreateType(cast<LValueReferenceType>(Ty), Unit);
+ case Type::MemberPointer:
+ return CreateType(cast<MemberPointerType>(Ty), Unit);
}
}
/// EmitFunctionStart - Constructs the debug code for entering a function -
/// "llvm.dbg.func.start.".
-void CGDebugInfo::EmitFunctionStart(const char *Name, QualType FnType,
+void CGDebugInfo::EmitFunctionStart(llvm::StringRef Name, QualType FnType,
llvm::Function *Fn,
CGBuilderTy &Builder) {
- const char *LinkageName = Name;
+ llvm::StringRef LinkageName(Name);
// Skip the asm prefix if it exists.
//
// FIXME: This should probably be the unmangled name?
if (Name[0] == '\01')
- ++Name;
+ Name = Name.substr(1);
// FIXME: Why is this using CurLoc???
llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc);
- SourceManager &SM = M->getContext().getSourceManager();
+ SourceManager &SM = CGM.getContext().getSourceManager();
unsigned LineNo = SM.getPresumedLoc(CurLoc).getLine();
llvm::DISubprogram SP =
@@ -930,7 +969,7 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) {
if (CurLoc.isInvalid() || CurLoc.isMacroID()) return;
// Don't bother if things are the same as last time.
- SourceManager &SM = M->getContext().getSourceManager();
+ SourceManager &SM = CGM.getContext().getSourceManager();
if (CurLoc == PrevLoc
|| (SM.getInstantiationLineNumber(CurLoc) ==
SM.getInstantiationLineNumber(PrevLoc)
@@ -982,7 +1021,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
// 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 = M->getCodeGenOpts();
+ const CodeGenOptions &CGO = CGM.getCodeGenOpts();
if (CGO.OptimizationLevel)
return;
@@ -1006,10 +1045,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
// Build up structure for the byref. See BuildByRefType.
FieldOffset = 0;
- FType = M->getContext().getPointerType(M->getContext().VoidTy);
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__isa", DefUnit,
0, FieldSize, FieldAlign,
@@ -1017,10 +1056,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = M->getContext().getPointerType(M->getContext().VoidTy);
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__forwarding", DefUnit,
0, FieldSize, FieldAlign,
@@ -1028,10 +1067,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty;
+ FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty;
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__flags", DefUnit,
0, FieldSize, FieldAlign,
@@ -1039,10 +1078,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty;
+ FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty;
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__size", DefUnit,
0, FieldSize, FieldAlign,
@@ -1050,12 +1089,12 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- bool HasCopyAndDispose = M->BlockRequiresCopying(Type);
+ bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type);
if (HasCopyAndDispose) {
- FType = M->getContext().getPointerType(M->getContext().VoidTy);
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__copy_helper", DefUnit,
0, FieldSize, FieldAlign,
@@ -1063,10 +1102,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = M->getContext().getPointerType(M->getContext().VoidTy);
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__destroy_helper", DefUnit,
0, FieldSize, FieldAlign,
@@ -1075,8 +1114,8 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
FieldOffset += FieldSize;
}
- unsigned Align = M->getContext().getDeclAlignInBytes(Decl);
- if (Align > M->getContext().Target.getPointerAlign(0) / 8) {
+ unsigned Align = CGM.getContext().getDeclAlignInBytes(Decl);
+ if (Align > CGM.getContext().Target.getPointerAlign(0) / 8) {
unsigned AlignedOffsetInBytes
= llvm::RoundUpToAlignment(FieldOffset/8, Align);
unsigned NumPaddingBytes
@@ -1084,11 +1123,11 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
if (NumPaddingBytes > 0) {
llvm::APInt pad(32, NumPaddingBytes);
- FType = M->getContext().getConstantArrayType(M->getContext().CharTy,
+ FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
pad, ArrayType::Normal, 0);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member,
Unit, "", DefUnit,
0, FieldSize, FieldAlign,
@@ -1100,7 +1139,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
FType = Type;
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = Align*8;
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
@@ -1121,7 +1160,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
}
// Get location information.
- SourceManager &SM = M->getContext().getSourceManager();
+ SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned Line = 0;
unsigned Column = 0;
@@ -1158,7 +1197,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
// 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 = M->getCodeGenOpts();
+ const CodeGenOptions &CGO = CGM.getCodeGenOpts();
if (CGO.OptimizationLevel || Builder.GetInsertBlock() == 0)
return;
@@ -1183,10 +1222,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
// Build up structure for the byref. See BuildByRefType.
FieldOffset = 0;
- FType = M->getContext().getPointerType(M->getContext().VoidTy);
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__isa", DefUnit,
0, FieldSize, FieldAlign,
@@ -1194,10 +1233,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = M->getContext().getPointerType(M->getContext().VoidTy);
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__forwarding", DefUnit,
0, FieldSize, FieldAlign,
@@ -1205,10 +1244,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty;
+ FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty;
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__flags", DefUnit,
0, FieldSize, FieldAlign,
@@ -1216,10 +1255,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty;
+ FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty;
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__size", DefUnit,
0, FieldSize, FieldAlign,
@@ -1227,12 +1266,12 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- bool HasCopyAndDispose = M->BlockRequiresCopying(Type);
+ bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type);
if (HasCopyAndDispose) {
- FType = M->getContext().getPointerType(M->getContext().VoidTy);
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__copy_helper", DefUnit,
0, FieldSize, FieldAlign,
@@ -1240,10 +1279,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- FType = M->getContext().getPointerType(M->getContext().VoidTy);
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__destroy_helper", DefUnit,
0, FieldSize, FieldAlign,
@@ -1252,8 +1291,8 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
FieldOffset += FieldSize;
}
- unsigned Align = M->getContext().getDeclAlignInBytes(Decl);
- if (Align > M->getContext().Target.getPointerAlign(0) / 8) {
+ unsigned Align = CGM.getContext().getDeclAlignInBytes(Decl);
+ if (Align > CGM.getContext().Target.getPointerAlign(0) / 8) {
unsigned AlignedOffsetInBytes
= llvm::RoundUpToAlignment(FieldOffset/8, Align);
unsigned NumPaddingBytes
@@ -1261,11 +1300,11 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
if (NumPaddingBytes > 0) {
llvm::APInt pad(32, NumPaddingBytes);
- FType = M->getContext().getConstantArrayType(M->getContext().CharTy,
+ FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
pad, ArrayType::Normal, 0);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
- FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member,
Unit, "", DefUnit,
0, FieldSize, FieldAlign,
@@ -1277,7 +1316,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
FType = Type;
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = M->getContext().getTypeSize(FType);
+ FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = Align*8;
XOffset = FieldOffset;
@@ -1299,7 +1338,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
}
// Get location information.
- SourceManager &SM = M->getContext().getSourceManager();
+ SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned Line = 0;
if (!PLoc.isInvalid())
@@ -1309,7 +1348,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
uint64_t offset = CGF->BlockDecls[Decl];
llvm::SmallVector<llvm::Value *, 9> addr;
- llvm::LLVMContext &VMContext = M->getLLVMContext();
+ llvm::LLVMContext &VMContext = CGM.getLLVMContext();
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
llvm::DIFactory::OpDeref));
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
@@ -1376,7 +1415,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
// Create global variable debug descriptor.
llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
- SourceManager &SM = M->getContext().getSourceManager();
+ SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
@@ -1387,9 +1426,9 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
llvm::APSInt ConstVal(32);
ConstVal = 1;
- QualType ET = M->getContext().getAsArrayType(T)->getElementType();
+ QualType ET = CGM.getContext().getAsArrayType(T)->getElementType();
- T = M->getContext().getConstantArrayType(ET, ConstVal,
+ T = CGM.getContext().getConstantArrayType(ET, ConstVal,
ArrayType::Normal, 0);
}
llvm::StringRef DeclName = Decl->getName();
@@ -1405,22 +1444,22 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
ObjCInterfaceDecl *Decl) {
// Create global variable debug descriptor.
llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
- SourceManager &SM = M->getContext().getSourceManager();
+ SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
llvm::StringRef Name = Decl->getName();
- QualType T = M->getContext().getObjCInterfaceType(Decl);
+ QualType T = CGM.getContext().getObjCInterfaceType(Decl);
if (T->isIncompleteArrayType()) {
// CodeGen turns int[] into int[1] so we'll do the same here.
llvm::APSInt ConstVal(32);
ConstVal = 1;
- QualType ET = M->getContext().getAsArrayType(T)->getElementType();
+ QualType ET = CGM.getContext().getAsArrayType(T)->getElementType();
- T = M->getContext().getConstantArrayType(ET, ConstVal,
+ T = CGM.getContext().getConstantArrayType(ET, ConstVal,
ArrayType::Normal, 0);
}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index af86e2b..7df2a62 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -40,7 +40,7 @@ namespace CodeGen {
/// and is responsible for emitting to llvm globals or pass directly to
/// the backend.
class CGDebugInfo {
- CodeGenModule *M;
+ CodeGenModule &CGM;
bool isMainCompileUnitCreated;
llvm::DIFactory DebugFactory;
@@ -74,12 +74,13 @@ class CGDebugInfo {
llvm::DIType CreateType(const EnumType *Ty, llvm::DICompileUnit U);
llvm::DIType CreateType(const ArrayType *Ty, llvm::DICompileUnit U);
llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DICompileUnit U);
-
+ llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DICompileUnit U);
+
llvm::DIType CreatePointerLikeType(unsigned Tag,
const Type *Ty, QualType PointeeTy,
llvm::DICompileUnit U);
public:
- CGDebugInfo(CodeGenModule *m);
+ CGDebugInfo(CodeGenModule &CGM);
~CGDebugInfo();
/// setLocation - Update the current source location. If \arg loc is
@@ -92,7 +93,7 @@ public:
/// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate
/// start of a new function.
- void EmitFunctionStart(const char *Name, QualType FnType,
+ void EmitFunctionStart(llvm::StringRef Name, QualType FnType,
llvm::Function *Fn, CGBuilderTy &Builder);
/// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index c047283..14ee90d 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -43,6 +43,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::StaticAssert: // static_assert(X, ""); [C++0x]
// None of these decls require codegen support.
return;
@@ -85,28 +86,32 @@ void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) {
assert(0 && "Unknown storage class");
}
+static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D,
+ const char *Separator) {
+ CodeGenModule &CGM = CGF.CGM;
+ if (CGF.getContext().getLangOptions().CPlusPlus)
+ return CGM.getMangledName(&D);
+
+ std::string ContextName;
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl))
+ ContextName = CGM.getMangledName(FD);
+ else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl))
+ ContextName = CGF.CurFn->getName();
+ else
+ // FIXME: What about in a block??
+ assert(0 && "Unknown context for block var decl");
+
+ return ContextName + Separator + D.getNameAsString();
+}
+
llvm::GlobalVariable *
CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D,
const char *Separator,
- llvm::GlobalValue::LinkageTypes
- Linkage) {
+ llvm::GlobalValue::LinkageTypes Linkage) {
QualType Ty = D.getType();
assert(Ty->isConstantSizeType() && "VLAs can't be static");
- std::string Name;
- if (getContext().getLangOptions().CPlusPlus) {
- Name = CGM.getMangledName(&D);
- } else {
- std::string ContextName;
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurFuncDecl))
- ContextName = CGM.getMangledName(FD);
- else if (isa<ObjCMethodDecl>(CurFuncDecl))
- ContextName = CurFn->getName();
- else
- assert(0 && "Unknown context for block var decl");
-
- Name = ContextName + Separator + D.getNameAsString();
- }
+ std::string Name = GetStaticDeclName(*this, D, Separator);
const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
llvm::GlobalVariable *GV =
@@ -118,6 +123,54 @@ CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D,
return GV;
}
+/// AddInitializerToGlobalBlockVarDecl - Add the initializer for 'D' to the
+/// global variable that has already been created for it. If the initializer
+/// has a different type than GV does, this may free GV and return a different
+/// one. Otherwise it just returns GV.
+llvm::GlobalVariable *
+CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D,
+ llvm::GlobalVariable *GV) {
+ llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), D.getType(), this);
+
+ // If constant emission failed, then this should be a C++ static
+ // initializer.
+ if (!Init) {
+ if (!getContext().getLangOptions().CPlusPlus)
+ CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
+ else
+ EmitStaticCXXBlockVarDeclInit(D, GV);
+ return GV;
+ }
+
+ // The initializer may differ in type from the global. Rewrite
+ // the global to match the initializer. (We have to do this
+ // because some types, like unions, can't be completely represented
+ // in the LLVM type system.)
+ if (GV->getType() != Init->getType()) {
+ llvm::GlobalVariable *OldGV = GV;
+
+ GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
+ OldGV->isConstant(),
+ OldGV->getLinkage(), Init, "",
+ 0, D.isThreadSpecified(),
+ D.getType().getAddressSpace());
+
+ // Steal the name of the old global
+ GV->takeName(OldGV);
+
+ // Replace all uses of the old global with the new global
+ llvm::Constant *NewPtrForOldDecl =
+ llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
+ OldGV->replaceAllUsesWith(NewPtrForOldDecl);
+
+ // Erase the old global, since it is no longer used.
+ OldGV->eraseFromParent();
+ }
+
+ GV->setInitializer(Init);
+ return GV;
+}
+
void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
@@ -135,45 +188,9 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
if (D.getType()->isVariablyModifiedType())
EmitVLASize(D.getType());
- if (D.getInit()) {
- llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), D.getType(), this);
-
- // If constant emission failed, then this should be a C++ static
- // initializer.
- if (!Init) {
- if (!getContext().getLangOptions().CPlusPlus)
- CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
- else
- EmitStaticCXXBlockVarDeclInit(D, GV);
- } else {
- // The initializer may differ in type from the global. Rewrite
- // the global to match the initializer. (We have to do this
- // because some types, like unions, can't be completely represented
- // in the LLVM type system.)
- if (GV->getType() != Init->getType()) {
- llvm::GlobalVariable *OldGV = GV;
-
- GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
- OldGV->isConstant(),
- OldGV->getLinkage(), Init, "",
- 0, D.isThreadSpecified(),
- D.getType().getAddressSpace());
-
- // Steal the name of the old global
- GV->takeName(OldGV);
-
- // Replace all uses of the old global with the new global
- llvm::Constant *NewPtrForOldDecl =
- llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
- OldGV->replaceAllUsesWith(NewPtrForOldDecl);
-
- // Erase the old global, since it is no longer used.
- OldGV->eraseFromParent();
- }
-
- GV->setInitializer(Init);
- }
- }
+ // If this value has an initializer, emit it.
+ if (D.getInit())
+ GV = AddInitializerToGlobalBlockVarDecl(D, GV);
// FIXME: Merge attribute handling.
if (const AnnotateAttr *AA = D.getAttr<AnnotateAttr>()) {
@@ -317,32 +334,36 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
bool isByRef = D.hasAttr<BlocksAttr>();
bool needsDispose = false;
unsigned Align = 0;
+ bool IsSimpleConstantInitializer = false;
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
if (!Target.useGlobalsForAutomaticVariables()) {
- // All constant structs and arrays should be global if
- // their initializer is constant and if the element type is POD.
- if (CGM.getCodeGenOpts().MergeAllConstants) {
- if (Ty.isConstant(getContext())
- && (Ty->isArrayType() || Ty->isRecordType())
- && (D.getInit()
- && D.getInit()->isConstantInitializer(getContext()))
- && Ty->isPODType()) {
+ // If this value is an array or struct, is POD, and if the initializer is
+ // a staticly determinable constant, try to optimize it.
+ if (D.getInit() && !isByRef &&
+ (Ty->isArrayType() || Ty->isRecordType()) &&
+ Ty->isPODType() &&
+ D.getInit()->isConstantInitializer(getContext())) {
+ // If this variable is marked 'const', emit the value as a global.
+ if (CGM.getCodeGenOpts().MergeAllConstants &&
+ Ty.isConstant(getContext())) {
EmitStaticBlockVarDecl(D);
return;
}
+
+ IsSimpleConstantInitializer = true;
}
// A normal fixed sized variable becomes an alloca in the entry block.
const llvm::Type *LTy = ConvertTypeForMem(Ty);
- Align = getContext().getDeclAlignInBytes(&D);
if (isByRef)
LTy = BuildByRefType(&D);
llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
- Alloc->setName(D.getNameAsString().c_str());
+ Alloc->setName(D.getNameAsString());
+ Align = getContext().getDeclAlignInBytes(&D);
if (isByRef)
Align = std::max(Align, unsigned(Target.getPointerAlign(0) / 8));
Alloc->setAlignment(Align);
@@ -436,9 +457,48 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
D.getNameAsString());
- bool isVolatile = (getContext().getCanonicalType(D.getType())
- .isVolatileQualified());
- if (Ty->isReferenceType()) {
+ bool isVolatile =
+ getContext().getCanonicalType(D.getType()).isVolatileQualified();
+
+ // If the initializer was a simple constant initializer, we can optimize it
+ // in various ways.
+ if (IsSimpleConstantInitializer) {
+ llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(),D.getType(),this);
+ assert(Init != 0 && "Wasn't a simple constant init?");
+
+ llvm::Value *AlignVal =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Align);
+ const llvm::Type *IntPtr =
+ llvm::IntegerType::get(VMContext, LLVMPointerWidth);
+ llvm::Value *SizeVal =
+ llvm::ConstantInt::get(IntPtr, getContext().getTypeSizeInBytes(Ty));
+
+ const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext);
+ if (Loc->getType() != BP)
+ Loc = Builder.CreateBitCast(Loc, BP, "tmp");
+
+ // If the initializer is all zeros, codegen with memset.
+ if (isa<llvm::ConstantAggregateZero>(Init)) {
+ llvm::Value *Zero =
+ llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 0);
+ Builder.CreateCall4(CGM.getMemSetFn(), Loc, Zero, SizeVal, AlignVal);
+ } else {
+ // Otherwise, create a temporary global with the initializer then
+ // memcpy from the global to the alloca.
+ std::string Name = GetStaticDeclName(*this, D, ".");
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(CGM.getModule(), Init->getType(), true,
+ llvm::GlobalValue::InternalLinkage,
+ Init, Name, 0, false, 0);
+ GV->setAlignment(Align);
+
+ llvm::Value *SrcPtr = GV;
+ if (SrcPtr->getType() != BP)
+ SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp");
+
+ Builder.CreateCall4(CGM.getMemCpyFn(), Loc, SrcPtr, SizeVal, AlignVal);
+ }
+ } else if (Ty->isReferenceType()) {
RValue RV = EmitReferenceBindingToExpr(Init, Ty, /*IsInitializer=*/true);
EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty);
} else if (!hasAggregateLLVMType(Init->getType())) {
@@ -521,19 +581,39 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
if (const ConstantArrayType *Array =
getContext().getAsConstantArrayType(Ty)) {
- DelayedCleanupBlock Scope(*this);
- QualType BaseElementTy = getContext().getBaseElementType(Array);
- const llvm::Type *BasePtr = ConvertType(BaseElementTy);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(DeclPtr, BasePtr);
- EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
+ {
+ DelayedCleanupBlock Scope(*this);
+ QualType BaseElementTy = getContext().getBaseElementType(Array);
+ const llvm::Type *BasePtr = ConvertType(BaseElementTy);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ Builder.CreateBitCast(DeclPtr, BasePtr);
+ EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
- // Make sure to jump to the exit block.
- EmitBranch(Scope.getCleanupExitBlock());
+ // Make sure to jump to the exit block.
+ EmitBranch(Scope.getCleanupExitBlock());
+ }
+ if (Exceptions) {
+ EHCleanupBlock Cleanup(*this);
+ QualType BaseElementTy = getContext().getBaseElementType(Array);
+ const llvm::Type *BasePtr = ConvertType(BaseElementTy);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ Builder.CreateBitCast(DeclPtr, BasePtr);
+ EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
+ }
} else {
- DelayedCleanupBlock Scope(*this);
- EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
+ {
+ DelayedCleanupBlock Scope(*this);
+ EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
+
+ // Make sure to jump to the exit block.
+ EmitBranch(Scope.getCleanupExitBlock());
+ }
+ if (Exceptions) {
+ EHCleanupBlock Cleanup(*this);
+ EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
+ }
}
}
}
@@ -545,8 +625,6 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
llvm::Constant* F = CGM.GetAddrOfFunction(FD);
assert(F && "Could not find function!");
- DelayedCleanupBlock scope(*this);
-
const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD);
// In some cases, the type of the function argument will be different from
@@ -556,20 +634,40 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
//
// To fix this we insert a bitcast here.
QualType ArgTy = Info.arg_begin()->type;
- DeclPtr = Builder.CreateBitCast(DeclPtr, ConvertType(ArgTy));
-
- CallArgList Args;
- Args.push_back(std::make_pair(RValue::get(DeclPtr),
- getContext().getPointerType(D.getType())));
-
- EmitCall(Info, F, Args);
+ {
+ DelayedCleanupBlock scope(*this);
+
+ CallArgList Args;
+ Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr,
+ ConvertType(ArgTy))),
+ getContext().getPointerType(D.getType())));
+ EmitCall(Info, F, Args);
+ }
+ if (Exceptions) {
+ EHCleanupBlock Cleanup(*this);
+
+ CallArgList Args;
+ Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr,
+ ConvertType(ArgTy))),
+ getContext().getPointerType(D.getType())));
+ EmitCall(Info, F, Args);
+ }
}
if (needsDispose && CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) {
- DelayedCleanupBlock scope(*this);
- llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
- V = Builder.CreateLoad(V);
- BuildBlockRelease(V);
+ {
+ DelayedCleanupBlock scope(*this);
+ llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
+ V = Builder.CreateLoad(V);
+ BuildBlockRelease(V);
+ }
+ // FIXME: Turn this on and audit the codegen
+ if (0 && Exceptions) {
+ EHCleanupBlock Cleanup(*this);
+ llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
+ V = Builder.CreateLoad(V);
+ BuildBlockRelease(V);
+ }
}
}
@@ -591,10 +689,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) {
const llvm::Type *LTy = ConvertTypeForMem(Ty);
if (LTy->isSingleValueType()) {
// TODO: Alignment
- std::string Name = D.getNameAsString();
- Name += ".addr";
DeclPtr = CreateTempAlloca(LTy);
- DeclPtr->setName(Name.c_str());
+ DeclPtr->setName(D.getNameAsString() + llvm::StringRef(".addr"));
// Store the initial value into the alloca.
EmitStoreOfScalar(Arg, DeclPtr, CTy.isVolatileQualified(), Ty);
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
new file mode 100644
index 0000000..0b6ea5a
--- /dev/null
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -0,0 +1,211 @@
+//===--- CGDeclCXX.cpp - Emit LLVM Code for C++ declarations --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code dealing with code generation of C++ declarations
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenFunction.h"
+using namespace clang;
+using namespace CodeGen;
+
+static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
+ llvm::Constant *DeclPtr) {
+ assert(D.hasGlobalStorage() && "VarDecl must have global storage!");
+ assert(!D.getType()->isReferenceType() &&
+ "Should not call EmitDeclInit on a reference!");
+
+ CodeGenModule &CGM = CGF.CGM;
+ ASTContext &Context = CGF.getContext();
+
+ const Expr *Init = D.getInit();
+ QualType T = D.getType();
+ bool isVolatile = Context.getCanonicalType(T).isVolatileQualified();
+
+ if (!CGF.hasAggregateLLVMType(T)) {
+ llvm::Value *V = CGF.EmitScalarExpr(Init);
+ CGF.EmitStoreOfScalar(V, DeclPtr, isVolatile, T);
+ } else if (T->isAnyComplexType()) {
+ CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile);
+ } else {
+ CGF.EmitAggExpr(Init, DeclPtr, isVolatile);
+
+ // Avoid generating destructor(s) for initialized objects.
+ if (!isa<CXXConstructExpr>(Init))
+ return;
+
+ const ConstantArrayType *Array = Context.getAsConstantArrayType(T);
+ if (Array)
+ T = Context.getBaseElementType(Array);
+
+ const RecordType *RT = T->getAs<RecordType>();
+ if (!RT)
+ return;
+
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (RD->hasTrivialDestructor())
+ return;
+
+ CXXDestructorDecl *Dtor = RD->getDestructor(Context);
+
+ llvm::Constant *DtorFn;
+ if (Array) {
+ DtorFn =
+ CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(Dtor,
+ Array,
+ DeclPtr);
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ DeclPtr = llvm::Constant::getNullValue(Int8PtrTy);
+ } else
+ DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
+
+ CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr);
+ }
+}
+
+void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
+ llvm::Constant *DeclPtr) {
+
+ const Expr *Init = D.getInit();
+ QualType T = D.getType();
+
+ if (!T->isReferenceType()) {
+ EmitDeclInit(*this, D, DeclPtr);
+ return;
+ }
+
+ ErrorUnsupported(Init, "global variable that binds to a reference");
+}
+
+void
+CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
+ llvm::Constant *DeclPtr) {
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8Ty(VMContext)->getPointerTo();
+
+ std::vector<const llvm::Type *> Params;
+ Params.push_back(Int8PtrTy);
+
+ // Get the destructor function type
+ const llvm::Type *DtorFnTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false);
+ DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy);
+
+ Params.clear();
+ Params.push_back(DtorFnTy);
+ Params.push_back(Int8PtrTy);
+ Params.push_back(Int8PtrTy);
+
+ // Get the __cxa_atexit function type
+ // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d );
+ const llvm::FunctionType *AtExitFnTy =
+ llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false);
+
+ llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy,
+ "__cxa_atexit");
+
+ llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy,
+ "__dso_handle");
+ llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy),
+ llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy),
+ llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) };
+ Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args));
+}
+
+void
+CodeGenModule::EmitCXXGlobalInitFunc() {
+ if (CXXGlobalInits.empty())
+ return;
+
+ const llvm::FunctionType *FTy
+ = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ false);
+
+ // Create our global initialization function.
+ // FIXME: Should this be tweakable by targets?
+ llvm::Function *Fn =
+ llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
+ "__cxx_global_initialization", &TheModule);
+
+ CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
+ &CXXGlobalInits[0],
+ CXXGlobalInits.size());
+ AddGlobalCtor(Fn);
+}
+
+void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
+ const VarDecl **Decls,
+ unsigned NumDecls) {
+ StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
+ SourceLocation());
+
+ for (unsigned i = 0; i != NumDecls; ++i) {
+ const VarDecl *D = Decls[i];
+
+ llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
+ EmitCXXGlobalVarDeclInit(*D, DeclPtr);
+ }
+ FinishFunction();
+}
+
+void
+CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
+ llvm::GlobalVariable *GV) {
+ // FIXME: This should use __cxa_guard_{acquire,release}?
+
+ assert(!getContext().getLangOptions().ThreadsafeStatics &&
+ "thread safe statics are currently not supported!");
+
+ llvm::SmallString<256> GuardVName;
+ CGM.getMangleContext().mangleGuardVariable(&D, GuardVName);
+
+ // Create the guard variable.
+ llvm::GlobalValue *GuardV =
+ new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext),
+ false, GV->getLinkage(),
+ llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)),
+ GuardVName.str());
+
+ // Load the first byte of the guard variable.
+ const llvm::Type *PtrTy
+ = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
+ llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy),
+ "tmp");
+
+ // Compare it against 0.
+ llvm::Value *nullValue
+ = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext));
+ llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool");
+
+ llvm::BasicBlock *InitBlock = createBasicBlock("init");
+ llvm::BasicBlock *EndBlock = createBasicBlock("init.end");
+
+ // If the guard variable is 0, jump to the initializer code.
+ Builder.CreateCondBr(ICmp, InitBlock, EndBlock);
+
+ EmitBlock(InitBlock);
+
+ if (D.getType()->isReferenceType()) {
+ QualType T = D.getType();
+ // We don't want to pass true for IsInitializer here, because a static
+ // reference to a temporary does not extend its lifetime.
+ RValue RV = EmitReferenceBindingToExpr(D.getInit(), T,
+ /*IsInitializer=*/false);
+ EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, T);
+
+ } else
+ EmitDeclInit(*this, D, GV);
+
+ Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext),
+ 1),
+ Builder.CreateBitCast(GuardV, PtrTy));
+
+ EmitBlock(EndBlock);
+}
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 420e275..b15b2e9 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -23,58 +23,83 @@ static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
// void *__cxa_allocate_exception(size_t thrown_size);
const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
std::vector<const llvm::Type*> Args(1, SizeTy);
-
- const llvm::FunctionType *FTy =
+
+ const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()),
Args, false);
-
+
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
}
+static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) {
+ // void __cxa_free_exception(void *thrown_exception);
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ std::vector<const llvm::Type*> Args(1, Int8PtrTy);
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
+ Args, false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
+}
+
static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
- // void __cxa_throw (void *thrown_exception, std::type_info *tinfo,
- // void (*dest) (void *) );
+ // void __cxa_throw(void *thrown_exception, std::type_info *tinfo,
+ // void (*dest) (void *));
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
std::vector<const llvm::Type*> Args(3, Int8PtrTy);
-
- const llvm::FunctionType *FTy =
+
+ const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
Args, false);
-
+
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
}
static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
- // void __cxa_rethrow ();
+ // void __cxa_rethrow();
- const llvm::FunctionType *FTy =
+ const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
-
+
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
}
static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
- // void* __cxa_begin_catch ();
+ // void* __cxa_begin_catch();
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
std::vector<const llvm::Type*> Args(1, Int8PtrTy);
-
- const llvm::FunctionType *FTy =
+
+ const llvm::FunctionType *FTy =
llvm::FunctionType::get(Int8PtrTy, Args, false);
-
+
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
}
static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
- // void __cxa_end_catch ();
+ // void __cxa_end_catch();
- const llvm::FunctionType *FTy =
+ const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
-
+
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
}
+static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
+ // void __cxa_call_unexepcted(void *thrown_exception);
+
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ std::vector<const llvm::Type*> Args(1, Int8PtrTy);
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
+ Args, false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
+}
+
// FIXME: Eventually this will all go into the backend. Set from the target for
// now.
static int using_sjlj_exceptions = 0;
@@ -82,38 +107,64 @@ static int using_sjlj_exceptions = 0;
static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) {
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
std::vector<const llvm::Type*> Args(1, Int8PtrTy);
-
- const llvm::FunctionType *FTy =
+
+ const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args,
false);
-
+
if (using_sjlj_exceptions)
return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
}
+static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
+ // void __terminate();
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev");
+}
+
// CopyObject - Utility to copy an object. Calls copy constructor as necessary.
-// N is casted to the right type.
-static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) {
+// 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(0);
-
- CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy));
+ 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(0);
- const CXXRecordDecl *RD;
- RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl());
- llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty);
+ 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)) {
- // FIXME: region management
+ llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest();
+ if (CGF.Exceptions) {
+ CodeGenFunction::EHCleanupBlock Cleanup(CGF);
+ llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF);
+
+ // Load the exception pointer.
+ llvm::Value *ExceptionPtr = CGF.Builder.CreateLoad(ExceptionPtrPtr);
+ CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr);
+ }
+
llvm::Value *Src = CGF.EmitLValue(E).getAddress();
+ CGF.setInvokeDest(PrevLandingPad);
+
+ llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler();
+ PrevLandingPad = CGF.getInvokeDest();
+ CGF.setInvokeDest(TerminateHandler);
// Stolen from EmitClassAggrMemberwiseCopy
llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor,
@@ -129,21 +180,22 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) {
CopyCtor->getType()->getAs<FunctionType>()->getResultType();
CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
Callee, CallArgs, CopyCtor);
- // FIXME: region management
+ CGF.setInvokeDest(PrevLandingPad);
} else
- CGF.ErrorUnsupported(E, "uncopyable object");
+ llvm_unreachable("uncopyable object");
}
}
// CopyObject - Utility to copy an object. Calls copy constructor as necessary.
// N is casted to the right type.
static void CopyObject(CodeGenFunction &CGF, QualType ObjectType,
- llvm::Value *E, llvm::Value *N) {
+ bool WasPointer, llvm::Value *E, llvm::Value *N) {
// Store the throw exception in the exception object.
- if (!CGF.hasAggregateLLVMType(ObjectType)) {
+ if (WasPointer || !CGF.hasAggregateLLVMType(ObjectType)) {
llvm::Value *Value = E;
+ if (!WasPointer)
+ Value = CGF.Builder.CreateLoad(Value);
const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0);
-
CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy));
} else {
const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0);
@@ -154,7 +206,6 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType,
CGF.EmitAggregateCopy(This, E, ObjectType);
} else if (CXXConstructorDecl *CopyCtor
= RD->getCopyConstructor(CGF.getContext(), 0)) {
- // FIXME: region management
llvm::Value *Src = E;
// Stolen from EmitClassAggrMemberwiseCopy
@@ -171,66 +222,181 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType,
CopyCtor->getType()->getAs<FunctionType>()->getResultType();
CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
Callee, CallArgs, CopyCtor);
- // FIXME: region management
} else
- llvm::llvm_unreachable("uncopyable object");
+ llvm_unreachable("uncopyable object");
}
}
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
if (!E->getSubExpr()) {
- Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn();
+ if (getInvokeDest()) {
+ llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
+ Builder.CreateInvoke(getReThrowFn(*this), Cont, getInvokeDest())
+ ->setDoesNotReturn();
+ EmitBlock(Cont);
+ } else
+ Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn();
Builder.CreateUnreachable();
// Clear the insertion point to indicate we are in unreachable code.
Builder.ClearInsertionPoint();
return;
}
-
+
QualType ThrowType = E->getSubExpr()->getType();
- // FIXME: Handle cleanup.
- if (!CleanupEntries.empty()){
- ErrorUnsupported(E, "throw expression with cleanup entries");
- return;
- }
-
+
// Now allocate the exception object.
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8;
-
+
llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this);
- llvm::Value *ExceptionPtr =
- Builder.CreateCall(AllocExceptionFn,
+ llvm::Value *ExceptionPtr =
+ Builder.CreateCall(AllocExceptionFn,
llvm::ConstantInt::get(SizeTy, TypeSize),
"exception");
-
- CopyObject(*this, E->getSubExpr(), ExceptionPtr);
+ llvm::Value *ExceptionPtrPtr =
+ CreateTempAlloca(ExceptionPtr->getType(), "exception.ptr");
+ Builder.CreateStore(ExceptionPtr, ExceptionPtrPtr);
+
+
+ CopyObject(*this, E->getSubExpr(), ExceptionPtr, ExceptionPtrPtr);
+
// Now throw the exception.
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
- llvm::Constant *TypeInfo = CGM.GenerateRtti(ThrowType);
+ llvm::Constant *TypeInfo = CGM.GenerateRTTI(ThrowType);
llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy);
-
- llvm::CallInst *ThrowCall =
- Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor);
- ThrowCall->setDoesNotReturn();
+
+ if (getInvokeDest()) {
+ llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
+ llvm::InvokeInst *ThrowCall =
+ Builder.CreateInvoke3(getThrowFn(*this), Cont, getInvokeDest(),
+ ExceptionPtr, TypeInfo, Dtor);
+ ThrowCall->setDoesNotReturn();
+ EmitBlock(Cont);
+ } else {
+ llvm::CallInst *ThrowCall =
+ Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor);
+ ThrowCall->setDoesNotReturn();
+ }
Builder.CreateUnreachable();
-
+
// Clear the insertion point to indicate we are in unreachable code.
Builder.ClearInsertionPoint();
+
+ // FIXME: For now, emit a dummy basic block because expr emitters in generally
+ // are not ready to handle emitting expressions at unreachable points.
+ EnsureInsertPoint();
}
-void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
-#if 1
- EmitStmt(S.getTryBlock());
- if (0) {
- getBeginCatchFn(*this);
- getEndCatchFn(*this);
- getUnwindResumeOrRethrowFn(*this);
- CopyObject(*this, QualType(), 0, 0);
+void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
+ const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
+ if (FD == 0)
+ return;
+ const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>();
+ if (Proto == 0)
+ return;
+
+ assert(!Proto->hasAnyExceptionSpec() && "function with parameter pack");
+
+ if (!Proto->hasExceptionSpec())
+ return;
+
+ llvm::Constant *Personality =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
+ (VMContext),
+ true),
+ "__gxx_personality_v0");
+ Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
+ llvm::Value *llvm_eh_exception =
+ CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
+ llvm::Value *llvm_eh_selector =
+ CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
+ const llvm::IntegerType *Int8Ty;
+ const llvm::PointerType *PtrToInt8Ty;
+ Int8Ty = llvm::Type::getInt8Ty(VMContext);
+ // C string type. Used in lots of places.
+ PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
+ llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
+ llvm::SmallVector<llvm::Value*, 8> SelectorArgs;
+
+ llvm::BasicBlock *PrevLandingPad = getInvokeDest();
+ llvm::BasicBlock *EHSpecHandler = createBasicBlock("ehspec.handler");
+ llvm::BasicBlock *Match = createBasicBlock("match");
+ llvm::BasicBlock *Unwind = 0;
+
+ assert(PrevLandingPad == 0 && "EHSpec has invoke context");
+ (void)PrevLandingPad;
+
+ llvm::BasicBlock *Cont = createBasicBlock("cont");
+
+ EmitBranchThroughCleanup(Cont);
+
+ // Emit the statements in the try {} block
+ setInvokeDest(EHSpecHandler);
+
+ EmitBlock(EHSpecHandler);
+ // Exception object
+ llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
+ llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow");
+
+ SelectorArgs.push_back(Exc);
+ SelectorArgs.push_back(Personality);
+ SelectorArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+ Proto->getNumExceptions()+1));
+
+ for (unsigned i = 0; i < Proto->getNumExceptions(); ++i) {
+ QualType Ty = Proto->getExceptionType(i);
+ llvm::Value *EHType
+ = CGM.GenerateRTTI(Ty.getNonReferenceType());
+ SelectorArgs.push_back(EHType);
}
-#else
- // FIXME: The below is still just a sketch of the code we need.
+ if (Proto->getNumExceptions())
+ SelectorArgs.push_back(Null);
+
+ // Find which handler was matched.
+ llvm::Value *Selector
+ = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(),
+ SelectorArgs.end(), "selector");
+ if (Proto->getNumExceptions()) {
+ Unwind = createBasicBlock("Unwind");
+
+ Builder.CreateStore(Exc, RethrowPtr);
+ Builder.CreateCondBr(Builder.CreateICmpSLT(Selector,
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+ 0)),
+ Match, Unwind);
+
+ EmitBlock(Match);
+ }
+ Builder.CreateCall(getUnexpectedFn(*this), Exc)->setDoesNotReturn();
+ Builder.CreateUnreachable();
+
+ if (Proto->getNumExceptions()) {
+ EmitBlock(Unwind);
+ Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
+ Builder.CreateLoad(RethrowPtr));
+ Builder.CreateUnreachable();
+ }
+
+ EmitBlock(Cont);
+}
+
+void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
+ const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
+ if (FD == 0)
+ return;
+ const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>();
+ if (Proto == 0)
+ return;
+
+ if (!Proto->hasExceptionSpec())
+ return;
+
+ setInvokeDest(0);
+}
+
+void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
// Pointer to the personality function
llvm::Constant *Personality =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
@@ -238,31 +404,66 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
true),
"__gxx_personality_v0");
Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
+ llvm::Value *llvm_eh_exception =
+ CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
+ llvm::Value *llvm_eh_selector =
+ CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
llvm::BasicBlock *PrevLandingPad = getInvokeDest();
llvm::BasicBlock *TryHandler = createBasicBlock("try.handler");
-#if 0
llvm::BasicBlock *FinallyBlock = createBasicBlock("finally");
-#endif
llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw");
llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end");
-#if 0
// Push an EH context entry, used for handling rethrows.
PushCleanupBlock(FinallyBlock);
-#endif
// Emit the statements in the try {} block
setInvokeDest(TryHandler);
- EmitStmt(S.getTryBlock());
+ // FIXME: We should not have to do this here. The AST should have the member
+ // initializers under the CXXTryStmt's TryBlock.
+ if (OuterTryBlock == &S) {
+ GlobalDecl GD = CurGD;
+ const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
+
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
+ size_t OldCleanupStackSize = CleanupEntries.size();
+ EmitCtorPrologue(CD, CurGD.getCtorType());
+ EmitStmt(S.getTryBlock());
+
+ // If any of the member initializers are temporaries bound to references
+ // make sure to emit their destructors.
+ EmitCleanupBlocks(OldCleanupStackSize);
+ } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) {
+ llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue");
+ PushCleanupBlock(DtorEpilogue);
+
+ EmitStmt(S.getTryBlock());
+
+ CleanupBlockInfo Info = PopCleanupBlock();
+
+ assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!");
+ EmitBlock(DtorEpilogue);
+ EmitDtorEpilogue(DD, GD.getDtorType());
+
+ if (Info.SwitchBlock)
+ EmitBlock(Info.SwitchBlock);
+ if (Info.EndBlock)
+ EmitBlock(Info.EndBlock);
+ } else
+ EmitStmt(S.getTryBlock());
+ } else
+ EmitStmt(S.getTryBlock());
// Jump to end if there is no exception
EmitBranchThroughCleanup(FinallyEnd);
+ llvm::BasicBlock *TerminateHandler = getTerminateHandler();
+
// Emit the handlers
EmitBlock(TryHandler);
-
+
const llvm::IntegerType *Int8Ty;
const llvm::PointerType *PtrToInt8Ty;
Int8Ty = llvm::Type::getInt8Ty(VMContext);
@@ -270,16 +471,14 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
llvm::SmallVector<llvm::Value*, 8> SelectorArgs;
- llvm::Value *llvm_eh_exception =
- CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
- llvm::Value *llvm_eh_selector =
- CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
llvm::Value *llvm_eh_typeid_for =
CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for);
// Exception object
llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow");
+ llvm::SmallVector<llvm::Value*, 8> Args;
+ Args.clear();
SelectorArgs.push_back(Exc);
SelectorArgs.push_back(Personality);
@@ -288,7 +487,8 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
const CXXCatchStmt *C = S.getHandler(i);
VarDecl *CatchParam = C->getExceptionDecl();
if (CatchParam) {
- llvm::Value *EHType = CGM.GenerateRtti(C->getCaughtType().getNonReferenceType());
+ llvm::Value *EHType
+ = CGM.GenerateRTTI(C->getCaughtType().getNonReferenceType());
SelectorArgs.push_back(EHType);
} else {
// null indicates catch all
@@ -334,27 +534,31 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc);
- // Bind the catch parameter if it exists.
- if (CatchParam) {
- QualType CatchType = CatchParam->getType().getNonReferenceType();
- if (!CatchType.getTypePtr()->isPointerType())
- CatchType = getContext().getPointerType(CatchType);
- ExcObject =
- Builder.CreateBitCast(ExcObject, ConvertType(CatchType));
- // CatchParam is a ParmVarDecl because of the grammar
- // construction used to handle this, but for codegen purposes
- // we treat this as a local decl.
- EmitLocalBlockVarDecl(*CatchParam);
-#if 0
- // FIXME: objects with ctors, references
- Builder.CreateStore(ExcObject, GetAddrOfLocalVar(CatchParam));
-#else
- CopyObject(*this, CatchParam->getType().getNonReferenceType(),
- ExcObject, GetAddrOfLocalVar(CatchParam));
-#endif
+ {
+ CleanupScope CatchScope(*this);
+ // Bind the catch parameter if it exists.
+ if (CatchParam) {
+ QualType CatchType = CatchParam->getType().getNonReferenceType();
+ setInvokeDest(TerminateHandler);
+ bool WasPointer = true;
+ if (!CatchType.getTypePtr()->isPointerType()) {
+ if (!isa<ReferenceType>(CatchParam->getType()))
+ WasPointer = false;
+ CatchType = getContext().getPointerType(CatchType);
+ }
+ ExcObject = Builder.CreateBitCast(ExcObject, ConvertType(CatchType));
+ EmitLocalBlockVarDecl(*CatchParam);
+ // FIXME: we need to do this sooner so that the EH region for the
+ // cleanup doesn't start until after the ctor completes, use a decl
+ // init?
+ CopyObject(*this, CatchParam->getType().getNonReferenceType(),
+ WasPointer, ExcObject, GetAddrOfLocalVar(CatchParam));
+ setInvokeDest(MatchHandler);
+ }
+
+ EmitStmt(CatchBody);
}
- EmitStmt(CatchBody);
EmitBranchThroughCleanup(FinallyEnd);
EmitBlock(MatchHandler);
@@ -362,7 +566,7 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
llvm::Value *Exc = 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.clear();
Args.push_back(Exc);
Args.push_back(Personality);
Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
@@ -375,45 +579,32 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
EmitBlock(MatchEnd);
- // Unfortunately, we also have to generate another EH frame here
- // in case this throws.
- llvm::BasicBlock *MatchEndHandler =
- createBasicBlock("match.end.handler");
- llvm::BasicBlock *Cont = createBasicBlock("myinvoke.cont");
+ llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
Builder.CreateInvoke(getEndCatchFn(*this),
- Cont, MatchEndHandler,
+ Cont, TerminateHandler,
Args.begin(), Args.begin());
-
EmitBlock(Cont);
if (Info.SwitchBlock)
EmitBlock(Info.SwitchBlock);
if (Info.EndBlock)
EmitBlock(Info.EndBlock);
- EmitBlock(MatchEndHandler);
Exc = 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(Personality);
- Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- 0));
- Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
Builder.CreateStore(Exc, RethrowPtr);
EmitBranchThroughCleanup(FinallyRethrow);
if (Next)
EmitBlock(Next);
}
- if (!HasCatchAll)
+ if (!HasCatchAll) {
+ Builder.CreateStore(Exc, RethrowPtr);
EmitBranchThroughCleanup(FinallyRethrow);
+ }
CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock();
setInvokeDest(PrevLandingPad);
-#if 0
EmitBlock(FinallyBlock);
if (Info.SwitchBlock)
@@ -423,13 +614,122 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
// Branch around the rethrow code.
EmitBranch(FinallyEnd);
-#endif
EmitBlock(FinallyRethrow);
- Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
- Builder.CreateLoad(RethrowPtr));
+ // FIXME: Eventually we can chain the handlers together and just do a call
+ // here.
+ if (getInvokeDest()) {
+ llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
+ Builder.CreateInvoke(getUnwindResumeOrRethrowFn(*this), Cont,
+ getInvokeDest(),
+ Builder.CreateLoad(RethrowPtr));
+ EmitBlock(Cont);
+ } else
+ Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
+ Builder.CreateLoad(RethrowPtr));
+
Builder.CreateUnreachable();
EmitBlock(FinallyEnd);
-#endif
+}
+
+CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
+ llvm::BasicBlock *Cont1 = CGF.createBasicBlock("cont");
+ CGF.EmitBranch(Cont1);
+ CGF.setInvokeDest(PreviousInvokeDest);
+
+
+ CGF.EmitBlock(CleanupHandler);
+
+ 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);
+ 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::SmallVector<llvm::Value*, 8> Args;
+ Args.clear();
+ Args.push_back(Exc);
+ Args.push_back(Personality);
+ Args.push_back(Null);
+ CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
+
+ CGF.EmitBlock(CleanupEntryBB);
+
+ CGF.EmitBlock(Cont1);
+
+ if (CGF.getInvokeDest()) {
+ llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
+ CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont,
+ CGF.getInvokeDest(), Exc);
+ CGF.EmitBlock(Cont);
+ } else
+ CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc);
+
+ CGF.Builder.CreateUnreachable();
+
+ CGF.EmitBlock(Cont);
+ if (CGF.Exceptions)
+ CGF.setInvokeDest(CleanupHandler);
+}
+
+llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
+ if (TerminateHandler)
+ return TerminateHandler;
+
+ llvm::BasicBlock *Cont = 0;
+
+ if (HaveInsertPoint()) {
+ Cont = createBasicBlock("cont");
+ EmitBranch(Cont);
+ }
+
+ llvm::Constant *Personality =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
+ (VMContext),
+ true),
+ "__gxx_personality_v0");
+ Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
+ llvm::Value *llvm_eh_exception =
+ CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
+ llvm::Value *llvm_eh_selector =
+ CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
+
+ // Set up terminate handler
+ TerminateHandler = createBasicBlock("terminate.handler");
+ EmitBlock(TerminateHandler);
+ llvm::Value *Exc = 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(Personality);
+ Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+ 1));
+ Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
+ llvm::CallInst *TerminateCall =
+ Builder.CreateCall(getTerminateFn(*this));
+ TerminateCall->setDoesNotReturn();
+ TerminateCall->setDoesNotThrow();
+ Builder.CreateUnreachable();
+
+ // Clear the insertion point to indicate we are in unreachable code.
+ Builder.ClearInsertionPoint();
+
+ if (Cont)
+ EmitBlock(Cont);
+
+ return TerminateHandler;
}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 63fca2d..e6bbfa8 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -17,6 +17,8 @@
#include "CGObjCRuntime.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
+#include "llvm/Intrinsics.h"
+#include "clang/CodeGen/CodeGenOptions.h"
#include "llvm/Target/TargetData.h"
using namespace clang;
using namespace CodeGen;
@@ -38,6 +40,21 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty,
/// expression and compare the result against zero, returning an Int1Ty value.
llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) {
QualType BoolTy = getContext().BoolTy;
+ if (E->getType()->isMemberFunctionPointerType()) {
+ llvm::Value *Ptr = CreateTempAlloca(ConvertType(E->getType()));
+ EmitAggExpr(E, Ptr, /*VolatileDest=*/false);
+
+ // Get the pointer.
+ llvm::Value *FuncPtr = Builder.CreateStructGEP(Ptr, 0, "src.ptr");
+ FuncPtr = Builder.CreateLoad(FuncPtr);
+
+ llvm::Value *IsNotNull =
+ Builder.CreateICmpNE(FuncPtr,
+ llvm::Constant::getNullValue(FuncPtr->getType()),
+ "tobool");
+
+ return IsNotNull;
+ }
if (!E->getType()->isAnyComplexType())
return EmitScalarConversion(EmitScalarExpr(E), E->getType(), BoolTy);
@@ -137,8 +154,19 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
const CXXDestructorDecl *Dtor =
ClassDecl->getDestructor(getContext());
- DelayedCleanupBlock scope(*this);
- EmitCXXDestructorCall(Dtor, Dtor_Complete, Val.getAggregateAddr());
+ {
+ DelayedCleanupBlock Scope(*this);
+ EmitCXXDestructorCall(Dtor, Dtor_Complete,
+ Val.getAggregateAddr());
+
+ // Make sure to jump to the exit block.
+ EmitBranch(Scope.getCleanupExitBlock());
+ }
+ if (Exceptions) {
+ EHCleanupBlock Cleanup(*this);
+ EmitCXXDestructorCall(Dtor, Dtor_Complete,
+ Val.getAggregateAddr());
+ }
}
}
}
@@ -237,6 +265,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
switch (E->getStmtClass()) {
default: return EmitUnsupportedLValue(E, "l-value expression");
+ case Expr::ObjCIsaExprClass:
+ return EmitObjCIsaExpr(cast<ObjCIsaExpr>(E));
case Expr::BinaryOperatorClass:
return EmitBinaryOperatorLValue(cast<BinaryOperator>(E));
case Expr::CallExprClass:
@@ -330,13 +360,8 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
if (Ty->isBooleanType()) {
// Bool can have different representation in memory than in registers.
- const llvm::Type *SrcTy = Value->getType();
const llvm::PointerType *DstPtr = cast<llvm::PointerType>(Addr->getType());
- if (DstPtr->getElementType() != SrcTy) {
- const llvm::Type *MemTy =
- llvm::PointerType::get(SrcTy, DstPtr->getAddressSpace());
- Addr = Builder.CreateBitCast(Addr, MemTy, "storetmp");
- }
+ Value = Builder.CreateIntCast(Value, DstPtr->getElementType(), false);
}
Builder.CreateStore(Value, Addr, Volatile);
}
@@ -408,8 +433,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV,
// Shift to proper location.
if (StartBit)
- Val = Builder.CreateLShr(Val, llvm::ConstantInt::get(EltTy, StartBit),
- "bf.lo");
+ Val = Builder.CreateLShr(Val, StartBit, "bf.lo");
// Mask off unused bits.
llvm::Constant *LowMask = llvm::ConstantInt::get(VMContext,
@@ -431,8 +455,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV,
HighVal = Builder.CreateAnd(HighVal, HighMask, "bf.lo.cleared");
// Shift to proper location and or in to bitfield value.
- HighVal = Builder.CreateShl(HighVal,
- llvm::ConstantInt::get(EltTy, LowBits));
+ HighVal = Builder.CreateShl(HighVal, LowBits);
Val = Builder.CreateOr(Val, HighVal, "bf.val");
}
@@ -618,8 +641,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
// LowVal = (LowVal & InvMask) | (NewVal << StartBit),
// with the shift of NewVal implicitly stripping the high bits.
llvm::Value *NewLowVal =
- Builder.CreateShl(NewVal, llvm::ConstantInt::get(EltTy, StartBit),
- "bf.value.lo");
+ Builder.CreateShl(NewVal, StartBit, "bf.value.lo");
LowVal = Builder.CreateAnd(LowVal, InvMask, "bf.prev.lo.cleared");
LowVal = Builder.CreateOr(LowVal, NewLowVal, "bf.new.lo");
@@ -645,8 +667,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
// where the high bits of NewVal have already been cleared and the
// shift stripping the low bits.
llvm::Value *NewHighVal =
- Builder.CreateLShr(NewVal, llvm::ConstantInt::get(EltTy, LowBits),
- "bf.value.high");
+ Builder.CreateLShr(NewVal, LowBits, "bf.value.high");
HighVal = Builder.CreateAnd(HighVal, InvMask, "bf.prev.hi.cleared");
HighVal = Builder.CreateOr(HighVal, NewHighVal, "bf.new.hi");
@@ -993,6 +1014,36 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
}
}
+llvm::BasicBlock *CodeGenFunction::getTrapBB() {
+ const CodeGenOptions &GCO = CGM.getCodeGenOpts();
+
+ // If we are not optimzing, don't collapse all calls to trap in the function
+ // to the same call, that way, in the debugger they can see which operation
+ // did in fact fail. If we are optimizing, we collpase all call to trap down
+ // to just one per function to save on codesize.
+ if (GCO.OptimizationLevel
+ && TrapBB)
+ return TrapBB;
+
+ llvm::BasicBlock *Cont = 0;
+ if (HaveInsertPoint()) {
+ Cont = createBasicBlock("cont");
+ EmitBranch(Cont);
+ }
+ TrapBB = createBasicBlock("trap");
+ EmitBlock(TrapBB);
+
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::trap, 0, 0);
+ llvm::CallInst *TrapCall = Builder.CreateCall(F);
+ TrapCall->setDoesNotReturn();
+ TrapCall->setDoesNotThrow();
+ Builder.CreateUnreachable();
+
+ if (Cont)
+ EmitBlock(Cont);
+ return TrapBB;
+}
+
LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
// The index must always be an integer, which is not an aggregate. Emit it.
llvm::Value *Idx = EmitScalarExpr(E->getIdx());
@@ -1021,6 +1072,24 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
llvm::IntegerType::get(VMContext, LLVMPointerWidth),
IdxSigned, "idxprom");
+ if (CatchUndefined) {
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E->getBase())) {
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr())) {
+ if (ICE->getCastKind() == CastExpr::CK_ArrayToPointerDecay) {
+ if (const ConstantArrayType *CAT
+ = getContext().getAsConstantArrayType(DRE->getType())) {
+ llvm::APInt Size = CAT->getSize();
+ llvm::BasicBlock *Cont = createBasicBlock("cont");
+ Builder.CreateCondBr(Builder.CreateICmpULE(Idx,
+ llvm::ConstantInt::get(Idx->getType(), Size)),
+ Cont, getTrapBB());
+ EmitBlock(Cont);
+ }
+ }
+ }
+ }
+ }
+
// We know that the pointer points to a type of the correct size, unless the
// size is a VLA or Objective-C interface.
llvm::Value *Address = 0;
@@ -1417,7 +1486,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) {
if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(TargetDecl))
return EmitCXXOperatorMemberCallExpr(CE, MD);
- if (isa<CXXPseudoDestructorExpr>(E->getCallee())) {
+ if (isa<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) {
// C++ [expr.pseudo]p1:
// The result shall only be used as the operand for the function call
// operator (), and the result of such a call has type void. The only
@@ -1436,6 +1505,7 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
// Comma expressions just emit their LHS then their RHS as an l-value.
if (E->getOpcode() == BinaryOperator::Comma) {
EmitAnyExpr(E->getLHS());
+ EnsureInsertPoint();
return EmitLValue(E->getRHS());
}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index d225d90..2c122eb 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -120,7 +120,7 @@ public:
void EmitInitializationToLValue(Expr *E, LValue Address);
void EmitNullInitializationToLValue(LValue Address, QualType T);
// case Expr::ChooseExprClass:
-
+ void VisitCXXThrowExpr(const CXXThrowExpr *E) { CGF.EmitCXXThrowExpr(E); }
};
} // end anonymous namespace.
@@ -502,21 +502,16 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) {
void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
#if 0
- // FIXME: Disabled while we figure out what to do about
- // test/CodeGen/bitfield.c
+ // FIXME: Assess perf here? Figure out what cases are worth optimizing here
+ // (Length of globals? Chunks of zeroed-out space?).
//
// If we can, prefer a copy from a global; this is a lot less code for long
// globals, and it's easier for the current optimizers to analyze.
- // FIXME: Should we really be doing this? Should we try to avoid cases where
- // we emit a global with a lot of zeros? Should we try to avoid short
- // globals?
- if (E->isConstantInitializer(CGF.getContext(), 0)) {
- llvm::Constant* C = CGF.CGM.EmitConstantExpr(E, &CGF);
+ if (llvm::Constant* C = CGF.CGM.EmitConstantExpr(E, E->getType(), &CGF)) {
llvm::GlobalVariable* GV =
- new llvm::GlobalVariable(C->getType(), true,
- llvm::GlobalValue::InternalLinkage,
- C, "", &CGF.CGM.getModule(), 0);
- EmitFinalDestCopy(E, LValue::MakeAddr(GV, 0));
+ new llvm::GlobalVariable(CGF.CGM.getModule(), C->getType(), true,
+ llvm::GlobalValue::InternalLinkage, C, "");
+ EmitFinalDestCopy(E, LValue::MakeAddr(GV, Qualifiers()));
return;
}
#endif
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index b982c15..150f11e 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -15,13 +15,8 @@
using namespace clang;
using namespace CodeGen;
-static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) {
- if (!E->isArray())
- return 0;
-
- QualType T = E->getAllocatedType();
-
- const RecordType *RT = T->getAs<RecordType>();
+static uint64_t CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) {
+ const RecordType *RT = ElementType->getAs<RecordType>();
if (!RT)
return 0;
@@ -31,13 +26,59 @@ static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) {
// Check if the class has a trivial destructor.
if (RD->hasTrivialDestructor()) {
- // FIXME: Check for a two-argument delete.
- return 0;
- }
+ // Check if the usual deallocation function takes two arguments.
+ const CXXMethodDecl *UsualDeallocationFunction = 0;
+
+ DeclarationName OpName =
+ Ctx.DeclarationNames.getCXXOperatorName(OO_Array_Delete);
+ DeclContext::lookup_const_iterator Op, OpEnd;
+ for (llvm::tie(Op, OpEnd) = RD->lookup(OpName);
+ Op != OpEnd; ++Op) {
+ const CXXMethodDecl *Delete = cast<CXXMethodDecl>(*Op);
+
+ if (Delete->isUsualDeallocationFunction()) {
+ UsualDeallocationFunction = Delete;
+ break;
+ }
+ }
+
+ // No usual deallocation function, we don't need a cookie.
+ if (!UsualDeallocationFunction)
+ return 0;
+
+ // The usual deallocation function doesn't take a size_t argument, so we
+ // don't need a cookie.
+ if (UsualDeallocationFunction->getNumParams() == 1)
+ return 0;
+
+ assert(UsualDeallocationFunction->getNumParams() == 2 &&
+ "Unexpected deallocation function type!");
+ }
- // Padding is the maximum of sizeof(size_t) and alignof(T)
+ // Padding is the maximum of sizeof(size_t) and alignof(ElementType)
return std::max(Ctx.getTypeSize(Ctx.getSizeType()),
- static_cast<uint64_t>(Ctx.getTypeAlign(T))) / 8;
+ static_cast<uint64_t>(Ctx.getTypeAlign(ElementType))) / 8;
+}
+
+static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) {
+ if (!E->isArray())
+ return 0;
+
+ // No cookie is required if the new operator being used is
+ // ::operator new[](size_t, void*).
+ const FunctionDecl *OperatorNew = E->getOperatorNew();
+ if (OperatorNew->getDeclContext()->getLookupContext()->isFileContext()) {
+ if (OperatorNew->getNumParams() == 2) {
+ CanQualType ParamType =
+ Ctx.getCanonicalType(OperatorNew->getParamDecl(1)->getType());
+
+ if (ParamType == Ctx.VoidPtrTy)
+ return 0;
+ }
+ }
+
+ return CalculateCookiePadding(Ctx, E->getAllocatedType());
+ QualType T = E->getAllocatedType();
}
static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
@@ -237,6 +278,39 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
return NewPtr;
}
+static std::pair<llvm::Value *, llvm::Value *>
+GetAllocatedObjectPtrAndNumElements(CodeGenFunction &CGF,
+ llvm::Value *Ptr, QualType DeleteTy) {
+ QualType SizeTy = CGF.getContext().getSizeType();
+ const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy);
+
+ uint64_t DeleteTypeAlign = CGF.getContext().getTypeAlign(DeleteTy);
+ uint64_t CookiePadding = std::max(CGF.getContext().getTypeSize(SizeTy),
+ DeleteTypeAlign) / 8;
+ assert(CookiePadding && "CookiePadding should not be 0.");
+
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ uint64_t CookieOffset =
+ CookiePadding - CGF.getContext().getTypeSize(SizeTy) / 8;
+
+ llvm::Value *AllocatedObjectPtr = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
+ AllocatedObjectPtr =
+ CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr,
+ -CookiePadding);
+
+ llvm::Value *NumElementsPtr =
+ CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr,
+ CookieOffset);
+ NumElementsPtr =
+ CGF.Builder.CreateBitCast(NumElementsPtr, SizeLTy->getPointerTo());
+
+ llvm::Value *NumElements = CGF.Builder.CreateLoad(NumElementsPtr);
+ NumElements =
+ CGF.Builder.CreateIntCast(NumElements, SizeLTy, /*isSigned=*/false);
+
+ return std::make_pair(AllocatedObjectPtr, NumElements);
+}
+
void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
llvm::Value *Ptr,
QualType DeleteTy) {
@@ -245,17 +319,37 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
CallArgList DeleteArgs;
+ // Check if we need to pass the size to the delete operator.
+ llvm::Value *Size = 0;
+ QualType SizeTy;
+ if (DeleteFTy->getNumArgs() == 2) {
+ SizeTy = DeleteFTy->getArgType(1);
+ uint64_t DeleteTypeSize = getContext().getTypeSize(DeleteTy) / 8;
+ Size = llvm::ConstantInt::get(ConvertType(SizeTy), DeleteTypeSize);
+ }
+
+ if (DeleteFD->getOverloadedOperator() == OO_Array_Delete &&
+
+ CalculateCookiePadding(getContext(), DeleteTy)) {
+ // We need to get the number of elements in the array from the cookie.
+ llvm::Value *AllocatedObjectPtr;
+ llvm::Value *NumElements;
+ llvm::tie(AllocatedObjectPtr, NumElements) =
+ GetAllocatedObjectPtrAndNumElements(*this, Ptr, DeleteTy);
+
+ // Multiply the size with the number of elements.
+ if (Size)
+ Size = Builder.CreateMul(NumElements, Size);
+
+ Ptr = AllocatedObjectPtr;
+ }
+
QualType ArgTy = DeleteFTy->getArgType(0);
llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));
DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy));
- if (DeleteFTy->getNumArgs() == 2) {
- QualType SizeTy = DeleteFTy->getArgType(1);
- uint64_t SizeVal = getContext().getTypeSize(DeleteTy) / 8;
- llvm::Constant *Size = llvm::ConstantInt::get(ConvertType(SizeTy),
- SizeVal);
+ if (Size)
DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy));
- }
// Emit the call to delete.
EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(),
@@ -300,34 +394,13 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
if (!RD->hasTrivialDestructor()) {
const CXXDestructorDecl *Dtor = RD->getDestructor(getContext());
if (E->isArrayForm()) {
- QualType SizeTy = getContext().getSizeType();
- uint64_t CookiePadding = std::max(getContext().getTypeSize(SizeTy),
- static_cast<uint64_t>(getContext().getTypeAlign(DeleteTy))) / 8;
- if (CookiePadding) {
- llvm::Type *Ptr8Ty =
- llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
- uint64_t CookieOffset =
- CookiePadding - getContext().getTypeSize(SizeTy) / 8;
- llvm::Value *AllocatedObjectPtr =
- Builder.CreateConstInBoundsGEP1_64(
- Builder.CreateBitCast(Ptr, Ptr8Ty), -CookiePadding);
- llvm::Value *NumElementsPtr =
- Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr,
- CookieOffset);
- NumElementsPtr = Builder.CreateBitCast(NumElementsPtr,
- ConvertType(SizeTy)->getPointerTo());
-
- llvm::Value *NumElements =
- Builder.CreateLoad(NumElementsPtr);
- NumElements =
- Builder.CreateIntCast(NumElements,
- llvm::Type::getInt64Ty(VMContext), false,
- "count.tmp");
- EmitCXXAggrDestructorCall(Dtor, NumElements, Ptr);
- Ptr = AllocatedObjectPtr;
- }
- }
- else if (Dtor->isVirtual()) {
+ llvm::Value *AllocatedObjectPtr;
+ llvm::Value *NumElements;
+ llvm::tie(AllocatedObjectPtr, NumElements) =
+ GetAllocatedObjectPtrAndNumElements(*this, Ptr, DeleteTy);
+
+ EmitCXXAggrDestructorCall(Dtor, NumElements, Ptr);
+ } else if (Dtor->isVirtual()) {
const llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(Dtor),
/*isVariadic=*/false);
@@ -352,18 +425,10 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
QualType Ty = E->getType();
const llvm::Type *LTy = ConvertType(Ty)->getPointerTo();
- if (E->isTypeOperand()) {
- Ty = E->getTypeOperand();
- CanQualType CanTy = CGM.getContext().getCanonicalType(Ty);
- Ty = CanTy.getUnqualifiedType().getNonReferenceType();
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->isPolymorphic())
- return Builder.CreateBitCast(CGM.GenerateRttiRef(RD), LTy);
- return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy);
- }
- return Builder.CreateBitCast(CGM.GenerateRtti(Ty), LTy);
- }
+
+ if (E->isTypeOperand())
+ return Builder.CreateBitCast(CGM.GetAddrOfRTTI(E->getTypeOperand()), LTy);
+
Expr *subE = E->getExprOperand();
Ty = subE->getType();
CanQualType CanTy = CGM.getContext().getCanonicalType(Ty);
@@ -404,9 +469,9 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
V = Builder.CreateLoad(V);
return V;
}
- return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy);
+ return Builder.CreateBitCast(CGM.GenerateRTTI(RD), LTy);
}
- return Builder.CreateBitCast(CGM.GenerateRtti(Ty), LTy);
+ return Builder.CreateBitCast(CGM.GenerateRTTI(Ty), LTy);
}
llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
@@ -485,8 +550,8 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
// FIXME: Calculate better hint.
llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL);
- llvm::Value *SrcArg = CGM.GenerateRttiRef(SrcTy);
- llvm::Value *DstArg = CGM.GenerateRttiRef(DstTy);
+ llvm::Value *SrcArg = CGM.GenerateRTTIRef(SrcTy);
+ llvm::Value *DstArg = CGM.GenerateRTTIRef(DstTy);
V = Builder.CreateBitCast(V, PtrToInt8Ty);
V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"),
V, SrcArg, DstArg, hint);
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 9289f78..d428983 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -167,7 +167,11 @@ class ConstStructBuilder {
}
// Or in the bits that go into the previous byte.
- Tmp |= cast<llvm::ConstantInt>(Elements.back())->getValue();
+ if (llvm::ConstantInt *Val = dyn_cast<llvm::ConstantInt>(Elements.back()))
+ Tmp |= Val->getValue();
+ else
+ assert(isa<llvm::UndefValue>(Elements.back()));
+
Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp);
if (FitsCompletelyInPreviousByte)
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index c1cbecc..2f31c05 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -167,6 +167,12 @@ public:
return CGF.EmitObjCMessageExpr(E).getScalarVal();
}
+ Value *VisitObjCIsaExpr(ObjCIsaExpr *E) {
+ LValue LV = CGF.EmitObjCIsaExpr(E);
+ Value *V = CGF.EmitLoadOfLValue(LV, E->getType()).getScalarVal();
+ return V;
+ }
+
Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E);
Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E);
Value *VisitMemberExpr(MemberExpr *E);
@@ -257,6 +263,10 @@ public:
CGF.EmitCXXDeleteExpr(E);
return 0;
}
+ Value *VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) {
+ return llvm::ConstantInt::get(Builder.getInt1Ty(),
+ E->EvaluateTrait(CGF.getContext()));
+ }
Value *VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E) {
// C++ [expr.pseudo]p1:
@@ -798,6 +808,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
//assert(0 && "Unknown cast kind!");
break;
+ case CastExpr::CK_AnyPointerToObjCPointerCast:
+ case CastExpr::CK_AnyPointerToBlockPointerCast:
case CastExpr::CK_BitCast: {
Value *Src = Visit(const_cast<Expr*>(E));
return Builder.CreateBitCast(Src, ConvertType(DestTy));
@@ -943,34 +955,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
case CastExpr::CK_FloatingCast:
return EmitScalarConversion(Visit(E), E->getType(), DestTy);
- case CastExpr::CK_MemberPointerToBoolean: {
- const MemberPointerType* T = E->getType()->getAs<MemberPointerType>();
-
- if (T->getPointeeType()->isFunctionType()) {
- // We have a member function pointer.
- llvm::Value *Ptr = CGF.CreateTempAlloca(ConvertType(E->getType()));
-
- CGF.EmitAggExpr(E, Ptr, /*VolatileDest=*/false);
-
- // Get the pointer.
- llvm::Value *FuncPtr = Builder.CreateStructGEP(Ptr, 0, "src.ptr");
- FuncPtr = Builder.CreateLoad(FuncPtr);
-
- llvm::Value *IsNotNull =
- Builder.CreateICmpNE(FuncPtr,
- llvm::Constant::getNullValue(FuncPtr->getType()),
- "tobool");
-
- return IsNotNull;
- }
-
- // We have a regular member pointer.
- Value *Ptr = Visit(const_cast<Expr*>(E));
- llvm::Value *IsNotNull =
- Builder.CreateICmpNE(Ptr, CGF.CGM.EmitNullConstant(E->getType()),
- "tobool");
- return IsNotNull;
- }
+ case CastExpr::CK_MemberPointerToBoolean:
+ return CGF.EvaluateExprAsBool(E);
}
// Handle cases where the source is an non-complex type.
@@ -1540,6 +1526,16 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
+ if (CGF.CatchUndefined
+ && isa<llvm::IntegerType>(Ops.LHS->getType())) {
+ unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth();
+ llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
+ CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS,
+ llvm::ConstantInt::get(RHS->getType(), Width)),
+ Cont, CGF.getTrapBB());
+ CGF.EmitBlock(Cont);
+ }
+
return Builder.CreateShl(Ops.LHS, RHS, "shl");
}
@@ -1550,6 +1546,16 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
+ if (CGF.CatchUndefined
+ && isa<llvm::IntegerType>(Ops.LHS->getType())) {
+ unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth();
+ llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
+ CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS,
+ llvm::ConstantInt::get(RHS->getType(), Width)),
+ Cont, CGF.getTrapBB());
+ CGF.EmitBlock(Cont);
+ }
+
if (Ops.Ty->isUnsignedIntegerType())
return Builder.CreateLShr(Ops.LHS, RHS, "shr");
return Builder.CreateAShr(Ops.LHS, RHS, "shr");
@@ -1560,7 +1566,34 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
TestAndClearIgnoreResultAssign();
Value *Result;
QualType LHSTy = E->getLHS()->getType();
- if (!LHSTy->isAnyComplexType()) {
+ if (LHSTy->isMemberFunctionPointerType()) {
+ Value *LHSPtr = CGF.EmitAnyExprToTemp(E->getLHS()).getAggregateAddr();
+ Value *RHSPtr = CGF.EmitAnyExprToTemp(E->getRHS()).getAggregateAddr();
+ llvm::Value *LHSFunc = Builder.CreateStructGEP(LHSPtr, 0);
+ LHSFunc = Builder.CreateLoad(LHSFunc);
+ llvm::Value *RHSFunc = Builder.CreateStructGEP(RHSPtr, 0);
+ RHSFunc = Builder.CreateLoad(RHSFunc);
+ Value *ResultF = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc,
+ LHSFunc, RHSFunc, "cmp.func");
+ Value *NullPtr = llvm::Constant::getNullValue(LHSFunc->getType());
+ Value *ResultNull = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc,
+ LHSFunc, NullPtr, "cmp.null");
+ llvm::Value *LHSAdj = Builder.CreateStructGEP(LHSPtr, 1);
+ LHSAdj = Builder.CreateLoad(LHSAdj);
+ llvm::Value *RHSAdj = Builder.CreateStructGEP(RHSPtr, 1);
+ RHSAdj = Builder.CreateLoad(RHSAdj);
+ Value *ResultA = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc,
+ LHSAdj, RHSAdj, "cmp.adj");
+ if (E->getOpcode() == BinaryOperator::EQ) {
+ Result = Builder.CreateOr(ResultNull, ResultA, "or.na");
+ Result = Builder.CreateAnd(Result, ResultF, "and.f");
+ } else {
+ assert(E->getOpcode() == BinaryOperator::NE &&
+ "Member pointer comparison other than == or != ?");
+ Result = Builder.CreateAnd(ResultNull, ResultA, "and.na");
+ Result = Builder.CreateOr(Result, ResultF, "or.f");
+ }
+ } else if (!LHSTy->isAnyComplexType()) {
Value *LHS = Visit(E->getLHS());
Value *RHS = Visit(E->getRHS());
@@ -1868,10 +1901,11 @@ VisitConditionalOperator(const ConditionalOperator *E) {
CGF.EmitBlock(ContBlock);
- if (!LHS || !RHS) {
- assert(E->getType()->isVoidType() && "Non-void value should have a value");
- return 0;
- }
+ // If the LHS or RHS is a throw expression, it will be legitimately null.
+ if (!LHS)
+ return RHS;
+ if (!RHS)
+ return LHS;
// Create a PHI node for the real part.
llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), "cond");
@@ -1976,3 +2010,22 @@ llvm::Value *CodeGenFunction::EmitVector(llvm::Value * const *Vals,
return Vec;
}
+
+LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
+ llvm::Value *V;
+ // object->isa or (*object).isa
+ // Generate code as for: *(Class*)object
+ Expr *BaseExpr = E->getBase();
+ if (E->isArrow())
+ V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr);
+ else
+ V = EmitLValue(BaseExpr).getAddress();
+
+ // build Class* type
+ const llvm::Type *ClassPtrTy = ConvertType(E->getType());
+ ClassPtrTy = ClassPtrTy->getPointerTo();
+ V = Builder.CreateBitCast(V, ClassPtrTy);
+ LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType()));
+ return LV;
+}
+
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 2e8ab29..fb920f0 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -28,6 +28,7 @@
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetData.h"
#include <cstdio>
@@ -905,6 +906,13 @@ protected:
const ObjCContainerDecl *OCD,
const ObjCCommonTypesHelper &ObjCTypes);
+ /// PushProtocolProperties - Push protocol's property on the input stack.
+ void PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet,
+ std::vector<llvm::Constant*> &Properties,
+ const Decl *Container,
+ const ObjCProtocolDecl *PROTO,
+ const ObjCCommonTypesHelper &ObjCTypes);
+
/// GetProtocolRef - Return a reference to the internal protocol
/// description, creating an empty one if it has not been
/// defined. The return value has type ProtocolPtrTy.
@@ -1793,6 +1801,26 @@ CGObjCMac::EmitProtocolList(llvm::Twine Name,
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListPtrTy);
}
+void CGObjCCommonMac::PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet,
+ std::vector<llvm::Constant*> &Properties,
+ const Decl *Container,
+ const ObjCProtocolDecl *PROTO,
+ const ObjCCommonTypesHelper &ObjCTypes) {
+ std::vector<llvm::Constant*> Prop(2);
+ for (ObjCProtocolDecl::protocol_iterator P = PROTO->protocol_begin(),
+ E = PROTO->protocol_end(); P != E; ++P)
+ PushProtocolProperties(PropertySet, Properties, Container, (*P), ObjCTypes);
+ for (ObjCContainerDecl::prop_iterator I = PROTO->prop_begin(),
+ E = PROTO->prop_end(); I != E; ++I) {
+ const ObjCPropertyDecl *PD = *I;
+ if (!PropertySet.insert(PD->getIdentifier()))
+ continue;
+ Prop[0] = GetPropertyName(PD->getIdentifier());
+ Prop[1] = GetPropertyTypeString(PD, Container);
+ Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy, Prop));
+ }
+}
+
/*
struct _objc_property {
const char * const name;
@@ -1810,14 +1838,20 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(llvm::Twine Name,
const ObjCContainerDecl *OCD,
const ObjCCommonTypesHelper &ObjCTypes) {
std::vector<llvm::Constant*> Properties, Prop(2);
+ llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet;
for (ObjCContainerDecl::prop_iterator I = OCD->prop_begin(),
E = OCD->prop_end(); I != E; ++I) {
const ObjCPropertyDecl *PD = *I;
+ PropertySet.insert(PD->getIdentifier());
Prop[0] = GetPropertyName(PD->getIdentifier());
Prop[1] = GetPropertyTypeString(PD, Container);
Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy,
Prop));
}
+ if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD))
+ for (ObjCInterfaceDecl::protocol_iterator P = OID->protocol_begin(),
+ E = OID->protocol_end(); P != E; ++P)
+ PushProtocolProperties(PropertySet, Properties, Container, (*P), ObjCTypes);
// Return null for empty list.
if (Properties.empty())
@@ -2507,8 +2541,11 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// through finally.
CGF.PushCleanupBlock(FinallyBlock);
- CGF.ObjCEHValueStack.push_back(0);
-
+ if (CGF.ObjCEHValueStack.empty())
+ CGF.ObjCEHValueStack.push_back(0);
+ // If This is a nested @try, caught exception is that of enclosing @try.
+ else
+ CGF.ObjCEHValueStack.push_back(CGF.ObjCEHValueStack.back());
// Allocate memory for the exception data and rethrow pointer.
llvm::Value *ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy,
"exceptiondata.ptr");
@@ -4134,23 +4171,19 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
"\01L_OBJC_LABEL_CLASS_$",
"__DATA, __objc_classlist, regular, no_dead_strip");
- bool hasWeakImport = false;
for (unsigned i = 0; i < DefinedClasses.size(); i++) {
llvm::GlobalValue *IMPLGV = DefinedClasses[i];
if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage)
continue;
IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage);
- hasWeakImport = true;
}
- if (hasWeakImport) {
- for (unsigned i = 0; i < DefinedMetaClasses.size(); i++) {
- llvm::GlobalValue *IMPLGV = DefinedMetaClasses[i];
- if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage)
- continue;
- IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage);
- }
- }
+ for (unsigned i = 0; i < DefinedMetaClasses.size(); i++) {
+ llvm::GlobalValue *IMPLGV = DefinedMetaClasses[i];
+ if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage)
+ continue;
+ IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ }
AddModuleClassList(DefinedNonLazyClasses,
"\01L_OBJC_LABEL_NONLAZY_CLASS_$",
@@ -4437,9 +4470,12 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
Root = Super;
IsAGV = GetClassGlobal(ObjCMetaClassName + Root->getNameAsString());
+ if (Root->hasAttr<WeakImportAttr>())
+ IsAGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
// work on super class metadata symbol.
std::string SuperClassName =
- ObjCMetaClassName + ID->getClassInterface()->getSuperClass()->getNameAsString();
+ ObjCMetaClassName +
+ ID->getClassInterface()->getSuperClass()->getNameAsString();
SuperClassGV = GetClassGlobal(SuperClassName);
if (ID->getClassInterface()->getSuperClass()->hasAttr<WeakImportAttr>())
SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
diff --git a/lib/CodeGen/CGRtti.cpp b/lib/CodeGen/CGRTTI.cpp
index 43fcb31..02de00e 100644
--- a/lib/CodeGen/CGRtti.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -1,4 +1,4 @@
-//===--- CGCXXRtti.cpp - Emit LLVM Code for C++ RTTI descriptors ----------===//
+//===--- CGCXXRTTI.cpp - Emit LLVM Code for C++ RTTI descriptors ----------===//
//
// The LLVM Compiler Infrastructure
//
@@ -17,14 +17,35 @@
using namespace clang;
using namespace CodeGen;
-class RttiBuilder {
+namespace {
+class RTTIBuilder {
CodeGenModule &CGM; // Per-module state.
llvm::LLVMContext &VMContext;
const llvm::Type *Int8PtrTy;
llvm::SmallSet<const CXXRecordDecl *, 16> SeenVBase;
llvm::SmallSet<const CXXRecordDecl *, 32> SeenBase;
+
+ // Type info flags.
+ enum {
+ /// TI_Const - Type has const qualifier.
+ TI_Const = 0x1,
+
+ /// TI_Volatile - Type has volatile qualifier.
+ TI_Volatile = 0x2,
+
+ /// TI_Restrict - Type has restrict qualifier.
+ TI_Restrict = 0x4,
+
+ /// TI_Incomplete - Type is incomplete.
+ TI_Incomplete = 0x8,
+
+ /// TI_ContainingClassIncomplete - Containing class is incomplete.
+ /// (in pointer to member).
+ TI_ContainingClassIncomplete = 0x10
+ };
+
public:
- RttiBuilder(CodeGenModule &cgm)
+ RTTIBuilder(CodeGenModule &cgm)
: CGM(cgm), VMContext(cgm.getModule().getContext()),
Int8PtrTy(llvm::Type::getInt8PtrTy(VMContext)) { }
@@ -47,27 +68,37 @@ public:
return llvm::ConstantExpr::getBitCast(C, Int8PtrTy);
}
+ // FIXME: This should be removed, and clients should pass in the linkage
+ // directly instead.
+ static inline llvm::GlobalVariable::LinkageTypes
+ GetLinkageFromExternFlag(bool Extern) {
+ if (Extern)
+ return llvm::GlobalValue::WeakODRLinkage;
+
+ return llvm::GlobalValue::InternalLinkage;
+ }
+
+ // FIXME: This should be removed, and clients should pass in the linkage
+ // directly instead.
llvm::Constant *BuildName(QualType Ty, bool Hidden, bool Extern) {
+ return BuildName(Ty, Hidden, GetLinkageFromExternFlag(Extern));
+ }
+
+ llvm::Constant *BuildName(QualType Ty, bool Hidden,
+ llvm::GlobalVariable::LinkageTypes Linkage) {
llvm::SmallString<256> OutName;
- CGM.getMangleContext().mangleCXXRttiName(Ty, OutName);
+ CGM.getMangleContext().mangleCXXRTTIName(Ty, OutName);
llvm::StringRef Name = OutName.str();
- llvm::GlobalVariable::LinkageTypes linktype;
- linktype = llvm::GlobalValue::LinkOnceODRLinkage;
- if (!Extern)
- linktype = llvm::GlobalValue::InternalLinkage;
-
- llvm::GlobalVariable *GV;
- GV = CGM.getModule().getGlobalVariable(Name);
- if (GV && !GV->isDeclaration())
- return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+ llvm::GlobalVariable *OGV = CGM.getModule().getGlobalVariable(Name);
+ if (OGV && !OGV->isDeclaration())
+ return llvm::ConstantExpr::getBitCast(OGV, Int8PtrTy);
- llvm::Constant *C;
- C = llvm::ConstantArray::get(VMContext, Name.substr(4));
+ llvm::Constant *C = llvm::ConstantArray::get(VMContext, Name.substr(4));
- llvm::GlobalVariable *OGV = GV;
- GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, linktype,
- C, Name);
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, Linkage,
+ C, Name);
if (OGV) {
GV->takeName(OGV);
llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV,
@@ -94,11 +125,8 @@ public:
llvm::Constant *BuildTypeRef(QualType Ty) {
llvm::Constant *C;
- if (!CGM.getContext().getLangOptions().Rtti)
- return llvm::Constant::getNullValue(Int8PtrTy);
-
llvm::SmallString<256> OutName;
- CGM.getMangleContext().mangleCXXRtti(Ty, OutName);
+ CGM.getMangleContext().mangleCXXRTTI(Ty, OutName);
llvm::StringRef Name = OutName.str();
C = CGM.getModule().getGlobalVariable(Name);
@@ -158,19 +186,15 @@ public:
return true;
}
- llvm::Constant *finish(std::vector<llvm::Constant *> &info,
+ llvm::Constant *finish(llvm::Constant *const *Values, unsigned NumValues,
llvm::GlobalVariable *GV,
- llvm::StringRef Name, bool Hidden, bool Extern) {
- llvm::GlobalVariable::LinkageTypes linktype;
- linktype = llvm::GlobalValue::LinkOnceODRLinkage;
- if (!Extern)
- linktype = llvm::GlobalValue::InternalLinkage;
-
- llvm::Constant *C;
- C = llvm::ConstantStruct::get(VMContext, &info[0], info.size(), false);
+ llvm::StringRef Name, bool Hidden,
+ llvm::GlobalVariable::LinkageTypes Linkage) {
+ llvm::Constant *C =
+ llvm::ConstantStruct::get(VMContext, Values, NumValues, /*Packed=*/false);
llvm::GlobalVariable *OGV = GV;
- GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, linktype,
+ GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, Linkage,
C, Name);
if (OGV) {
GV->takeName(OGV);
@@ -185,14 +209,16 @@ public:
}
- llvm::Constant *Buildclass_type_info(const CXXRecordDecl *RD) {
- if (!CGM.getContext().getLangOptions().Rtti)
- return llvm::Constant::getNullValue(Int8PtrTy);
-
+ llvm::Constant *
+ Buildclass_type_info(const CXXRecordDecl *RD,
+ llvm::GlobalVariable::LinkageTypes Linkage) {
+ std::vector<llvm::Constant *> info;
+ assert(info.empty() && "Info vector must be empty!");
+
llvm::Constant *C;
llvm::SmallString<256> OutName;
- CGM.getMangleContext().mangleCXXRtti(CGM.getContext().getTagDeclType(RD),
+ CGM.getMangleContext().mangleCXXRTTI(CGM.getContext().getTagDeclType(RD),
OutName);
llvm::StringRef Name = OutName.str();
@@ -201,10 +227,11 @@ public:
if (GV && !GV->isDeclaration())
return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
- std::vector<llvm::Constant *> info;
-
+ // If we're in an anonymous namespace, then we always want internal linkage.
+ if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
+ Linkage = llvm::GlobalVariable::InternalLinkage;
+
bool Hidden = CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden;
- bool Extern = !RD->isInAnonymousNamespace();
bool simple = false;
if (RD->getNumBases() == 0)
@@ -216,7 +243,7 @@ public:
C = BuildVtableRef("_ZTVN10__cxxabiv121__vmi_class_type_infoE");
info.push_back(C);
info.push_back(BuildName(CGM.getContext().getTagDeclType(RD), Hidden,
- Extern));
+ Linkage));
// If we have no bases, there are no more fields.
if (RD->getNumBases()) {
@@ -230,7 +257,7 @@ public:
e = RD->bases_end(); i != e; ++i) {
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- info.push_back(CGM.GenerateRttiRef(Base));
+ info.push_back(CGM.GetAddrOfRTTI(Base));
if (simple)
break;
int64_t offset;
@@ -249,12 +276,12 @@ public:
}
}
- return finish(info, GV, Name, Hidden, Extern);
+ return finish(&info[0], info.size(), GV, Name, Hidden, Linkage);
}
/// - BuildFlags - Build a __flags value for __pbase_type_info.
- llvm::Constant *BuildInt(int f) {
- return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), f);
+ llvm::Constant *BuildInt(unsigned n) {
+ return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), n);
}
bool DecideExtern(QualType Ty) {
@@ -266,7 +293,7 @@ public:
return DecideExtern(PT->getPointeeType());
if (const RecordType *RT = Ty->getAs<RecordType>())
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
- return !RD->isInAnonymousNamespace();
+ return !RD->isInAnonymousNamespace() && RD->hasLinkage();
return true;
}
@@ -284,10 +311,13 @@ public:
}
llvm::Constant *BuildPointerType(QualType Ty) {
+ std::vector<llvm::Constant *> info;
+ assert(info.empty() && "Info vector must be empty!");
+
llvm::Constant *C;
llvm::SmallString<256> OutName;
- CGM.getMangleContext().mangleCXXRtti(Ty, OutName);
+ CGM.getMangleContext().mangleCXXRTTI(Ty, OutName);
llvm::StringRef Name = OutName.str();
llvm::GlobalVariable *GV;
@@ -295,52 +325,58 @@ public:
if (GV && !GV->isDeclaration())
return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
- std::vector<llvm::Constant *> info;
-
bool Extern = DecideExtern(Ty);
bool Hidden = DecideHidden(Ty);
- QualType PTy = Ty->getPointeeType();
- QualType BTy;
- bool PtrMem = false;
- if (const MemberPointerType *MPT = dyn_cast<MemberPointerType>(Ty)) {
- PtrMem = true;
- BTy = QualType(MPT->getClass(), 0);
- PTy = MPT->getPointeeType();
- }
+ const MemberPointerType *PtrMemTy = dyn_cast<MemberPointerType>(Ty);
+ QualType PointeeTy;
+
+ if (PtrMemTy)
+ PointeeTy = PtrMemTy->getPointeeType();
+ else
+ PointeeTy = Ty->getPointeeType();
- if (PtrMem)
+ if (PtrMemTy)
C = BuildVtableRef("_ZTVN10__cxxabiv129__pointer_to_member_type_infoE");
else
C = BuildVtableRef("_ZTVN10__cxxabiv119__pointer_type_infoE");
+
info.push_back(C);
info.push_back(BuildName(Ty, Hidden, Extern));
- Qualifiers Q = PTy.getQualifiers();
- PTy = CGM.getContext().getCanonicalType(PTy).getUnqualifiedType();
- int flags = 0;
- flags += Q.hasConst() ? 0x1 : 0;
- flags += Q.hasVolatile() ? 0x2 : 0;
- flags += Q.hasRestrict() ? 0x4 : 0;
- flags += Ty.getTypePtr()->isIncompleteType() ? 0x8 : 0;
- if (PtrMem && BTy.getTypePtr()->isIncompleteType())
- flags += 0x10;
-
- info.push_back(BuildInt(flags));
+ Qualifiers Q = PointeeTy.getQualifiers();
+
+ PointeeTy =
+ CGM.getContext().getCanonicalType(PointeeTy).getUnqualifiedType();
+
+ unsigned Flags = 0;
+ if (Q.hasConst())
+ Flags |= TI_Const;
+ if (Q.hasVolatile())
+ Flags |= TI_Volatile;
+ if (Q.hasRestrict())
+ Flags |= TI_Restrict;
+
+ if (Ty->isIncompleteType())
+ Flags |= TI_Incomplete;
+
+ if (PtrMemTy && PtrMemTy->getClass()->isIncompleteType())
+ Flags |= TI_ContainingClassIncomplete;
+
+ info.push_back(BuildInt(Flags));
info.push_back(BuildInt(0));
- info.push_back(BuildType(PTy));
+ info.push_back(BuildType(PointeeTy));
- if (PtrMem)
- info.push_back(BuildType(BTy));
+ if (PtrMemTy)
+ info.push_back(BuildType(QualType(PtrMemTy->getClass(), 0)));
// We always generate these as hidden, only the name isn't hidden.
- return finish(info, GV, Name, true, Extern);
+ return finish(&info[0], info.size(), GV, Name, /*Hidden=*/true,
+ GetLinkageFromExternFlag(Extern));
}
llvm::Constant *BuildSimpleType(QualType Ty, const char *vtbl) {
- llvm::Constant *C;
-
llvm::SmallString<256> OutName;
- CGM.getMangleContext().mangleCXXRtti(Ty, OutName);
+ CGM.getMangleContext().mangleCXXRTTI(Ty, OutName);
llvm::StringRef Name = OutName.str();
llvm::GlobalVariable *GV;
@@ -348,26 +384,26 @@ public:
if (GV && !GV->isDeclaration())
return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
- std::vector<llvm::Constant *> info;
-
bool Extern = DecideExtern(Ty);
bool Hidden = DecideHidden(Ty);
- C = BuildVtableRef(vtbl);
- info.push_back(C);
- info.push_back(BuildName(Ty, Hidden, Extern));
-
+ llvm::Constant *Info[] = {
+ BuildVtableRef(vtbl), BuildName(Ty, Hidden, Extern)
+ };
+
// We always generate these as hidden, only the name isn't hidden.
- return finish(info, GV, Name, true, Extern);
+ return finish(&Info[0], llvm::array_lengthof(Info), GV, Name,
+ /*Hidden=*/true, GetLinkageFromExternFlag(Extern));
}
+ /// BuildType - Builds the type info for the given type.
llvm::Constant *BuildType(QualType Ty) {
const clang::Type &Type
= *CGM.getContext().getCanonicalType(Ty).getTypePtr();
if (const RecordType *RT = Ty.getTypePtr()->getAs<RecordType>())
if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()))
- return Buildclass_type_info(RD);
+ return BuildClassTypeInfo(RD);
switch (Type.getTypeClass()) {
default: {
@@ -405,22 +441,65 @@ public:
return BuildSimpleType(Ty, "_ZTVN10__cxxabiv116__enum_type_infoE");
}
}
+
+ /// BuildClassTypeInfo - Builds the class type info (or a reference to it)
+ /// for the given record decl.
+ llvm::Constant *BuildClassTypeInfo(const CXXRecordDecl *RD) {
+ const CXXMethodDecl *KeyFunction = 0;
+
+ if (RD->isDynamicClass())
+ KeyFunction = CGM.getContext().getKeyFunction(RD);
+
+ if (KeyFunction) {
+ // If the key function is defined in this translation unit, then the RTTI
+ // related constants should also be emitted here, with external linkage.
+ if (KeyFunction->getBody())
+ return Buildclass_type_info(RD, llvm::GlobalValue::ExternalLinkage);
+
+ // Otherwise, we just want a reference to the type info.
+ return Buildclass_type_infoRef(RD);
+ }
+
+ // If there is no key function (or if the record doesn't have any virtual
+ // member functions or virtual bases), emit the type info with weak_odr
+ // linkage.
+ return Buildclass_type_info(RD, llvm::GlobalValue::WeakODRLinkage);
+ }
};
+}
+
+llvm::Constant *CodeGenModule::GetAddrOfRTTI(const CXXRecordDecl *RD) {
+ if (!getContext().getLangOptions().RTTI) {
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ return llvm::Constant::getNullValue(Int8PtrTy);
+ }
+
+ return RTTIBuilder(*this).BuildClassTypeInfo(RD);
+}
+
+llvm::Constant *CodeGenModule::GetAddrOfRTTI(QualType Ty) {
+ if (!getContext().getLangOptions().RTTI) {
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ return llvm::Constant::getNullValue(Int8PtrTy);
+ }
+
+ return RTTIBuilder(*this).BuildType(Ty);
+}
-llvm::Constant *CodeGenModule::GenerateRttiRef(const CXXRecordDecl *RD) {
- RttiBuilder b(*this);
+llvm::Constant *CodeGenModule::GenerateRTTIRef(const CXXRecordDecl *RD) {
+ RTTIBuilder b(*this);
return b.Buildclass_type_infoRef(RD);
}
-llvm::Constant *CodeGenModule::GenerateRtti(const CXXRecordDecl *RD) {
- RttiBuilder b(*this);
+llvm::Constant *CodeGenModule::GenerateRTTI(const CXXRecordDecl *RD) {
+ RTTIBuilder b(*this);
- return b.Buildclass_type_info(RD);
+ return b.Buildclass_type_info(RD, llvm::GlobalValue::ExternalLinkage);
}
-llvm::Constant *CodeGenModule::GenerateRtti(QualType Ty) {
- RttiBuilder b(*this);
+llvm::Constant *CodeGenModule::GenerateRTTI(QualType Ty) {
+ RTTIBuilder b(*this);
return b.BuildType(Ty);
}
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 1a9bc39..31784ed 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -88,8 +88,6 @@ void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D,
AppendBytes(NumBytesToAppend);
- AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct, getTypeAlignment(Ty));
-
BitsAvailableInLastField =
NextFieldOffsetInBytes * 8 - (FieldOffset + FieldSize);
}
@@ -247,6 +245,14 @@ void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) {
uint64_t RecordSizeInBytes = RecordSize / 8;
assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!");
+ uint64_t AlignedNextFieldOffset =
+ llvm::RoundUpToAlignment(NextFieldOffsetInBytes, AlignmentAsLLVMStruct);
+
+ if (AlignedNextFieldOffset == RecordSizeInBytes) {
+ // We don't need any padding.
+ return;
+ }
+
unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes;
AppendBytes(NumPadBytes);
}
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index 715aa4c..5283ed9 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -26,12 +26,23 @@ class VtableBuilder {
public:
/// Index_t - Vtable index type.
typedef uint64_t Index_t;
+ typedef std::vector<std::pair<GlobalDecl,
+ std::pair<GlobalDecl, ThunkAdjustment> > >
+ SavedAdjustmentsVectorTy;
private:
- std::vector<llvm::Constant *> &methods;
- std::vector<llvm::Constant *> submethods;
+
+ // VtableComponents - The components of the vtable being built.
+ typedef llvm::SmallVector<llvm::Constant *, 64> VtableComponentsVectorTy;
+ VtableComponentsVectorTy VtableComponents;
+
+ const bool BuildVtable;
+
llvm::Type *Ptr8Ty;
- /// Class - The most derived class that this vtable is being built for.
- const CXXRecordDecl *Class;
+
+ /// MostDerivedClass - The most derived class that this vtable is being
+ /// built for.
+ const CXXRecordDecl *MostDerivedClass;
+
/// LayoutClass - The most derived class used for virtual base layout
/// information.
const CXXRecordDecl *LayoutClass;
@@ -45,9 +56,7 @@ private:
llvm::Constant *rtti;
llvm::LLVMContext &VMContext;
CodeGenModule &CGM; // Per-module state.
- /// Index - Maps a method decl into a vtable index. Useful for virtual
- /// dispatch codegen.
- llvm::DenseMap<GlobalDecl, Index_t> Index;
+
llvm::DenseMap<GlobalDecl, Index_t> VCall;
llvm::DenseMap<GlobalDecl, Index_t> VCallOffset;
// This is the offset to the nearest virtual base
@@ -57,54 +66,93 @@ private:
/// PureVirtualFunction - Points to __cxa_pure_virtual.
llvm::Constant *PureVirtualFn;
- /// Thunk - Represents a single thunk.
- struct Thunk {
- Thunk()
- : Index(0) { }
-
- Thunk(uint64_t Index, const ThunkAdjustment &Adjustment)
- : Index(Index), Adjustment(Adjustment) { }
-
- /// Index - The index in the vtable.
- uint64_t Index;
+ /// VtableMethods - A data structure for keeping track of methods in a vtable.
+ /// Can add methods, override methods and iterate in vtable order.
+ class VtableMethods {
+ // MethodToIndexMap - Maps from a global decl to the index it has in the
+ // Methods vector.
+ llvm::DenseMap<GlobalDecl, uint64_t> MethodToIndexMap;
+
+ /// Methods - The methods, in vtable order.
+ typedef llvm::SmallVector<GlobalDecl, 16> MethodsVectorTy;
+ MethodsVectorTy Methods;
+ MethodsVectorTy OrigMethods;
+
+ public:
+ /// AddMethod - Add a method to the vtable methods.
+ void AddMethod(GlobalDecl GD) {
+ assert(!MethodToIndexMap.count(GD) &&
+ "Method has already been added!");
+
+ MethodToIndexMap[GD] = Methods.size();
+ Methods.push_back(GD);
+ OrigMethods.push_back(GD);
+ }
- /// Adjustment - The thunk adjustment.
- ThunkAdjustment Adjustment;
- };
+ /// OverrideMethod - Replace a method with another.
+ void OverrideMethod(GlobalDecl OverriddenGD, GlobalDecl GD) {
+ llvm::DenseMap<GlobalDecl, uint64_t>::iterator i
+ = MethodToIndexMap.find(OverriddenGD);
+ assert(i != MethodToIndexMap.end() && "Did not find entry!");
+
+ // Get the index of the old decl.
+ uint64_t Index = i->second;
+
+ // Replace the old decl with the new decl.
+ Methods[Index] = GD;
- /// Thunks - The thunks in a vtable.
- typedef llvm::DenseMap<GlobalDecl, Thunk> ThunksMapTy;
- ThunksMapTy Thunks;
+ // And add the new.
+ MethodToIndexMap[GD] = Index;
+ }
- /// CovariantThunk - Represents a single covariant thunk.
- struct CovariantThunk {
- CovariantThunk()
- : Index(0) { }
-
- CovariantThunk(uint64_t Index, const ThunkAdjustment &ThisAdjustment,
- const ThunkAdjustment &ReturnAdjustment,
- CanQualType ReturnType)
- : Index(Index), Adjustment(ThisAdjustment, ReturnAdjustment),
- ReturnType(ReturnType) { }
-
- // Index - The index in the vtable.
- uint64_t Index;
-
- /// Adjustment - The covariant thunk adjustment.
- CovariantThunkAdjustment Adjustment;
+ /// getIndex - Gives the index of a passed in GlobalDecl. Returns false if
+ /// the index couldn't be found.
+ bool getIndex(GlobalDecl GD, uint64_t &Index) const {
+ llvm::DenseMap<GlobalDecl, uint64_t>::const_iterator i
+ = MethodToIndexMap.find(GD);
+
+ if (i == MethodToIndexMap.end())
+ return false;
+
+ Index = i->second;
+ return true;
+ }
+
+ GlobalDecl getOrigMethod(uint64_t Index) const {
+ return OrigMethods[Index];
+ }
+
+ MethodsVectorTy::size_type size() const {
+ return Methods.size();
+ }
+
+ void clear() {
+ MethodToIndexMap.clear();
+ Methods.clear();
+ OrigMethods.clear();
+ }
- /// ReturnType - The return type of the function.
- CanQualType ReturnType;
+ GlobalDecl operator[](uint64_t Index) const {
+ return Methods[Index];
+ }
};
- /// CovariantThunks - The covariant thunks in a vtable.
- typedef llvm::DenseMap<GlobalDecl, CovariantThunk> CovariantThunksMapTy;
- CovariantThunksMapTy CovariantThunks;
+ /// Methods - The vtable methods we're currently building.
+ VtableMethods Methods;
+
+ /// ThisAdjustments - For a given index in the vtable, contains the 'this'
+ /// pointer adjustment needed for a method.
+ typedef llvm::DenseMap<uint64_t, ThunkAdjustment> ThisAdjustmentsMapTy;
+ ThisAdjustmentsMapTy ThisAdjustments;
+
+ SavedAdjustmentsVectorTy SavedAdjustments;
+
+ /// BaseReturnTypes - Contains the base return types of methods who have been
+ /// overridden with methods whose return types require adjustment. Used for
+ /// generating covariant thunk information.
+ typedef llvm::DenseMap<uint64_t, CanQualType> BaseReturnTypesMapTy;
+ BaseReturnTypesMapTy BaseReturnTypes;
- /// PureVirtualMethods - Pure virtual methods.
- typedef llvm::DenseSet<GlobalDecl> PureVirtualMethodsSetTy;
- PureVirtualMethodsSetTy PureVirtualMethods;
-
std::vector<Index_t> VCalls;
typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
@@ -143,21 +191,32 @@ private:
}
public:
- VtableBuilder(std::vector<llvm::Constant *> &meth, const CXXRecordDecl *c,
- const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm)
- : methods(meth), Class(c), LayoutClass(l), LayoutOffset(lo),
- BLayout(cgm.getContext().getASTRecordLayout(l)),
- rtti(cgm.GenerateRttiRef(c)), VMContext(cgm.getModule().getContext()),
- CGM(cgm), PureVirtualFn(0),subAddressPoints(AllocAddressPoint(cgm, l, c)),
+ VtableBuilder(const CXXRecordDecl *MostDerivedClass,
+ const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm,
+ bool build)
+ : BuildVtable(build), MostDerivedClass(MostDerivedClass), LayoutClass(l),
+ LayoutOffset(lo), BLayout(cgm.getContext().getASTRecordLayout(l)),
+ rtti(0), VMContext(cgm.getModule().getContext()),CGM(cgm),
+ PureVirtualFn(0),
+ subAddressPoints(AllocAddressPoint(cgm, l, MostDerivedClass)),
Extern(!l->isInAnonymousNamespace()),
- LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) {
+ LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) {
Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
+ if (BuildVtable)
+ rtti = CGM.GetAddrOfRTTI(MostDerivedClass);
}
- llvm::DenseMap<GlobalDecl, Index_t> &getIndex() { return Index; }
+ // getVtableComponents - Returns a reference to the vtable components.
+ const VtableComponentsVectorTy &getVtableComponents() const {
+ return VtableComponents;
+ }
+
llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex()
{ return VBIndex; }
+ SavedAdjustmentsVectorTy &getSavedAdjustments()
+ { return SavedAdjustments; }
+
llvm::Constant *wrap(Index_t i) {
llvm::Constant *m;
m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i);
@@ -168,8 +227,8 @@ public:
return llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
}
-//#define D1(x)
-#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0)
+#define D1(x)
+//#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0)
void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset,
bool updateVBIndex, Index_t current_vbindex) {
@@ -249,7 +308,7 @@ public:
qB = qB->getPointeeType();
CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
- if (D != Class)
+ if (D != MostDerivedClass)
return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B);
llvm::DenseMap<const CXXRecordDecl *, Index_t>::iterator i;
i = VBIndex.find(B);
@@ -260,166 +319,19 @@ public:
return 0;
}
- bool OverrideMethod(GlobalDecl GD, llvm::Constant *m,
- bool MorallyVirtual, Index_t OverrideOffset,
- Index_t Offset, int64_t CurrentVBaseOffset) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- const bool isPure = MD->isPure();
- typedef CXXMethodDecl::method_iterator meth_iter;
- // FIXME: Should OverrideOffset's be Offset?
-
- // FIXME: Don't like the nested loops. For very large inheritance
- // heirarchies we could have a table on the side with the final overridder
- // and just replace each instance of an overridden method once. Would be
- // nice to measure the cost/benefit on real code.
-
- for (meth_iter mi = MD->begin_overridden_methods(),
- e = MD->end_overridden_methods();
- mi != e; ++mi) {
- GlobalDecl OGD;
-
- const CXXMethodDecl *OMD = *mi;
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(OMD))
- OGD = GlobalDecl(DD, GD.getDtorType());
- else
- OGD = OMD;
-
- llvm::Constant *om;
- om = WrapAddrOf(OGD);
- om = llvm::ConstantExpr::getBitCast(om, Ptr8Ty);
-
- for (Index_t i = 0, e = submethods.size();
- i != e; ++i) {
- // FIXME: begin_overridden_methods might be too lax, covariance */
- if (submethods[i] != om)
- continue;
- QualType nc_oret = OMD->getType()->getAs<FunctionType>()->getResultType();
- CanQualType oret = CGM.getContext().getCanonicalType(nc_oret);
- QualType nc_ret = MD->getType()->getAs<FunctionType>()->getResultType();
- CanQualType ret = CGM.getContext().getCanonicalType(nc_ret);
- ThunkAdjustment ReturnAdjustment;
- if (oret != ret) {
- // FIXME: calculate offsets for covariance
- CovariantThunksMapTy::iterator i = CovariantThunks.find(OMD);
- if (i != CovariantThunks.end()) {
- oret = i->second.ReturnType;
- CovariantThunks.erase(i);
- }
- // FIXME: Double check oret
- Index_t nv = getNVOffset(oret, ret)/8;
- ReturnAdjustment = ThunkAdjustment(nv, getVbaseOffset(oret, ret));
- }
- Index[GD] = i;
- submethods[i] = m;
- if (isPure)
- PureVirtualMethods.insert(GD);
- PureVirtualMethods.erase(OGD);
- Thunks.erase(OGD);
- if (MorallyVirtual || VCall.count(OGD)) {
- Index_t &idx = VCall[OGD];
- if (idx == 0) {
- NonVirtualOffset[GD] = -OverrideOffset/8 + CurrentVBaseOffset/8;
- VCallOffset[GD] = OverrideOffset/8;
- idx = VCalls.size()+1;
- VCalls.push_back(0);
- D1(printf(" vcall for %s at %d with delta %d most derived %s\n",
- MD->getNameAsString().c_str(), (int)-idx-3,
- (int)VCalls[idx-1], Class->getNameAsCString()));
- } else {
- NonVirtualOffset[GD] = NonVirtualOffset[OGD];
- VCallOffset[GD] = VCallOffset[OGD];
- VCalls[idx-1] = -VCallOffset[OGD] + OverrideOffset/8;
- D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n",
- MD->getNameAsString().c_str(), (int)-idx-3,
- (int)VCalls[idx-1], Class->getNameAsCString()));
- }
- VCall[GD] = idx;
- int64_t NonVirtualAdjustment = NonVirtualOffset[GD];
- int64_t VirtualAdjustment =
- -((idx + extra + 2) * LLVMPointerWidth / 8);
-
- // Optimize out virtual adjustments of 0.
- if (VCalls[idx-1] == 0)
- VirtualAdjustment = 0;
-
- ThunkAdjustment ThisAdjustment(NonVirtualAdjustment,
- VirtualAdjustment);
-
- // FIXME: Do we always have to build a covariant thunk to save oret,
- // which is the containing virtual base class?
- if (!ReturnAdjustment.isEmpty()) {
- CovariantThunks[GD] =
- CovariantThunk(i, ThisAdjustment, ReturnAdjustment, oret);
- } else if (!isPure && !ThisAdjustment.isEmpty())
- Thunks[GD] = Thunk(i, ThisAdjustment);
- return true;
- }
-
- // FIXME: finish off
- int64_t NonVirtualAdjustment = VCallOffset[OGD] - OverrideOffset/8;
-
- if (NonVirtualAdjustment || !ReturnAdjustment.isEmpty()) {
- ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0);
-
- if (!ReturnAdjustment.isEmpty()) {
- CovariantThunks[GD] =
- CovariantThunk(i, ThisAdjustment, ReturnAdjustment, oret);
- } else if (!isPure)
- Thunks[GD] = Thunk(i, ThisAdjustment);
- }
- return true;
- }
- }
-
- return false;
- }
-
- void InstallThunks() {
- for (ThunksMapTy::const_iterator i = Thunks.begin(), e = Thunks.end();
- i != e; ++i) {
- GlobalDecl GD = i->first;
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- assert(!MD->isPure() && "Can't thunk pure virtual methods!");
-
- const Thunk& Thunk = i->second;
- assert(Thunk.Index == Index[GD] && "Thunk index mismatch!");
-
- submethods[Thunk.Index] = CGM.BuildThunk(MD, Extern, Thunk.Adjustment);
- }
- Thunks.clear();
-
- for (CovariantThunksMapTy::const_iterator i = CovariantThunks.begin(),
- e = CovariantThunks.end(); i != e; ++i) {
- GlobalDecl GD = i->first;
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- if (MD->isPure())
- continue;
-
- const CovariantThunk &Thunk = i->second;
- assert(Thunk.Index == Index[GD] && "Thunk index mismatch!");
- submethods[Thunk.Index] =
- CGM.BuildCovariantThunk(MD, Extern, Thunk.Adjustment);
- }
- CovariantThunks.clear();
-
- for (PureVirtualMethodsSetTy::iterator i = PureVirtualMethods.begin(),
- e = PureVirtualMethods.end(); i != e; ++i) {
- GlobalDecl GD = *i;
- submethods[Index[GD]] = getPureVirtualFn();
- }
- PureVirtualMethods.clear();
- }
+ bool OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
+ Index_t OverrideOffset, Index_t Offset,
+ int64_t CurrentVBaseOffset);
+ /// AppendMethods - Append the current methods to the vtable.
+ void AppendMethodsToVtable();
+
llvm::Constant *WrapAddrOf(GlobalDecl GD) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD))
- return wrap(CGM.GetAddrOfCXXDestructor(Dtor, GD.getDtorType()));
-
const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD);
- return wrap(CGM.GetAddrOfFunction(MD, Ty));
+ return wrap(CGM.GetAddrOfFunction(GD, Ty));
}
void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset,
@@ -438,15 +350,15 @@ public:
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
// Override both the complete and the deleting destructor.
GlobalDecl CompDtor(DD, Dtor_Complete);
- OverrideMethod(CompDtor, WrapAddrOf(CompDtor), MorallyVirtual,
- OverrideOffset, Offset, CurrentVBaseOffset);
-
+ OverrideMethod(CompDtor, MorallyVirtual, OverrideOffset, Offset,
+ CurrentVBaseOffset);
+
GlobalDecl DeletingDtor(DD, Dtor_Deleting);
- OverrideMethod(DeletingDtor, WrapAddrOf(DeletingDtor), MorallyVirtual,
- OverrideOffset, Offset, CurrentVBaseOffset);
+ OverrideMethod(DeletingDtor, MorallyVirtual, OverrideOffset, Offset,
+ CurrentVBaseOffset);
} else {
- OverrideMethod(MD, WrapAddrOf(MD), MorallyVirtual, OverrideOffset,
- Offset, CurrentVBaseOffset);
+ OverrideMethod(MD, MorallyVirtual, OverrideOffset, Offset,
+ CurrentVBaseOffset);
}
}
}
@@ -454,24 +366,20 @@ public:
void AddMethod(const GlobalDecl GD, bool MorallyVirtual, Index_t Offset,
int64_t CurrentVBaseOffset) {
- llvm::Constant *m = WrapAddrOf(GD);
-
// If we can find a previously allocated slot for this, reuse it.
- if (OverrideMethod(GD, m, MorallyVirtual, Offset, Offset,
+ if (OverrideMethod(GD, MorallyVirtual, Offset, Offset,
CurrentVBaseOffset))
return;
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- // else allocate a new slot.
- Index[GD] = submethods.size();
- submethods.push_back(m);
+ // We didn't find an entry in the vtable that we could use, add a new
+ // entry.
+ Methods.AddMethod(GD);
+
D1(printf(" vfn for %s at %d\n", MD->getNameAsString().c_str(),
(int)Index[GD]));
- if (MD->isPure())
- PureVirtualMethods.insert(GD);
+
+ VCallOffset[GD] = Offset/8;
if (MorallyVirtual) {
- VCallOffset[GD] = Offset/8;
Index_t &idx = VCall[GD];
// Allocate the first one, after that, we reuse the previous one.
if (idx == 0) {
@@ -530,16 +438,19 @@ public:
#define D(X)
void insertVCalls(int InsertionPoint) {
- llvm::Constant *e = 0;
D1(printf("============= combining vbase/vcall\n"));
D(VCalls.insert(VCalls.begin(), 673));
D(VCalls.push_back(672));
- methods.insert(methods.begin() + InsertionPoint, VCalls.size(), e);
- // The vcalls come first...
- for (std::vector<Index_t>::reverse_iterator i = VCalls.rbegin(),
- e = VCalls.rend();
- i != e; ++i)
- methods[InsertionPoint++] = wrap((0?600:0) + *i);
+
+ VtableComponents.insert(VtableComponents.begin() + InsertionPoint,
+ VCalls.size(), 0);
+ if (BuildVtable) {
+ // The vcalls come first...
+ for (std::vector<Index_t>::reverse_iterator i = VCalls.rbegin(),
+ e = VCalls.rend();
+ i != e; ++i)
+ VtableComponents[InsertionPoint++] = wrap((0?600:0) + *i);
+ }
VCalls.clear();
VCall.clear();
}
@@ -570,11 +481,13 @@ public:
}
- Index_t end(const CXXRecordDecl *RD, const ASTRecordLayout &Layout,
- const CXXRecordDecl *PrimaryBase, bool PrimaryBaseWasVirtual,
- bool MorallyVirtual, int64_t Offset, bool ForVirtualBase,
- int64_t CurrentVBaseOffset,
- Path_t *Path) {
+ Index_t FinishGenerateVtable(const CXXRecordDecl *RD,
+ const ASTRecordLayout &Layout,
+ const CXXRecordDecl *PrimaryBase,
+ bool PrimaryBaseWasVirtual,
+ bool MorallyVirtual, int64_t Offset,
+ bool ForVirtualBase, int64_t CurrentVBaseOffset,
+ Path_t *Path) {
bool alloc = false;
if (Path == 0) {
alloc = true;
@@ -584,21 +497,22 @@ public:
StartNewTable();
extra = 0;
bool DeferVCalls = MorallyVirtual || ForVirtualBase;
- int VCallInsertionPoint = methods.size();
+ int VCallInsertionPoint = VtableComponents.size();
if (!DeferVCalls) {
insertVCalls(VCallInsertionPoint);
} else
// FIXME: just for extra, or for all uses of VCalls.size post this?
extra = -VCalls.size();
- methods.push_back(wrap(-((Offset-LayoutOffset)/8)));
- methods.push_back(rtti);
- Index_t AddressPoint = methods.size();
+ // Add the offset to top.
+ VtableComponents.push_back(BuildVtable ? wrap(-((Offset-LayoutOffset)/8)) : 0);
+
+ // Add the RTTI information.
+ VtableComponents.push_back(rtti);
+
+ Index_t AddressPoint = VtableComponents.size();
- InstallThunks();
- D1(printf("============= combining methods\n"));
- methods.insert(methods.end(), submethods.begin(), submethods.end());
- submethods.clear();
+ AppendMethodsToVtable();
// and then the non-virtual bases.
NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual,
@@ -635,17 +549,11 @@ public:
const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
// vtables are composed from the chain of primaries.
- if (PrimaryBase) {
+ if (PrimaryBase && !PrimaryBaseWasVirtual) {
D1(printf(" doing primaries for %s most derived %s\n",
RD->getNameAsCString(), Class->getNameAsCString()));
-
- int BaseCurrentVBaseOffset = CurrentVBaseOffset;
- if (PrimaryBaseWasVirtual)
- BaseCurrentVBaseOffset = BLayout.getVBaseClassOffset(PrimaryBase);
-
- if (!PrimaryBaseWasVirtual)
- Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
- updateVBIndex, current_vbindex, BaseCurrentVBaseOffset);
+ Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
+ updateVBIndex, current_vbindex, CurrentVBaseOffset);
}
D1(printf(" doing vcall entries for %s most derived %s\n",
@@ -702,7 +610,8 @@ public:
// Construction vtable don't need parts that have no virtual bases and
// aren't morally virtual.
- if ((LayoutClass != Class) && RD->getNumVBases() == 0 && !MorallyVirtual)
+ if ((LayoutClass != MostDerivedClass) &&
+ RD->getNumVBases() == 0 && !MorallyVirtual)
return 0;
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
@@ -722,8 +631,9 @@ public:
if (Path)
OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset);
- return end(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, MorallyVirtual,
- Offset, ForVirtualBase, CurrentVBaseOffset, Path);
+ return FinishGenerateVtable(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual,
+ MorallyVirtual, Offset, ForVirtualBase,
+ CurrentVBaseOffset, Path);
}
void GenerateVtableForVBases(const CXXRecordDecl *RD,
@@ -770,8 +680,7 @@ public:
delete Path;
}
};
-
-}
+} // end anonymous namespace
/// TypeConversionRequiresAdjustment - Returns whether conversion from a
/// derived type to a base type requires adjustment.
@@ -790,18 +699,18 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx,
// If we found a virtual base we always want to require adjustment.
if (Paths.getDetectedVirtual())
return true;
-
+
const CXXBasePath &Path = Paths.front();
for (size_t Start = 0, End = Path.size(); Start != End; ++Start) {
const CXXBasePathElement &Element = Path[Start];
-
+
// Check the base class offset.
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Element.Class);
const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>();
const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl());
-
+
if (Layout.getBaseClassOffset(Base) != 0) {
// This requires an adjustment.
return true;
@@ -825,7 +734,7 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx,
// No adjustment needed.
return false;
}
-
+
if (const ReferenceType *RT = dyn_cast<ReferenceType>(CanDerivedType)) {
CanDerivedType = RT->getPointeeType();
CanBaseType = cast<ReferenceType>(CanBaseType)->getPointeeType();
@@ -835,21 +744,190 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx,
} else {
assert(false && "Unexpected return type!");
}
-
+
if (CanDerivedType == CanBaseType) {
// No adjustment needed.
return false;
}
const CXXRecordDecl *DerivedDecl =
- cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl());
-
+ cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl());
+
const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl());
-
+ cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl());
+
return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl);
}
+bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
+ Index_t OverrideOffset, Index_t Offset,
+ int64_t CurrentVBaseOffset) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ const bool isPure = MD->isPure();
+
+ // FIXME: Should OverrideOffset's be Offset?
+
+ for (CXXMethodDecl::method_iterator mi = MD->begin_overridden_methods(),
+ e = MD->end_overridden_methods(); mi != e; ++mi) {
+ GlobalDecl OGD;
+
+ const CXXMethodDecl *OMD = *mi;
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(OMD))
+ OGD = GlobalDecl(DD, GD.getDtorType());
+ else
+ OGD = OMD;
+
+ // Check whether this is the method being overridden in this section of
+ // the vtable.
+ uint64_t Index;
+ if (!Methods.getIndex(OGD, Index))
+ continue;
+
+ // Get the original method, which we should be computing thunks, etc,
+ // against.
+ OGD = Methods.getOrigMethod(Index);
+ OMD = cast<CXXMethodDecl>(OGD.getDecl());
+
+ QualType ReturnType =
+ MD->getType()->getAs<FunctionType>()->getResultType();
+ QualType OverriddenReturnType =
+ OMD->getType()->getAs<FunctionType>()->getResultType();
+
+ // Check if we need a return type adjustment.
+ if (TypeConversionRequiresAdjustment(CGM.getContext(), ReturnType,
+ OverriddenReturnType)) {
+ CanQualType &BaseReturnType = BaseReturnTypes[Index];
+
+ // Insert the base return type.
+ if (BaseReturnType.isNull())
+ BaseReturnType =
+ CGM.getContext().getCanonicalType(OverriddenReturnType);
+ }
+
+ Methods.OverrideMethod(OGD, GD);
+
+ ThisAdjustments.erase(Index);
+ if (MorallyVirtual || VCall.count(OGD)) {
+ Index_t &idx = VCall[OGD];
+ if (idx == 0) {
+ NonVirtualOffset[GD] = -OverrideOffset/8 + CurrentVBaseOffset/8;
+ VCallOffset[GD] = OverrideOffset/8;
+ idx = VCalls.size()+1;
+ VCalls.push_back(0);
+ D1(printf(" vcall for %s at %d with delta %d most derived %s\n",
+ MD->getNameAsString().c_str(), (int)-idx-3,
+ (int)VCalls[idx-1], Class->getNameAsCString()));
+ } else {
+ NonVirtualOffset[GD] = NonVirtualOffset[OGD];
+ VCallOffset[GD] = VCallOffset[OGD];
+ VCalls[idx-1] = -VCallOffset[OGD] + OverrideOffset/8;
+ D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n",
+ MD->getNameAsString().c_str(), (int)-idx-3,
+ (int)VCalls[idx-1], Class->getNameAsCString()));
+ }
+ VCall[GD] = idx;
+ int64_t NonVirtualAdjustment = NonVirtualOffset[GD];
+ int64_t VirtualAdjustment =
+ -((idx + extra + 2) * LLVMPointerWidth / 8);
+
+ // Optimize out virtual adjustments of 0.
+ if (VCalls[idx-1] == 0)
+ VirtualAdjustment = 0;
+
+ ThunkAdjustment ThisAdjustment(NonVirtualAdjustment,
+ VirtualAdjustment);
+
+ if (!isPure && !ThisAdjustment.isEmpty()) {
+ ThisAdjustments[Index] = ThisAdjustment;
+ SavedAdjustments.push_back(
+ std::make_pair(GD, std::make_pair(OGD, ThisAdjustment)));
+ }
+ return true;
+ }
+
+ int64_t NonVirtualAdjustment = -VCallOffset[OGD] + OverrideOffset/8;
+
+ if (NonVirtualAdjustment) {
+ ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0);
+
+ if (!isPure) {
+ ThisAdjustments[Index] = ThisAdjustment;
+ SavedAdjustments.push_back(
+ std::make_pair(GD, std::make_pair(OGD, ThisAdjustment)));
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void VtableBuilder::AppendMethodsToVtable() {
+ if (!BuildVtable) {
+ VtableComponents.insert(VtableComponents.end(), Methods.size(),
+ (llvm::Constant *)0);
+ ThisAdjustments.clear();
+ BaseReturnTypes.clear();
+ Methods.clear();
+ return;
+ }
+
+ // Reserve room in the vtable for our new methods.
+ VtableComponents.reserve(VtableComponents.size() + Methods.size());
+
+ for (unsigned i = 0, e = Methods.size(); i != e; ++i) {
+ GlobalDecl GD = Methods[i];
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ // Get the 'this' pointer adjustment.
+ ThunkAdjustment ThisAdjustment = ThisAdjustments.lookup(i);
+
+ // Construct the return type adjustment.
+ ThunkAdjustment ReturnAdjustment;
+
+ QualType BaseReturnType = BaseReturnTypes.lookup(i);
+ if (!BaseReturnType.isNull() && !MD->isPure()) {
+ QualType DerivedType =
+ MD->getType()->getAs<FunctionType>()->getResultType();
+
+ int64_t NonVirtualAdjustment =
+ getNVOffset(BaseReturnType, DerivedType) / 8;
+
+ int64_t VirtualAdjustment =
+ getVbaseOffset(BaseReturnType, DerivedType);
+
+ ReturnAdjustment = ThunkAdjustment(NonVirtualAdjustment,
+ VirtualAdjustment);
+ }
+
+ llvm::Constant *Method = 0;
+ if (!ReturnAdjustment.isEmpty()) {
+ // Build a covariant thunk.
+ CovariantThunkAdjustment Adjustment(ThisAdjustment, ReturnAdjustment);
+ Method = wrap(CGM.GetAddrOfCovariantThunk(GD, Adjustment));
+ } else if (!ThisAdjustment.isEmpty()) {
+ // Build a "regular" thunk.
+ Method = wrap(CGM.GetAddrOfThunk(GD, ThisAdjustment));
+ } else if (MD->isPure()) {
+ // We have a pure virtual method.
+ Method = getPureVirtualFn();
+ } else {
+ // We have a good old regular method.
+ Method = WrapAddrOf(GD);
+ }
+
+ // Add the method to the vtable.
+ VtableComponents.push_back(Method);
+ }
+
+
+ ThisAdjustments.clear();
+ BaseReturnTypes.clear();
+
+ Methods.clear();
+}
+
void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
// Itanium C++ ABI 2.5.2:
@@ -874,7 +952,15 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
// we need to start counting at the end of the primary base's vtable.
CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase);
}
-
+
+ // Collect all the primary bases, so we can check whether methods override
+ // a method from the base.
+ llvm::SmallPtrSet<const CXXRecordDecl *, 5> PrimaryBases;
+ for (ASTRecordLayout::primary_base_info_iterator
+ I = Layout.primary_base_begin(), E = Layout.primary_base_end();
+ I != E; ++I)
+ PrimaryBases.insert((*I).getBase());
+
const CXXDestructorDecl *ImplicitVirtualDtor = 0;
for (CXXRecordDecl::method_iterator i = RD->method_begin(),
@@ -895,7 +981,7 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
assert(OverriddenMD->isCanonicalDecl() &&
"Should have the canonical decl of the overridden RD!");
- if (OverriddenRD == PrimaryBase) {
+ if (PrimaryBases.count(OverriddenRD)) {
// Check if converting from the return type of the method to the
// return type of the overridden method requires conversion.
QualType ReturnType =
@@ -993,6 +1079,33 @@ uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) {
return I->second;
}
+CGVtableInfo::AdjustmentVectorTy*
+CGVtableInfo::getAdjustments(GlobalDecl GD) {
+ SavedAdjustmentsTy::iterator I = SavedAdjustments.find(GD);
+ if (I != SavedAdjustments.end())
+ return &I->second;
+
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(GD.getDecl()->getDeclContext());
+ if (!SavedAdjustmentRecords.insert(RD).second)
+ return 0;
+
+ VtableBuilder b(RD, RD, 0, CGM, false);
+ D1(printf("vtable %s\n", RD->getNameAsCString()));
+ b.GenerateVtableForBase(RD);
+ b.GenerateVtableForVBases(RD);
+
+ for (VtableBuilder::SavedAdjustmentsVectorTy::iterator
+ i = b.getSavedAdjustments().begin(),
+ e = b.getSavedAdjustments().end(); i != e; i++)
+ SavedAdjustments[i->first].push_back(i->second);
+
+ I = SavedAdjustments.find(GD);
+ if (I != SavedAdjustments.end())
+ return &I->second;
+
+ return 0;
+}
+
int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
const CXXRecordDecl *VBase) {
ClassPairTy ClassPair(RD, VBase);
@@ -1002,10 +1115,9 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
if (I != VirtualBaseClassIndicies.end())
return I->second;
- std::vector<llvm::Constant *> methods;
// FIXME: This seems expensive. Can we do a partial job to get
// just this data.
- VtableBuilder b(methods, RD, RD, 0, CGM);
+ VtableBuilder b(RD, RD, 0, CGM, false);
D1(printf("vtable %s\n", RD->getNameAsCString()));
b.GenerateVtableForBase(RD);
b.GenerateVtableForVBases(RD);
@@ -1024,30 +1136,38 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
return I->second;
}
-llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass,
- const CXXRecordDecl *RD,
- uint64_t Offset) {
+uint64_t CGVtableInfo::getVtableAddressPoint(const CXXRecordDecl *RD) {
+ uint64_t AddressPoint =
+ (*(*(CGM.AddressPoints[RD]))[RD])[std::make_pair(RD, 0)];
+
+ return AddressPoint;
+}
+
+llvm::GlobalVariable *
+CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
+ bool GenerateDefinition,
+ const CXXRecordDecl *LayoutClass,
+ const CXXRecordDecl *RD, uint64_t Offset) {
llvm::SmallString<256> OutName;
if (LayoutClass != RD)
- getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset/8, RD, OutName);
+ CGM.getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset / 8,
+ RD, OutName);
else
- getMangleContext().mangleCXXVtable(RD, OutName);
+ CGM.getMangleContext().mangleCXXVtable(RD, OutName);
llvm::StringRef Name = OutName.str();
- std::vector<llvm::Constant *> methods;
- llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
int64_t AddressPoint;
- llvm::GlobalVariable *GV = getModule().getGlobalVariable(Name);
- if (GV && AddressPoints[LayoutClass] && !GV->isDeclaration()) {
- AddressPoint=(*(*(AddressPoints[LayoutClass]))[RD])[std::make_pair(RD,
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
+ if (GV && CGM.AddressPoints[LayoutClass] && !GV->isDeclaration()) {
+ AddressPoint=(*(*(CGM.AddressPoints[LayoutClass]))[RD])[std::make_pair(RD,
Offset)];
// FIXME: We can never have 0 address point. Do this for now so gepping
// retains the same structure. Later, we'll just assert.
if (AddressPoint == 0)
AddressPoint = 1;
} else {
- VtableBuilder b(methods, RD, LayoutClass, Offset, *this);
+ VtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition);
D1(printf("vtable %s\n", RD->getNameAsCString()));
// First comes the vtables for all the non-virtual bases...
@@ -1056,59 +1176,34 @@ llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass,
// then the vtables for all the virtual bases.
b.GenerateVtableForVBases(RD, Offset);
- bool CreateDefinition = true;
- if (LayoutClass != RD)
- CreateDefinition = true;
- else {
- const ASTRecordLayout &Layout =
- getContext().getASTRecordLayout(LayoutClass);
-
- if (const CXXMethodDecl *KeyFunction = Layout.getKeyFunction()) {
- if (!KeyFunction->getBody()) {
- // If there is a KeyFunction, and it isn't defined, just build a
- // reference to the vtable.
- CreateDefinition = false;
- }
- }
- }
+ llvm::Constant *Init = 0;
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ llvm::ArrayType *ArrayType =
+ llvm::ArrayType::get(Int8PtrTy, b.getVtableComponents().size());
+
+ if (GenerateDefinition)
+ Init = llvm::ConstantArray::get(ArrayType, &b.getVtableComponents()[0],
+ b.getVtableComponents().size());
- llvm::Constant *C = 0;
- llvm::Type *type = Ptr8Ty;
- llvm::GlobalVariable::LinkageTypes linktype
- = llvm::GlobalValue::ExternalLinkage;
- if (CreateDefinition) {
- llvm::ArrayType *ntype = llvm::ArrayType::get(Ptr8Ty, methods.size());
- C = llvm::ConstantArray::get(ntype, methods);
- linktype = llvm::GlobalValue::LinkOnceODRLinkage;
- if (LayoutClass->isInAnonymousNamespace())
- linktype = llvm::GlobalValue::InternalLinkage;
- type = ntype;
- }
llvm::GlobalVariable *OGV = GV;
- GV = new llvm::GlobalVariable(getModule(), type, true, linktype, C, Name);
+
+ GV = new llvm::GlobalVariable(CGM.getModule(), ArrayType,
+ /*isConstant=*/true, Linkage, Init, Name);
+ CGM.setGlobalVisibility(GV, RD);
+
if (OGV) {
GV->takeName(OGV);
- llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV,
- OGV->getType());
+ llvm::Constant *NewPtr =
+ llvm::ConstantExpr::getBitCast(GV, OGV->getType());
OGV->replaceAllUsesWith(NewPtr);
OGV->eraseFromParent();
}
- bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden;
- if (Hidden)
- GV->setVisibility(llvm::GlobalVariable::HiddenVisibility);
}
- llvm::Constant *vtable = llvm::ConstantExpr::getBitCast(GV, Ptr8Ty);
- llvm::Constant *AddressPointC;
- uint32_t LLVMPointerWidth = getContext().Target.getPointerWidth(0);
- AddressPointC = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- AddressPoint*LLVMPointerWidth/8);
- vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(vtable, &AddressPointC,
- 1);
-
- assert(vtable->getType() == Ptr8Ty);
- return vtable;
+
+ return GV;
}
+namespace {
class VTTBuilder {
/// Inits - The list of values built for the VTT.
std::vector<llvm::Constant *> &Inits;
@@ -1125,12 +1220,13 @@ class VTTBuilder {
llvm::LLVMContext &VMContext;
/// BuildVtablePtr - Build up a referene to the given secondary vtable
- llvm::Constant *BuildVtablePtr(llvm::Constant *vtbl,
- const CXXRecordDecl *VtblClass,
+ llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable,
+ const CXXRecordDecl *VtableClass,
const CXXRecordDecl *RD,
uint64_t Offset) {
- int64_t AddressPoint;
- AddressPoint = (*AddressPoints[VtblClass])[std::make_pair(RD, Offset)];
+ int64_t AddressPoint =
+ (*AddressPoints[VtableClass])[std::make_pair(RD, Offset)];
+
// FIXME: We can never have 0 address point. Do this for now so gepping
// retains the same structure. Later we'll just assert.
if (AddressPoint == 0)
@@ -1138,12 +1234,17 @@ class VTTBuilder {
D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n",
RD->getNameAsCString(), VtblClass->getNameAsCString(),
Class->getNameAsCString(), (int)Offset, (int)AddressPoint));
- uint32_t LLVMPointerWidth = CGM.getContext().Target.getPointerWidth(0);
- llvm::Constant *init;
- init = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- AddressPoint*LLVMPointerWidth/8);
- init = llvm::ConstantExpr::getInBoundsGetElementPtr(vtbl, &init, 1);
- return init;
+
+ llvm::Value *Idxs[] = {
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 0),
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), AddressPoint)
+ };
+
+ llvm::Constant *Init =
+ llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, Idxs, 2);
+
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ return llvm::ConstantExpr::getBitCast(Init, Int8PtrTy);
}
/// Secondary - Add the secondary vtable pointers to Inits. Offset is the
@@ -1180,8 +1281,11 @@ class VTTBuilder {
init = BuildVtablePtr(vtbl, VtblClass, RD, Offset);
else {
init = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseOffset);
- subvtbl = dyn_cast<llvm::Constant>(init->getOperand(0));
+
+ subvtbl = init;
subVtblClass = Base;
+
+ init = BuildVtablePtr(init, Class, Base, BaseOffset);
}
Inits.push_back(init);
}
@@ -1195,25 +1299,26 @@ class VTTBuilder {
if (RD->getNumVBases() == 0 && !MorallyVirtual)
return;
- llvm::Constant *init;
- const CXXRecordDecl *VtblClass;
+ llvm::Constant *Vtable;
+ const CXXRecordDecl *VtableClass;
// First comes the primary virtual table pointer...
if (MorallyVirtual) {
- init = BuildVtablePtr(ClassVtbl, Class, RD, Offset);
- VtblClass = Class;
+ Vtable = ClassVtbl;
+ VtableClass = Class;
} else {
- init = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset);
- VtblClass = RD;
+ Vtable = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset);
+ VtableClass = RD;
}
- llvm::Constant *vtbl = dyn_cast<llvm::Constant>(init->getOperand(0));
- Inits.push_back(init);
+
+ llvm::Constant *Init = BuildVtablePtr(Vtable, VtableClass, RD, Offset);
+ Inits.push_back(Init);
// then the secondary VTTs....
SecondaryVTTs(RD, Offset, MorallyVirtual);
// and last the secondary vtable pointers.
- Secondary(RD, vtbl, VtblClass, Offset, MorallyVirtual);
+ Secondary(RD, Vtable, VtableClass, Offset, MorallyVirtual);
}
/// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are
@@ -1248,6 +1353,7 @@ class VTTBuilder {
VirtualVTTs(Base);
}
}
+
public:
VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c,
CodeGenModule &cgm)
@@ -1258,8 +1364,7 @@ public:
// First comes the primary virtual table pointer for the complete class...
ClassVtbl = CGM.getVtableInfo().getVtable(Class);
- Inits.push_back(ClassVtbl);
- ClassVtbl = dyn_cast<llvm::Constant>(ClassVtbl->getOperand(0));
+ Inits.push_back(BuildVtablePtr(ClassVtbl, Class, Class, 0));
// then the secondary VTTs...
SecondaryVTTs(Class);
@@ -1271,98 +1376,116 @@ public:
VirtualVTTs(Class);
}
};
+}
-llvm::Constant *CodeGenModule::GenerateVTT(const CXXRecordDecl *RD) {
+llvm::GlobalVariable *
+CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
+ const CXXRecordDecl *RD) {
// Only classes that have virtual bases need a VTT.
if (RD->getNumVBases() == 0)
return 0;
llvm::SmallString<256> OutName;
- getMangleContext().mangleCXXVTT(RD, OutName);
+ CGM.getMangleContext().mangleCXXVTT(RD, OutName);
llvm::StringRef Name = OutName.str();
- llvm::GlobalVariable::LinkageTypes linktype;
- linktype = llvm::GlobalValue::LinkOnceODRLinkage;
- if (RD->isInAnonymousNamespace())
- linktype = llvm::GlobalValue::InternalLinkage;
- std::vector<llvm::Constant *> inits;
- llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
D1(printf("vtt %s\n", RD->getNameAsCString()));
- VTTBuilder b(inits, RD, *this);
-
- llvm::Constant *C;
- llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, inits.size());
- C = llvm::ConstantArray::get(type, inits);
- llvm::GlobalVariable *vtt = new llvm::GlobalVariable(getModule(), type, true,
- linktype, C, Name);
- bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden;
- if (Hidden)
- vtt->setVisibility(llvm::GlobalVariable::HiddenVisibility);
- return llvm::ConstantExpr::getBitCast(vtt, Ptr8Ty);
-}
+ std::vector<llvm::Constant *> inits;
+ VTTBuilder b(inits, RD, CGM);
-void CGVtableInfo::GenerateClassData(const CXXRecordDecl *RD) {
- Vtables[RD] = CGM.GenerateVtable(RD, RD);
- CGM.GenerateRtti(RD);
- CGM.GenerateVTT(RD);
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size());
+
+ llvm::Constant *Init = llvm::ConstantArray::get(Type, inits);
+
+ llvm::GlobalVariable *VTT =
+ new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true,
+ Linkage, Init, Name);
+ CGM.setGlobalVisibility(VTT, RD);
+
+ return VTT;
}
-llvm::Constant *CGVtableInfo::getVtable(const CXXRecordDecl *RD) {
- llvm::Constant *&vtbl = Vtables[RD];
- if (vtbl)
- return vtbl;
- vtbl = CGM.GenerateVtable(RD, RD);
-
- bool CreateDefinition = true;
-
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- if (const CXXMethodDecl *KeyFunction = Layout.getKeyFunction()) {
- if (!KeyFunction->getBody()) {
- // If there is a KeyFunction, and it isn't defined, just build a
- // reference to the vtable.
- CreateDefinition = false;
- }
+void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
+ const CXXRecordDecl *RD) {
+ llvm::GlobalVariable *&Vtable = Vtables[RD];
+ if (Vtable) {
+ assert(Vtable->getInitializer() && "Vtable doesn't have a definition!");
+ return;
}
+
+ Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0);
+ GenerateVTT(Linkage, RD);
+}
- if (CreateDefinition) {
- CGM.GenerateRtti(RD);
- CGM.GenerateVTT(RD);
- }
- return vtbl;
+llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) {
+ llvm::GlobalVariable *Vtable = Vtables.lookup(RD);
+
+ if (!Vtable)
+ Vtable = GenerateVtable(llvm::GlobalValue::ExternalLinkage,
+ /*GenerateDefinition=*/false, RD, RD, 0);
+
+ return Vtable;
}
-llvm::Constant *CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass,
- const CXXRecordDecl *RD,
- uint64_t Offset) {
- return CGM.GenerateVtable(LayoutClass, RD, Offset);
+llvm::GlobalVariable *
+CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass,
+ const CXXRecordDecl *RD, uint64_t Offset) {
+ return GenerateVtable(llvm::GlobalValue::InternalLinkage,
+ /*GenerateDefinition=*/true,
+ LayoutClass, RD, Offset);
}
void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
const CXXRecordDecl *RD = MD->getParent();
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ // If the class doesn't have a vtable we don't need to emit one.
+ if (!RD->isDynamicClass())
+ return;
// Get the key function.
- const CXXMethodDecl *KeyFunction = Layout.getKeyFunction();
+ const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD);
- if (!KeyFunction) {
- // If there's no key function, we don't want to emit the vtable here.
- return;
+ if (KeyFunction) {
+ // We don't have the right key function.
+ if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl())
+ return;
+
+ // If the key function is a destructor, we only want to emit the vtable
+ // once, so do it for the complete destructor.
+ if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Complete)
+ return;
+ } else {
+ // If there is no key function, we only want to emit the vtable if we are
+ // emitting a constructor.
+ if (!isa<CXXConstructorDecl>(MD) || GD.getCtorType() != Ctor_Complete)
+ return;
}
- // Check if we have the key function.
- if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl())
- return;
+ llvm::GlobalVariable::LinkageTypes Linkage;
+ if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
+ Linkage = llvm::GlobalVariable::InternalLinkage;
+ else if (KeyFunction && !MD->isInlined())
+ Linkage = llvm::GlobalVariable::ExternalLinkage;
+ else
+ Linkage = llvm::GlobalVariable::WeakODRLinkage;
- // If the key function is a destructor, we only want to emit the vtable once,
- // so do it for the complete destructor.
- if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Complete)
- return;
-
// Emit the data.
- GenerateClassData(RD);
+ GenerateClassData(Linkage, RD);
+
+ for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+ e = RD->method_end(); i != e; ++i) {
+ if ((*i)->isVirtual() && ((*i)->hasInlineBody() || (*i)->isImplicit())) {
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(*i)) {
+ CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Complete));
+ CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Deleting));
+ } else {
+ CGM.BuildThunksForVirtual(GlobalDecl(*i));
+ }
+ }
+ }
}
diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h
index 5c2b74c..eed5b64 100644
--- a/lib/CodeGen/CGVtable.h
+++ b/lib/CodeGen/CGVtable.h
@@ -15,12 +15,10 @@
#define CLANG_CODEGEN_CGVTABLE_H
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/GlobalVariable.h"
#include "GlobalDecl.h"
-namespace llvm {
- class Constant;
-}
-
namespace clang {
class CXXRecordDecl;
@@ -64,6 +62,11 @@ public:
};
class CGVtableInfo {
+public:
+ typedef std::vector<std::pair<GlobalDecl, ThunkAdjustment> >
+ AdjustmentVectorTy;
+
+private:
CodeGenModule &CGM;
/// MethodVtableIndices - Contains the index (relative to the vtable address
@@ -79,12 +82,17 @@ class CGVtableInfo {
typedef llvm::DenseMap<ClassPairTy, int64_t> VirtualBaseClassIndiciesTy;
VirtualBaseClassIndiciesTy VirtualBaseClassIndicies;
- llvm::DenseMap<const CXXRecordDecl *, llvm::Constant *> 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.
llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers;
+ typedef llvm::DenseMap<GlobalDecl, AdjustmentVectorTy> SavedAdjustmentsTy;
+ SavedAdjustmentsTy SavedAdjustments;
+ llvm::DenseSet<const CXXRecordDecl*> SavedAdjustmentRecords;
+
/// getNumVirtualFunctionPointers - Return the number of virtual function
/// pointers in the vtable for a given record decl.
uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
@@ -94,8 +102,19 @@ class CGVtableInfo {
/// GenerateClassData - Generate all the class data requires to be generated
/// upon definition of a KeyFunction. This includes the vtable, the
/// rtti data structure and the VTT.
- void GenerateClassData(const CXXRecordDecl *RD);
-
+ ///
+ /// \param Linkage - The desired linkage of the vtable, the RTTI and the VTT.
+ void GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
+ const CXXRecordDecl *RD);
+
+ llvm::GlobalVariable *
+ GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
+ bool GenerateDefinition, const CXXRecordDecl *LayoutClass,
+ const CXXRecordDecl *RD, uint64_t Offset);
+
+ llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
+ const CXXRecordDecl *RD);
+
public:
CGVtableInfo(CodeGenModule &CGM)
: CGM(CGM) { }
@@ -113,9 +132,17 @@ public:
int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
const CXXRecordDecl *VBase);
- llvm::Constant *getVtable(const CXXRecordDecl *RD);
- llvm::Constant *getCtorVtable(const CXXRecordDecl *RD,
- const CXXRecordDecl *Class, uint64_t Offset);
+ AdjustmentVectorTy *getAdjustments(GlobalDecl GD);
+
+ /// getVtableAddressPoint - returns the address point of the vtable for the
+ /// given record decl.
+ /// FIXME: This should return a list of address points.
+ uint64_t getVtableAddressPoint(const CXXRecordDecl *RD);
+
+ llvm::GlobalVariable *getVtable(const CXXRecordDecl *RD);
+ llvm::GlobalVariable *getCtorVtable(const CXXRecordDecl *RD,
+ const CXXRecordDecl *Class,
+ uint64_t Offset);
void MaybeEmitVtable(GlobalDecl GD);
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 9281416..3c26484 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -8,6 +8,7 @@ add_clang_library(clangCodeGen
CGCXX.cpp
CGDebugInfo.cpp
CGDecl.cpp
+ CGDeclCXX.cpp
CGException.cpp
CGExpr.cpp
CGExprAgg.cpp
@@ -19,7 +20,7 @@ add_clang_library(clangCodeGen
CGObjCGNU.cpp
CGObjCMac.cpp
CGRecordLayoutBuilder.cpp
- CGRtti.cpp
+ CGRTTI.cpp
CGStmt.cpp
CGTemporaries.cpp
CGVtable.cpp
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 6e0a77c..28df9e4 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/StmtCXX.h"
#include "llvm/Target/TargetData.h"
using namespace clang;
using namespace CodeGen;
@@ -30,9 +31,12 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
DebugInfo(0), IndirectBranch(0),
SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0),
CXXThisDecl(0), CXXVTTDecl(0),
- ConditionalBranchLevel(0) {
+ ConditionalBranchLevel(0), TerminateHandler(0), TrapBB(0),
+ UniqueAggrDestructorCount(0) {
LLVMIntTy = ConvertType(getContext().IntTy);
LLVMPointerWidth = Target.getPointerWidth(0);
+ Exceptions = getContext().getLangOptions().Exceptions;
+ CatchUndefined = getContext().getLangOptions().CatchUndefined;
}
ASTContext &CodeGenFunction::getContext() const {
@@ -130,6 +134,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
}
EmitFunctionEpilog(*CurFnInfo, ReturnValue);
+ EmitEndEHSpec(CurCodeDecl);
// If someone did an indirect goto, emit the indirect goto block at the end of
// the function.
@@ -179,9 +184,6 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
AllocaInsertPt->setName("allocapt");
ReturnBlock = createBasicBlock("return");
- ReturnValue = 0;
- if (!RetTy->isVoidType())
- ReturnValue = CreateTempAlloca(ConvertType(RetTy), "retval");
Builder.SetInsertPoint(EntryBB);
@@ -195,15 +197,26 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
DI->EmitFunctionStart(CGM.getMangledName(GD), FnType, CurFn, Builder);
} else {
// Just use LLVM function name.
-
- // FIXME: Remove unnecessary conversion to std::string when API settles.
- DI->EmitFunctionStart(std::string(Fn->getName()).c_str(),
- FnType, CurFn, Builder);
+ DI->EmitFunctionStart(Fn->getName(), FnType, CurFn, Builder);
}
}
// FIXME: Leaked.
CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args);
+
+ if (RetTy->isVoidType()) {
+ // Void type; nothing to return.
+ ReturnValue = 0;
+ } else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect &&
+ hasAggregateLLVMType(CurFnInfo->getReturnType())) {
+ // Indirect aggregate return; emit returned value directly into sret slot.
+ // This reduces code size, and is also affects correctness in C++.
+ ReturnValue = CurFn->arg_begin();
+ } else {
+ ReturnValue = CreateTempAlloca(ConvertType(RetTy), "retval");
+ }
+
+ EmitStartEHSpec(CurCodeDecl);
EmitFunctionProlog(*CurFnInfo, CurFn, Args);
// If any of the arguments have a variably modified type, make sure to
@@ -245,6 +258,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD,
FunctionArgList Args;
+ CurGD = GD;
+ OuterTryBlock = 0;
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
if (MD->isInstance()) {
// Create the implicit 'this' decl.
@@ -276,7 +291,6 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD,
FProto->getArgType(i)));
}
- // FIXME: Support CXXTryStmt here, too.
if (const CompoundStmt *S = FD->getCompoundBody()) {
StartFunction(GD, FD->getResultType(), Fn, Args, S->getLBracLoc());
@@ -341,6 +355,13 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD,
} else {
assert(false && "Cannot synthesize unknown implicit function");
}
+ } else if (const Stmt *S = FD->getBody()) {
+ if (const CXXTryStmt *TS = dyn_cast<CXXTryStmt>(S)) {
+ OuterTryBlock = TS;
+ StartFunction(GD, FD->getResultType(), Fn, Args, TS->getTryLoc());
+ EmitStmt(TS);
+ FinishFunction(TS->getEndLoc());
+ }
}
// Destroy the 'this' declaration.
@@ -606,8 +627,11 @@ llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) {
}
void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock,
- llvm::BasicBlock *CleanupExitBlock) {
- CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock));
+ llvm::BasicBlock *CleanupExitBlock,
+ llvm::BasicBlock *PreviousInvokeDest,
+ bool EHOnly) {
+ CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock,
+ PreviousInvokeDest, EHOnly));
}
void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize) {
@@ -629,6 +653,10 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() {
std::vector<llvm::BranchInst *> BranchFixups;
std::swap(BranchFixups, CE.BranchFixups);
+ bool EHOnly = CE.EHOnly;
+
+ setInvokeDest(CE.PreviousInvokeDest);
+
CleanupEntries.pop_back();
// Check if any branch fixups pointed to the scope we just popped. If so,
@@ -663,8 +691,9 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() {
Builder.SetInsertPoint(SwitchBlock);
- llvm::Value *DestCodePtr = CreateTempAlloca(llvm::Type::getInt32Ty(VMContext),
- "cleanup.dst");
+ llvm::Value *DestCodePtr
+ = CreateTempAlloca(llvm::Type::getInt32Ty(VMContext),
+ "cleanup.dst");
llvm::Value *DestCode = Builder.CreateLoad(DestCodePtr, "tmp");
// Create a switch instruction to determine where to jump next.
@@ -710,15 +739,16 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() {
new llvm::StoreInst(ID, DestCodePtr, BI);
} else {
// We need to jump through another cleanup block. Create a pad block
- // with a branch instruction that jumps to the final destination and
- // add it as a branch fixup to the current cleanup scope.
+ // with a branch instruction that jumps to the final destination and add
+ // it as a branch fixup to the current cleanup scope.
// Create the pad block.
llvm::BasicBlock *CleanupPad = createBasicBlock("cleanup.pad", CurFn);
// Create a unique case ID.
- llvm::ConstantInt *ID = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- SI->getNumSuccessors());
+ llvm::ConstantInt *ID
+ = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+ SI->getNumSuccessors());
// Store the jump destination before the branch instruction.
new llvm::StoreInst(ID, DestCodePtr, BI);
@@ -744,12 +774,19 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() {
BlockScopes.erase(Blocks[i]);
}
- return CleanupBlockInfo(CleanupEntryBlock, SwitchBlock, EndBlock);
+ return CleanupBlockInfo(CleanupEntryBlock, SwitchBlock, EndBlock, EHOnly);
}
void CodeGenFunction::EmitCleanupBlock() {
CleanupBlockInfo Info = PopCleanupBlock();
+ if (Info.EHOnly) {
+ // FIXME: Add this to the exceptional edge
+ if (Info.CleanupBlock->getNumUses() == 0)
+ delete Info.CleanupBlock;
+ return;
+ }
+
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 7f32045..12e636c 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -88,11 +88,17 @@ public:
QualType FnRetTy;
llvm::Function *CurFn;
+ /// CurGD - The GlobalDecl for the current function being compiled.
+ GlobalDecl CurGD;
+ /// OuterTryBlock - This is the address of the outter most try block, 0
+ /// otherwise.
+ const Stmt *OuterTryBlock;
+
/// ReturnBlock - Unified return block.
llvm::BasicBlock *ReturnBlock;
/// ReturnValue - The temporary alloca to hold the return value. This is null
/// iff the function has no return value.
- llvm::Instruction *ReturnValue;
+ llvm::Value *ReturnValue;
/// AllocaInsertPoint - This is an instruction in the entry block before which
/// we prefer to insert allocas.
@@ -101,6 +107,8 @@ public:
const llvm::Type *LLVMIntTy;
uint32_t LLVMPointerWidth;
+ bool Exceptions;
+ bool CatchUndefined;
public:
/// ObjCEHValueStack - Stack of Objective-C exception values, used for
/// rethrows.
@@ -109,7 +117,12 @@ public:
/// PushCleanupBlock - Push a new cleanup entry on the stack and set the
/// passed in block as the cleanup block.
void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock,
- llvm::BasicBlock *CleanupExitBlock = 0);
+ llvm::BasicBlock *CleanupExitBlock,
+ llvm::BasicBlock *PreviousInvokeDest,
+ bool EHOnly = false);
+ void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock) {
+ PushCleanupBlock(CleanupEntryBlock, 0, getInvokeDest(), false);
+ }
/// CleanupBlockInfo - A struct representing a popped cleanup block.
struct CleanupBlockInfo {
@@ -123,14 +136,43 @@ public:
/// EndBlock - the default destination for the switch instruction.
llvm::BasicBlock *EndBlock;
+ /// EHOnly - True iff this cleanup should only be performed on the
+ /// exceptional edge.
+ bool EHOnly;
+
CleanupBlockInfo(llvm::BasicBlock *cb, llvm::BasicBlock *sb,
- llvm::BasicBlock *eb)
- : CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb) {}
+ llvm::BasicBlock *eb, bool ehonly = false)
+ : CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb), EHOnly(ehonly) {}
+ };
+
+ /// EHCleanupBlock - RAII object that will create a cleanup block for the
+ /// exceptional edge and set the insert point to that block. When destroyed,
+ /// it creates the cleanup edge and sets the insert point to the previous
+ /// block.
+ class EHCleanupBlock {
+ CodeGenFunction& CGF;
+ llvm::BasicBlock *Cont;
+ 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")),
+ PreviousInvokeDest(CGF.getInvokeDest()) {
+ CGF.EmitBranch(Cont);
+ llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler();
+ CGF.Builder.SetInsertPoint(CleanupEntryBB);
+ CGF.setInvokeDest(TerminateHandler);
+ }
+ ~EHCleanupBlock();
};
/// PopCleanupBlock - Will pop the cleanup entry on the stack, process all
/// branch fixups and return a block info struct with the switch block and end
- /// block.
+ /// block. This will also reset the invoke handler to the previous value
+ /// from when the cleanup block was created.
CleanupBlockInfo PopCleanupBlock();
/// DelayedCleanupBlock - RAII object that will create a cleanup block and set
@@ -141,11 +183,15 @@ public:
llvm::BasicBlock *CurBB;
llvm::BasicBlock *CleanupEntryBB;
llvm::BasicBlock *CleanupExitBB;
+ llvm::BasicBlock *CurInvokeDest;
+ bool EHOnly;
public:
- DelayedCleanupBlock(CodeGenFunction &cgf)
+ 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);
}
@@ -156,7 +202,8 @@ public:
}
~DelayedCleanupBlock() {
- CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB);
+ CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB, CurInvokeDest,
+ EHOnly);
// FIXME: This is silly, move this into the builder.
if (CurBB)
CGF.Builder.SetInsertPoint(CurBB);
@@ -303,10 +350,21 @@ private:
/// inserted into the current function yet.
std::vector<llvm::BranchInst *> BranchFixups;
+ /// PreviousInvokeDest - The invoke handler from the start of the cleanup
+ /// region.
+ llvm::BasicBlock *PreviousInvokeDest;
+
+ /// EHOnly - Perform this only on the exceptional edge, not the main edge.
+ bool EHOnly;
+
explicit CleanupEntry(llvm::BasicBlock *CleanupEntryBlock,
- llvm::BasicBlock *CleanupExitBlock)
- : CleanupEntryBlock(CleanupEntryBlock),
- CleanupExitBlock(CleanupExitBlock) {}
+ llvm::BasicBlock *CleanupExitBlock,
+ llvm::BasicBlock *PreviousInvokeDest,
+ bool ehonly)
+ : CleanupEntryBlock(CleanupEntryBlock),
+ CleanupExitBlock(CleanupExitBlock),
+ PreviousInvokeDest(PreviousInvokeDest),
+ EHOnly(ehonly) {}
};
/// CleanupEntries - Stack of cleanup entries.
@@ -365,7 +423,11 @@ private:
/// getByrefValueFieldNumber - Given a declaration, returns the LLVM field
/// number that holds the value.
unsigned getByRefValueLLVMField(const ValueDecl *VD) const;
-
+
+ llvm::BasicBlock *TerminateHandler;
+ llvm::BasicBlock *TrapBB;
+
+ int UniqueAggrDestructorCount;
public:
CodeGenFunction(CodeGenModule &cgm);
@@ -441,16 +503,18 @@ public:
const ThunkAdjustment &Adjustment);
/// GenerateThunk - Generate a thunk for the given method
- llvm::Constant *GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD,
+ llvm::Constant *GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
bool Extern,
const ThunkAdjustment &ThisAdjustment);
llvm::Constant *
- GenerateCovariantThunk(llvm::Function *Fn, const CXXMethodDecl *MD,
+ GenerateCovariantThunk(llvm::Function *Fn, GlobalDecl GD,
bool Extern,
const CovariantThunkAdjustment &Adjustment);
void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type);
+ void InitializeVtablePtrs(const CXXRecordDecl *ClassDecl);
+
void SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
CXXCtorType Type,
llvm::Function *Fn,
@@ -487,6 +551,15 @@ public:
/// given temporary.
void EmitFunctionEpilog(const CGFunctionInfo &FI, llvm::Value *ReturnValue);
+ /// EmitStartEHSpec - Emit the start of the exception spec.
+ void EmitStartEHSpec(const Decl *D);
+
+ /// EmitEndEHSpec - Emit the end of the exception spec.
+ void EmitEndEHSpec(const Decl *D);
+
+ /// getTerminateHandler - Return a handler that just calls terminate.
+ llvm::BasicBlock *getTerminateHandler();
+
const llvm::Type *ConvertTypeForMem(QualType T);
const llvm::Type *ConvertType(QualType T);
@@ -903,6 +976,7 @@ public:
LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E);
LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E);
LValue EmitMemberExpr(const MemberExpr *E);
+ LValue EmitObjCIsaExpr(const ObjCIsaExpr *E);
LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E);
LValue EmitConditionalOperatorLValue(const ConditionalOperator *E);
LValue EmitCastLValue(const CastExpr *E);
@@ -1059,9 +1133,18 @@ public:
/// CreateStaticBlockVarDecl - Create a zero-initialized LLVM global for a
/// static block var decl.
- llvm::GlobalVariable * CreateStaticBlockVarDecl(const VarDecl &D,
- const char *Separator,
+ llvm::GlobalVariable *CreateStaticBlockVarDecl(const VarDecl &D,
+ const char *Separator,
llvm::GlobalValue::LinkageTypes Linkage);
+
+ /// AddInitializerToGlobalBlockVarDecl - Add the initializer for 'D' to the
+ /// global variable that has already been created for it. If the initializer
+ /// has a different type than GV does, this may free GV and return a different
+ /// one. Otherwise it just returns GV.
+ llvm::GlobalVariable *
+ AddInitializerToGlobalBlockVarDecl(const VarDecl &D,
+ llvm::GlobalVariable *GV);
+
/// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++ runtime
/// initialized static block var decl.
@@ -1112,6 +1195,10 @@ public:
/// try to simplify the codegen of the conditional based on the branch.
void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock,
llvm::BasicBlock *FalseBlock);
+
+ /// getTrapBB - Create a basic block that will call the trap intrinsic. We'll
+ /// generate a branch around the created basic block as necessary.
+ llvm::BasicBlock* getTrapBB();
private:
void EmitReturnOfRValue(RValue RV, QualType Ty);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 4b3b122..761f343 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -56,7 +56,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
Runtime = CreateMacObjCRuntime(*this);
// If debug info generation is enabled, create the CGDebugInfo object.
- DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(this) : 0;
+ DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(*this) : 0;
}
CodeGenModule::~CodeGenModule() {
@@ -256,9 +256,18 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
// The kind of external linkage this function will have, if it is not
// inline or static.
CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal;
- if (Context.getLangOptions().CPlusPlus &&
- FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
- External = CodeGenModule::GVA_TemplateInstantiation;
+ if (Context.getLangOptions().CPlusPlus) {
+ TemplateSpecializationKind TSK = FD->getTemplateSpecializationKind();
+
+ if (TSK == TSK_ExplicitInstantiationDefinition) {
+ // If a function has been explicitly instantiated, then it should
+ // always have strong external linkage.
+ return CodeGenModule::GVA_StrongExternal;
+ }
+
+ if (TSK == TSK_ImplicitInstantiation)
+ External = CodeGenModule::GVA_TemplateInstantiation;
+ }
if (!FD->isInlined())
return External;
@@ -522,6 +531,16 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
FD->hasAttr<DestructorAttr>())
return false;
+ // The key function for a class must never be deferred.
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Global)) {
+ const CXXRecordDecl *RD = MD->getParent();
+ if (MD->isOutOfLine() && RD->isDynamicClass()) {
+ const CXXMethodDecl *KeyFunction = getContext().getKeyFunction(RD);
+ if (KeyFunction == MD->getCanonicalDecl())
+ return false;
+ }
+ }
+
GVALinkage Linkage = GetLinkageForFunction(getContext(), FD, Features);
// static, static inline, always_inline, and extern inline functions can
@@ -576,11 +595,17 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
const VarDecl *VD = cast<VarDecl>(Global);
assert(VD->isFileVarDecl() && "Cannot emit local var decl as global.");
- // In C++, if this is marked "extern", defer code generation.
- if (getLangOptions().CPlusPlus && !VD->getInit() &&
- (VD->getStorageClass() == VarDecl::Extern ||
- VD->isExternC()))
- return;
+ if (getLangOptions().CPlusPlus && !VD->getInit()) {
+ // In C++, if this is marked "extern", defer code generation.
+ if (VD->getStorageClass() == VarDecl::Extern || VD->isExternC())
+ return;
+
+ // If this is a declaration of an explicit specialization of a static
+ // data member in a class template, don't emit it.
+ if (VD->isStaticDataMember() &&
+ VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ return;
+ }
// In C, if this isn't a definition, defer code generation.
if (!getLangOptions().CPlusPlus && !VD->getInit())
@@ -615,8 +640,19 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
Context.getSourceManager(),
"Generating code for declaration");
- if (isa<CXXMethodDecl>(D))
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
getVtableInfo().MaybeEmitVtable(GD);
+ if (MD->isVirtual() && MD->isOutOfLine() &&
+ (!isa<CXXDestructorDecl>(D) || GD.getDtorType() != Dtor_Base)) {
+ if (isa<CXXDestructorDecl>(D)) {
+ GlobalDecl CanonGD(cast<CXXDestructorDecl>(D->getCanonicalDecl()),
+ GD.getDtorType());
+ BuildThunksForVirtual(CanonGD);
+ } else {
+ BuildThunksForVirtual(MD->getCanonicalDecl());
+ }
+ }
+ }
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
EmitCXXConstructor(CD, GD.getCtorType());
@@ -724,6 +760,17 @@ CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy,
return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl());
}
+static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D) {
+ if (!D->getType().isConstant(Context))
+ return false;
+ if (Context.getLangOptions().CPlusPlus &&
+ Context.getBaseElementType(D->getType())->getAs<RecordType>()) {
+ // FIXME: We should do something fancier here!
+ return false;
+ }
+ return true;
+}
+
/// GetOrCreateLLVMGlobal - If the specified mangled name is not in the module,
/// create and return an llvm GlobalVariable with the specified type. If there
/// is something in the module with the specified name, return it potentially
@@ -767,7 +814,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName,
if (D) {
// FIXME: This code is overly simple and should be merged with other global
// handling.
- GV->setConstant(D->getType().isConstant(Context));
+ GV->setConstant(DeclIsConstantGlobal(Context, D));
// FIXME: Merge with other attribute handling code.
if (D->getStorageClass() == VarDecl::PrivateExtern)
@@ -844,7 +891,7 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
return CodeGenModule::GVA_StrongExternal;
case TSK_ExplicitInstantiationDeclaration:
- llvm::llvm_unreachable("Variable should not be instantiated");
+ llvm_unreachable("Variable should not be instantiated");
// Fall through to treat this like any other instantiation.
case TSK_ImplicitInstantiation:
@@ -942,11 +989,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
// If it is safe to mark the global 'constant', do so now.
GV->setConstant(false);
- if (D->getType().isConstant(Context)) {
- // FIXME: In C++, if the variable has a non-trivial ctor/dtor or any mutable
- // members, it cannot be declared "LLVM const".
+ if (DeclIsConstantGlobal(Context, D))
GV->setConstant(true);
- }
GV->setAlignment(getContext().getDeclAlignInBytes(D));
@@ -1226,13 +1270,8 @@ llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
if (Context.BuiltinInfo.isLibFunction(BuiltinID))
Name += 10;
- // Get the type for the builtin.
- ASTContext::GetBuiltinTypeError Error;
- QualType Type = Context.GetBuiltinType(BuiltinID, Error);
- assert(Error == ASTContext::GE_None && "Can't get builtin type");
-
const llvm::FunctionType *Ty =
- cast<llvm::FunctionType>(getTypes().ConvertType(Type));
+ cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType()));
// Unique the name through the identifier table.
Name = getContext().Idents.get(Name).getNameStart();
@@ -1658,14 +1697,13 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::FileScopeAsm: {
FileScopeAsmDecl *AD = cast<FileScopeAsmDecl>(D);
- std::string AsmString(AD->getAsmString()->getStrData(),
- AD->getAsmString()->getByteLength());
+ llvm::StringRef AsmString = AD->getAsmString()->getString();
const std::string &S = getModule().getModuleInlineAsm();
if (S.empty())
getModule().setModuleInlineAsm(AsmString);
else
- getModule().setModuleInlineAsm(S + '\n' + AsmString);
+ getModule().setModuleInlineAsm(S + '\n' + AsmString.str());
break;
}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 78bc4ed..cc7ec9c 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -212,34 +212,38 @@ public:
llvm::Constant *GetAddrOfFunction(GlobalDecl GD,
const llvm::Type *Ty = 0);
- /// GenerateVtable - Generate the vtable for the given type. LayoutClass is
- /// the class to use for the virtual base layout information. For
- /// non-construction vtables, this is always the same as RD. Offset is the
- /// offset in bits for the RD object in the LayoutClass, if we're generating a
- /// construction vtable, otherwise 0.
- llvm::Constant *GenerateVtable(const CXXRecordDecl *LayoutClass,
- const CXXRecordDecl *RD,
- uint64_t Offset=0);
-
- /// GenerateVTT - Generate the VTT for the given type.
- llvm::Constant *GenerateVTT(const CXXRecordDecl *RD);
-
- /// GenerateRtti - Generate the rtti information for the given type.
- llvm::Constant *GenerateRtti(const CXXRecordDecl *RD);
- /// GenerateRttiRef - Generate a reference to the rtti information for the
+ /// GetAddrOfRTTI - Get the address of the RTTI structure for the given type.
+ llvm::Constant *GetAddrOfRTTI(QualType Ty);
+
+ /// GetAddrOfRTTI - Get the address of the RTTI structure for the given record
+ /// decl.
+ llvm::Constant *GetAddrOfRTTI(const CXXRecordDecl *RD);
+
+ /// GenerateRTTI - Generate the rtti information for the given type.
+ llvm::Constant *GenerateRTTI(const CXXRecordDecl *RD);
+
+ /// GenerateRTTIRef - Generate a reference to the rtti information for the
/// given type.
- llvm::Constant *GenerateRttiRef(const CXXRecordDecl *RD);
- /// GenerateRttiNonClass - Generate the rtti information for the given
+ llvm::Constant *GenerateRTTIRef(const CXXRecordDecl *RD);
+
+ /// GenerateRTTI - Generate the rtti information for the given
/// non-class type.
- llvm::Constant *GenerateRtti(QualType Ty);
+ llvm::Constant *GenerateRTTI(QualType Ty);
+
+ llvm::Constant *GetAddrOfThunk(GlobalDecl GD,
+ const ThunkAdjustment &ThisAdjustment);
+ llvm::Constant *GetAddrOfCovariantThunk(GlobalDecl GD,
+ const CovariantThunkAdjustment &ThisAdjustment);
+ void BuildThunksForVirtual(GlobalDecl GD);
+ void BuildThunksForVirtualRecursive(GlobalDecl GD, GlobalDecl BaseOGD);
/// BuildThunk - Build a thunk for the given method.
- llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern,
+ llvm::Constant *BuildThunk(GlobalDecl GD, bool Extern,
const ThunkAdjustment &ThisAdjustment);
/// BuildCoVariantThunk - Build a thunk for the given method
llvm::Constant *
- BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern,
+ BuildCovariantThunk(const GlobalDecl &GD, bool Extern,
const CovariantThunkAdjustment &Adjustment);
typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
@@ -252,6 +256,11 @@ public:
llvm::Constant *GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl);
+ /// ComputeThunkAdjustment - Returns the two parts required to compute the
+ /// offset for an object.
+ ThunkAdjustment ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl);
+
/// 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.
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index c89879f..cd3575c 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -379,13 +379,13 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
// If we ever want to support other ABIs this needs to be abstracted.
QualType ETy = cast<MemberPointerType>(Ty).getPointeeType();
+ const llvm::Type *PtrDiffTy =
+ ConvertTypeRecursive(Context.getPointerDiffType());
if (ETy->isFunctionType()) {
- return llvm::StructType::get(TheModule.getContext(),
- ConvertType(Context.getPointerDiffType()),
- ConvertType(Context.getPointerDiffType()),
+ return llvm::StructType::get(TheModule.getContext(), PtrDiffTy, PtrDiffTy,
NULL);
} else
- return ConvertType(Context.getPointerDiffType());
+ return PtrDiffTy;
}
case Type::TemplateSpecialization:
diff --git a/lib/CodeGen/GlobalDecl.h b/lib/CodeGen/GlobalDecl.h
index b812020..b054312 100644
--- a/lib/CodeGen/GlobalDecl.h
+++ b/lib/CodeGen/GlobalDecl.h
@@ -96,15 +96,14 @@ namespace llvm {
return LHS == RHS;
}
- static bool isPod() {
- // GlobalDecl isn't *technically* a POD type. However, we can get
- // away with calling it a POD type since its copy constructor,
- // copy assignment operator, and destructor are all trivial.
- return true;
- }
-
};
-}
+ // GlobalDecl isn't *technically* a POD type. However, its copy constructor,
+ // copy assignment operator, and destructor are all trivial.
+ template <>
+ struct isPodLike<clang::CodeGen::GlobalDecl> {
+ static const bool value = true;
+ };
+} // end namespace llvm
#endif
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index d6f7808..90cc894 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -89,8 +89,6 @@ private:
void addSubstitution(QualType T);
void addSubstitution(uintptr_t Ptr);
- bool mangleFunctionDecl(const FunctionDecl *FD);
-
void mangleName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
@@ -99,7 +97,7 @@ private:
void mangleUnscopedTemplateName(const TemplateDecl *ND);
void mangleSourceName(const IdentifierInfo *II);
void mangleLocalName(const NamedDecl *ND);
- void mangleNestedName(const NamedDecl *ND);
+ void mangleNestedName(const NamedDecl *ND, const DeclContext *DC);
void mangleNestedName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
@@ -108,6 +106,8 @@ private:
void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
void mangleQualifiers(Qualifiers Quals);
+ void mangleObjCMethodName(const ObjCMethodDecl *MD);
+
// Declare manglers for every type class.
#define ABSTRACT_TYPE(CLASS, PARENT)
#define NON_CANONICAL_TYPE(CLASS, PARENT)
@@ -117,6 +117,8 @@ private:
void mangleType(const TagType*);
void mangleBareFunctionType(const FunctionType *T,
bool MangleReturnType);
+
+ void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value);
void mangleExpression(const Expr *E);
void mangleCXXCtorType(CXXCtorType T);
void mangleCXXDtorType(CXXDtorType T);
@@ -169,11 +171,19 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
isInExternCSystemHeader(D->getLocation()))
return false;
- // C functions, "main", and variables at global scope are not
- // mangled.
- if ((FD && FD->isMain()) ||
- (!FD && D->getDeclContext()->isTranslationUnit()) ||
- isInCLinkageSpecification(D))
+ // Variables at global scope are not mangled.
+ if (!FD) {
+ const DeclContext *DC = D->getDeclContext();
+ // Check for extern variable declared locally.
+ if (isa<FunctionDecl>(DC) && D->hasLinkage())
+ while (!DC->isNamespace() && !DC->isTranslationUnit())
+ DC = DC->getParent();
+ if (DC->isTranslationUnit())
+ return false;
+ }
+
+ // C functions and "main" are not mangled.
+ if ((FD && FD->isMain()) || isInCLinkageSpecification(D))
return false;
return true;
@@ -241,14 +251,32 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
mangleBareFunctionType(FT, MangleReturnType);
}
-static bool isStdNamespace(const NamespaceDecl *NS) {
+/// isStd - Return whether a given namespace is the 'std' namespace.
+static bool isStd(const NamespaceDecl *NS) {
const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier();
return II && II->isStr("std");
}
+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();
+ }
+
+ return DC;
+}
+
+// isStdNamespace - Return whether a given decl context is a toplevel 'std'
+// namespace.
static bool isStdNamespace(const DeclContext *DC) {
- return DC->isNamespace() && DC->getParent()->isTranslationUnit() &&
- isStdNamespace(cast<NamespaceDecl>(DC));
+ if (!DC->isNamespace())
+ return false;
+
+ if (!IgnoreLinkageSpecDecls(DC->getParent())->isTranslationUnit())
+ return false;
+
+ return isStd(cast<NamespaceDecl>(DC));
}
static const TemplateDecl *
@@ -278,6 +306,13 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
// ::= <local-name>
//
const DeclContext *DC = ND->getDeclContext();
+
+ // If this is an extern variable declared locally, the relevant DeclContext
+ // is that of the containing namespace, or the translation unit.
+ if (isa<FunctionDecl>(DC) && ND->hasLinkage())
+ while (!DC->isNamespace() && !DC->isTranslationUnit())
+ DC = DC->getParent();
+
while (isa<LinkageSpecDecl>(DC))
DC = DC->getParent();
@@ -294,22 +329,17 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
return;
}
- if (isa<FunctionDecl>(DC)) {
+ if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) {
mangleLocalName(ND);
return;
}
- mangleNestedName(ND);
+ mangleNestedName(ND, DC);
}
void CXXNameMangler::mangleName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
- const DeclContext *DC = TD->getDeclContext();
- while (isa<LinkageSpecDecl>(DC)) {
- assert(cast<LinkageSpecDecl>(DC)->getLanguage() ==
- LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!");
- DC = DC->getParent();
- }
+ const DeclContext *DC = IgnoreLinkageSpecDecls(TD->getDeclContext());
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
mangleUnscopedTemplateName(TD);
@@ -456,8 +486,8 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
break;
case DeclarationName::CXXLiteralOperatorName:
- // Guessing based on existing ABI.
- Out << "ul";
+ // FIXME: This mangling is not yet official.
+ Out << "li";
mangleSourceName(Name.getCXXLiteralIdentifier());
break;
@@ -474,7 +504,8 @@ void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
Out << II->getLength() << II->getName();
}
-void CXXNameMangler::mangleNestedName(const NamedDecl *ND) {
+void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
+ const DeclContext *DC) {
// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
// ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
@@ -488,7 +519,7 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND) {
mangleTemplatePrefix(TD);
mangleTemplateArgumentList(*TemplateArgs);
} else {
- manglePrefix(ND->getDeclContext());
+ manglePrefix(DC);
mangleUnqualifiedName(ND);
}
@@ -512,9 +543,14 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
// := Z <function encoding> E s [<discriminator>]
// <discriminator> := _ <non-negative number>
Out << 'Z';
- mangleFunctionEncoding(cast<FunctionDecl>(ND->getDeclContext()));
+
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND->getDeclContext()))
+ mangleObjCMethodName(MD);
+ else
+ mangleFunctionEncoding(cast<FunctionDecl>(ND->getDeclContext()));
+
Out << 'E';
- mangleSourceName(ND->getIdentifier());
+ mangleUnqualifiedName(ND);
}
void CXXNameMangler::manglePrefix(const DeclContext *DC) {
@@ -523,7 +559,6 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC) {
// ::= <template-param>
// ::= # empty
// ::= <substitution>
- // FIXME: We only handle mangling of namespaces and classes at the moment.
while (isa<LinkageSpecDecl>(DC))
DC = DC->getParent();
@@ -654,10 +689,13 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
case OO_Call: Out << "cl"; break;
// ::= ix # []
case OO_Subscript: Out << "ix"; break;
- // UNSUPPORTED: ::= qu # ?
+
+ // ::= qu # ?
+ // The conditional operator can't be overloaded, but we still handle it when
+ // mangling expressions.
+ case OO_Conditional: Out << "qu"; break;
case OO_None:
- case OO_Conditional:
case NUM_OVERLOADED_OPERATORS:
assert(false && "Not an overloaded operator");
break;
@@ -676,6 +714,21 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
// FIXME: For now, just drop all extension qualifiers on the floor.
}
+void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
+ llvm::SmallString<64> Name;
+ llvm::raw_svector_ostream OS(Name);
+
+ const ObjCContainerDecl *CD =
+ dyn_cast<ObjCContainerDecl>(MD->getDeclContext());
+ assert (CD && "Missing container decl in GetNameForMethod");
+ OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName();
+ if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD))
+ OS << '(' << CID->getNameAsString() << ')';
+ OS << ' ' << MD->getSelector().getAsString() << ']';
+
+ Out << OS.str().size() << OS.str();
+}
+
void CXXNameMangler::mangleType(QualType T) {
// Only operate on the canonical type!
T = Context.getASTContext().getCanonicalType(T);
@@ -694,7 +747,7 @@ void CXXNameMangler::mangleType(QualType T) {
#define ABSTRACT_TYPE(CLASS, PARENT)
#define NON_CANONICAL_TYPE(CLASS, PARENT) \
case Type::CLASS: \
- llvm::llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \
+ llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \
return;
#define TYPE(CLASS, PARENT) \
case Type::CLASS: \
@@ -788,7 +841,7 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) {
Out << 'E';
}
void CXXNameMangler::mangleType(const FunctionNoProtoType *T) {
- llvm::llvm_unreachable("Can't mangle K&R function prototypes");
+ llvm_unreachable("Can't mangle K&R function prototypes");
}
void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
bool MangleReturnType) {
@@ -816,6 +869,12 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
// <type> ::= <class-enum-type>
// <class-enum-type> ::= <name>
+void CXXNameMangler::mangleType(const UnresolvedUsingType *T) {
+ mangleName(T->getDecl());
+}
+
+// <type> ::= <class-enum-type>
+// <class-enum-type> ::= <name>
void CXXNameMangler::mangleType(const EnumType *T) {
mangleType(static_cast<const TagType*>(T));
}
@@ -823,10 +882,7 @@ void CXXNameMangler::mangleType(const RecordType *T) {
mangleType(static_cast<const TagType*>(T));
}
void CXXNameMangler::mangleType(const TagType *T) {
- if (!T->getDecl()->getIdentifier())
- mangleName(T->getDecl()->getTypedefForAnonDecl());
- else
- mangleName(T->getDecl());
+ mangleName(T->getDecl());
}
// <type> ::= <array-type>
@@ -960,6 +1016,24 @@ void CXXNameMangler::mangleType(const TypenameType *T) {
Out << 'E';
}
+void CXXNameMangler::mangleIntegerLiteral(QualType T,
+ const llvm::APSInt &Value) {
+ // <expr-primary> ::= L <type> <value number> E # integer literal
+ Out << 'L';
+
+ mangleType(T);
+ if (T->isBooleanType()) {
+ // Boolean values are encoded as 0/1.
+ Out << (Value.getBoolValue() ? '1' : '0');
+ } else {
+ if (Value.isNegative())
+ Out << 'n';
+ Value.abs().print(Out, false);
+ }
+ Out << 'E';
+
+}
+
void CXXNameMangler::mangleExpression(const Expr *E) {
// <expression> ::= <unary operator-name> <expression>
// ::= <binary operator-name> <expression> <expression>
@@ -978,6 +1052,32 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
switch (E->getStmtClass()) {
default: assert(false && "Unhandled expression kind!");
+ case Expr::UnaryOperatorClass: {
+ const UnaryOperator *UO = cast<UnaryOperator>(E);
+ mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()),
+ /*Arity=*/1);
+ mangleExpression(UO->getSubExpr());
+ break;
+ }
+
+ case Expr::BinaryOperatorClass: {
+ const BinaryOperator *BO = cast<BinaryOperator>(E);
+ mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()),
+ /*Arity=*/2);
+ mangleExpression(BO->getLHS());
+ mangleExpression(BO->getRHS());
+ break;
+ }
+
+ case Expr::ConditionalOperatorClass: {
+ const ConditionalOperator *CO = cast<ConditionalOperator>(E);
+ mangleOperatorName(OO_Conditional, /*Arity=*/3);
+ mangleExpression(CO->getCond());
+ mangleExpression(CO->getLHS());
+ mangleExpression(CO->getRHS());
+ break;
+ }
+
case Expr::ParenExprClass:
mangleExpression(cast<ParenExpr>(E)->getSubExpr());
break;
@@ -1014,6 +1114,11 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
break;
}
+ case Expr::IntegerLiteralClass:
+ mangleIntegerLiteral(E->getType(),
+ llvm::APSInt(cast<IntegerLiteral>(E)->getValue()));
+ break;
+
}
}
@@ -1090,23 +1195,9 @@ void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) {
mangleExpression(A.getAsExpr());
Out << 'E';
break;
- case TemplateArgument::Integral: {
- // <expr-primary> ::= L <type> <value number> E # integer literal
-
- const llvm::APSInt *Integral = A.getAsIntegral();
- Out << 'L';
- mangleType(A.getIntegralType());
- if (A.getIntegralType()->isBooleanType()) {
- // Boolean values are encoded as 0/1.
- Out << (Integral->getBoolValue() ? '1' : '0');
- } else {
- if (Integral->isNegative())
- Out << 'n';
- Integral->abs().print(Out, false);
- }
- Out << 'E';
+ case TemplateArgument::Integral:
+ mangleIntegerLiteral(A.getIntegralType(), *A.getAsIntegral());
break;
- }
case TemplateArgument::Declaration: {
// <expr-primary> ::= L <mangled-name> E # external name
@@ -1228,12 +1319,29 @@ static bool isCharSpecialization(QualType T, const char *Name) {
return SD->getIdentifier()->getName() == Name;
}
+template <std::size_t StrLen>
+bool isStreamCharSpecialization(const ClassTemplateSpecializationDecl *SD,
+ const char (&Str)[StrLen]) {
+ if (!SD->getIdentifier()->isStr(Str))
+ return false;
+
+ const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
+ if (TemplateArgs.size() != 2)
+ return false;
+
+ if (!isCharType(TemplateArgs[0].getAsType()))
+ return false;
+
+ if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
+ return false;
+
+ return true;
+}
+
bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
// <substitution> ::= St # ::std::
- // FIXME: type_info == comes out as __ZNK3std9type_infoeqERKS0_ instead of
- // __ZNKSt9type_infoeqERKS_
if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
- if (isStdNamespace(NS)) {
+ if (isStd(NS)) {
Out << "St";
return true;
}
@@ -1280,23 +1388,26 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
return true;
}
- // <substitution> ::= So # ::std::basic_ostream<char,
+ // <substitution> ::= Si # ::std::basic_istream<char,
// ::std::char_traits<char> >
- if (SD->getIdentifier()->isStr("basic_ostream")) {
- const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
-
- if (TemplateArgs.size() != 2)
- return false;
-
- if (!isCharType(TemplateArgs[0].getAsType()))
- return false;
-
- if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
- return false;
+ if (isStreamCharSpecialization(SD, "basic_istream")) {
+ Out << "Si";
+ return true;
+ }
+ // <substitution> ::= So # ::std::basic_ostream<char,
+ // ::std::char_traits<char> >
+ if (isStreamCharSpecialization(SD, "basic_ostream")) {
Out << "So";
return true;
}
+
+ // <substitution> ::= Sd # ::std::basic_iostream<char,
+ // ::std::char_traits<char> >
+ if (isStreamCharSpecialization(SD, "basic_iostream")) {
+ Out << "Sd";
+ return true;
+ }
}
return false;
}
@@ -1362,7 +1473,6 @@ void MangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
void MangleContext::mangleThunk(const FunctionDecl *FD,
const ThunkAdjustment &ThisAdjustment,
llvm::SmallVectorImpl<char> &Res) {
- // FIXME: Hum, we might have to thunk these, fix.
assert(!isa<CXXDestructorDecl>(FD) &&
"Use mangleCXXDtor for destructor decls!");
@@ -1374,15 +1484,26 @@ void MangleContext::mangleThunk(const FunctionDecl *FD,
Mangler.mangleFunctionEncoding(FD);
}
+void MangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *D,
+ CXXDtorType Type,
+ const ThunkAdjustment &ThisAdjustment,
+ llvm::SmallVectorImpl<char> &Res) {
+ // <special-name> ::= T <call-offset> <base encoding>
+ // # base is the nominal target function of thunk
+ CXXNameMangler Mangler(*this, Res, D, Type);
+ Mangler.getStream() << "_ZT";
+ Mangler.mangleCallOffset(ThisAdjustment);
+ Mangler.mangleFunctionEncoding(D);
+}
+
/// \brief Mangles the a covariant thunk for the declaration D and emits that
/// name to the given output stream.
void
MangleContext::mangleCovariantThunk(const FunctionDecl *FD,
const CovariantThunkAdjustment& Adjustment,
llvm::SmallVectorImpl<char> &Res) {
- // FIXME: Hum, we might have to thunk these, fix.
assert(!isa<CXXDestructorDecl>(FD) &&
- "Use mangleCXXDtor for destructor decls!");
+ "No such thing as a covariant thunk for a destructor!");
// <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
// # base is the nominal target function of thunk
@@ -1434,7 +1555,7 @@ void MangleContext::mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
Mangler.mangleName(Type);
}
-void MangleContext::mangleCXXRtti(QualType Ty,
+void MangleContext::mangleCXXRTTI(QualType Ty,
llvm::SmallVectorImpl<char> &Res) {
// <special-name> ::= TI <type> # typeinfo structure
CXXNameMangler Mangler(*this, Res);
@@ -1442,7 +1563,7 @@ void MangleContext::mangleCXXRtti(QualType Ty,
Mangler.mangleType(Ty);
}
-void MangleContext::mangleCXXRttiName(QualType Ty,
+void MangleContext::mangleCXXRTTIName(QualType Ty,
llvm::SmallVectorImpl<char> &Res) {
// <special-name> ::= TS <type> # typeinfo name (null terminated byte string)
CXXNameMangler Mangler(*this, Res);
diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h
index 65b1d9f..8d96295 100644
--- a/lib/CodeGen/Mangle.h
+++ b/lib/CodeGen/Mangle.h
@@ -67,6 +67,9 @@ public:
void mangleThunk(const FunctionDecl *FD,
const ThunkAdjustment &ThisAdjustment,
llvm::SmallVectorImpl<char> &);
+ void mangleCXXDtorThunk(const CXXDestructorDecl *D, CXXDtorType Type,
+ const ThunkAdjustment &ThisAdjustment,
+ llvm::SmallVectorImpl<char> &);
void mangleCovariantThunk(const FunctionDecl *FD,
const CovariantThunkAdjustment& Adjustment,
llvm::SmallVectorImpl<char> &);
@@ -76,8 +79,8 @@ public:
void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
const CXXRecordDecl *Type,
llvm::SmallVectorImpl<char> &);
- void mangleCXXRtti(QualType T, llvm::SmallVectorImpl<char> &);
- void mangleCXXRttiName(QualType T, llvm::SmallVectorImpl<char> &);
+ void mangleCXXRTTI(QualType T, llvm::SmallVectorImpl<char> &);
+ void mangleCXXRTTIName(QualType T, llvm::SmallVectorImpl<char> &);
void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
llvm::SmallVectorImpl<char> &);
void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp
index 2bc6175..7be1ead 100644
--- a/lib/CodeGen/TargetABIInfo.cpp
+++ b/lib/CodeGen/TargetABIInfo.cpp
@@ -17,37 +17,37 @@
#include "clang/AST/RecordLayout.h"
#include "llvm/Type.h"
#include "llvm/ADT/Triple.h"
-#include <cstdio>
-
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace CodeGen;
ABIInfo::~ABIInfo() {}
void ABIArgInfo::dump() const {
- fprintf(stderr, "(ABIArgInfo Kind=");
+ llvm::raw_ostream &OS = llvm::errs();
+ OS << "(ABIArgInfo Kind=";
switch (TheKind) {
case Direct:
- fprintf(stderr, "Direct");
+ OS << "Direct";
break;
case Extend:
- fprintf(stderr, "Extend");
+ OS << "Extend";
break;
case Ignore:
- fprintf(stderr, "Ignore");
+ OS << "Ignore";
break;
case Coerce:
- fprintf(stderr, "Coerce Type=");
- getCoerceToType()->print(llvm::errs());
+ OS << "Coerce Type=";
+ getCoerceToType()->print(OS);
break;
case Indirect:
- fprintf(stderr, "Indirect Align=%d", getIndirectAlign());
+ OS << "Indirect Align=" << getIndirectAlign();
break;
case Expand:
- fprintf(stderr, "Expand");
+ OS << "Expand";
break;
}
- fprintf(stderr, ")\n");
+ OS << ")\n";
}
static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 87357cf..dbe7bd9 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -41,9 +41,9 @@ using namespace clang;
// Used to set values for "production" clang, for releases.
// #define USE_PRODUCTION_CLANG
-Driver::Driver(const char *_Name, const char *_Dir,
- const char *_DefaultHostTriple,
- const char *_DefaultImageName,
+Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir,
+ llvm::StringRef _DefaultHostTriple,
+ llvm::StringRef _DefaultImageName,
bool IsProduction, Diagnostic &_Diags)
: Opts(createDriverOptTable()), Diags(_Diags),
Name(_Name), Dir(_Dir), DefaultHostTriple(_DefaultHostTriple),
@@ -113,81 +113,57 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) {
const char **Start = argv + 1, **End = argv + argc;
const char *HostTriple = DefaultHostTriple.c_str();
- // Read -ccc args.
+ InputArgList *Args = ParseArgStrings(Start, End);
+
+ // -no-canonical-prefixes is used very early in main.
+ Args->ClaimAllArgs(options::OPT_no_canonical_prefixes);
+
+ // Extract -ccc args.
//
// FIXME: We need to figure out where this behavior should live. Most of it
// should be outside in the client; the parts that aren't should have proper
// options, either by introducing new ones or by overloading gcc ones like -V
// or -b.
- for (; Start != End && memcmp(*Start, "-ccc-", 5) == 0; ++Start) {
- const char *Opt = *Start + 5;
-
- if (!strcmp(Opt, "print-options")) {
- CCCPrintOptions = true;
- } else if (!strcmp(Opt, "print-phases")) {
- CCCPrintActions = true;
- } else if (!strcmp(Opt, "print-bindings")) {
- CCCPrintBindings = true;
- } else if (!strcmp(Opt, "cxx")) {
- CCCIsCXX = true;
- } else if (!strcmp(Opt, "echo")) {
- CCCEcho = true;
-
- } else if (!strcmp(Opt, "gcc-name")) {
- assert(Start+1 < End && "FIXME: -ccc- argument handling.");
- CCCGenericGCCName = *++Start;
-
- } else if (!strcmp(Opt, "clang-cxx")) {
- CCCUseClangCXX = true;
- } else if (!strcmp(Opt, "no-clang-cxx")) {
- CCCUseClangCXX = false;
- } else if (!strcmp(Opt, "pch-is-pch")) {
- CCCUsePCH = true;
- } else if (!strcmp(Opt, "pch-is-pth")) {
- CCCUsePCH = false;
- } else if (!strcmp(Opt, "no-clang")) {
- CCCUseClang = false;
- } else if (!strcmp(Opt, "no-clang-cpp")) {
- CCCUseClangCPP = false;
- } else if (!strcmp(Opt, "clang-archs")) {
- assert(Start+1 < End && "FIXME: -ccc- argument handling.");
- llvm::StringRef Cur = *++Start;
-
- CCCClangArchs.clear();
- while (!Cur.empty()) {
- std::pair<llvm::StringRef, llvm::StringRef> Split = Cur.split(',');
-
- if (!Split.first.empty()) {
- llvm::Triple::ArchType Arch =
- llvm::Triple(Split.first, "", "").getArch();
-
- if (Arch == llvm::Triple::UnknownArch) {
- // FIXME: Error handling.
- llvm::errs() << "invalid arch name: " << Split.first << "\n";
- exit(1);
- }
-
- CCCClangArchs.insert(Arch);
+ CCCPrintOptions = Args->hasArg(options::OPT_ccc_print_options);
+ CCCPrintActions = Args->hasArg(options::OPT_ccc_print_phases);
+ CCCPrintBindings = Args->hasArg(options::OPT_ccc_print_bindings);
+ CCCIsCXX = Args->hasArg(options::OPT_ccc_cxx) || CCCIsCXX;
+ CCCEcho = Args->hasArg(options::OPT_ccc_echo);
+ if (const Arg *A = Args->getLastArg(options::OPT_ccc_gcc_name))
+ CCCGenericGCCName = A->getValue(*Args);
+ CCCUseClangCXX = Args->hasFlag(options::OPT_ccc_clang_cxx,
+ options::OPT_ccc_no_clang_cxx,
+ CCCUseClangCXX);
+ CCCUsePCH = Args->hasFlag(options::OPT_ccc_pch_is_pch,
+ options::OPT_ccc_pch_is_pth);
+ CCCUseClang = !Args->hasArg(options::OPT_ccc_no_clang);
+ CCCUseClangCPP = !Args->hasArg(options::OPT_ccc_no_clang_cpp);
+ if (const Arg *A = Args->getLastArg(options::OPT_ccc_clang_archs)) {
+ llvm::StringRef Cur = A->getValue(*Args);
+
+ CCCClangArchs.clear();
+ while (!Cur.empty()) {
+ std::pair<llvm::StringRef, llvm::StringRef> Split = Cur.split(',');
+
+ if (!Split.first.empty()) {
+ llvm::Triple::ArchType Arch =
+ llvm::Triple(Split.first, "", "").getArch();
+
+ if (Arch == llvm::Triple::UnknownArch) {
+ Diag(clang::diag::err_drv_invalid_arch_name) << Arch;
+ continue;
}
- Cur = Split.second;
+ CCCClangArchs.insert(Arch);
}
- } else if (!strcmp(Opt, "host-triple")) {
- assert(Start+1 < End && "FIXME: -ccc- argument handling.");
- HostTriple = *++Start;
- } else if (!strcmp(Opt, "install-dir")) {
- assert(Start+1 < End && "FIXME: -ccc- argument handling.");
- Dir = *++Start;
-
- } else {
- // FIXME: Error handling.
- llvm::errs() << "invalid option: " << *Start << "\n";
- exit(1);
+ Cur = Split.second;
}
}
-
- InputArgList *Args = ParseArgStrings(Start, End);
+ if (const Arg *A = Args->getLastArg(options::OPT_ccc_host_triple))
+ HostTriple = A->getValue(*Args);
+ if (const Arg *A = Args->getLastArg(options::OPT_ccc_install_dir))
+ Dir = A->getValue(*Args);
Host = GetHostInfo(HostTriple);
@@ -287,110 +263,11 @@ void Driver::PrintOptions(const ArgList &Args) const {
}
}
-static std::string getOptionHelpName(const OptTable &Opts, options::ID Id) {
- std::string Name = Opts.getOptionName(Id);
-
- // Add metavar, if used.
- switch (Opts.getOptionKind(Id)) {
- case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
- assert(0 && "Invalid option with help text.");
-
- case Option::MultiArgClass: case Option::JoinedAndSeparateClass:
- assert(0 && "Cannot print metavar for this kind of option.");
-
- case Option::FlagClass:
- break;
-
- case Option::SeparateClass: case Option::JoinedOrSeparateClass:
- Name += ' ';
- // FALLTHROUGH
- case Option::JoinedClass: case Option::CommaJoinedClass:
- Name += Opts.getOptionMetaVar(Id);
- break;
- }
-
- return Name;
-}
-
+// FIXME: Move -ccc options to real options in the .td file (or eliminate), and
+// then move to using OptTable::PrintHelp.
void Driver::PrintHelp(bool ShowHidden) const {
- llvm::raw_ostream &OS = llvm::outs();
-
- OS << "OVERVIEW: clang \"gcc-compatible\" driver\n";
- OS << '\n';
- OS << "USAGE: " << Name << " [options] <input files>\n";
- OS << '\n';
- OS << "OPTIONS:\n";
-
- // Render help text into (option, help) pairs.
- std::vector< std::pair<std::string, const char*> > OptionHelp;
-
- for (unsigned i = 0, e = getOpts().getNumOptions(); i != e; ++i) {
- options::ID Id = (options::ID) (i + 1);
- if (const char *Text = getOpts().getOptionHelpText(Id))
- OptionHelp.push_back(std::make_pair(getOptionHelpName(getOpts(), Id),
- Text));
- }
-
- if (ShowHidden) {
- OptionHelp.push_back(std::make_pair("\nDRIVER OPTIONS:",""));
- OptionHelp.push_back(std::make_pair("-ccc-cxx",
- "Act as a C++ driver"));
- OptionHelp.push_back(std::make_pair("-ccc-gcc-name",
- "Name for native GCC compiler"));
- OptionHelp.push_back(std::make_pair("-ccc-clang-cxx",
- "Enable the clang compiler for C++"));
- OptionHelp.push_back(std::make_pair("-ccc-no-clang-cxx",
- "Disable the clang compiler for C++"));
- OptionHelp.push_back(std::make_pair("-ccc-no-clang",
- "Disable the clang compiler"));
- OptionHelp.push_back(std::make_pair("-ccc-no-clang-cpp",
- "Disable the clang preprocessor"));
- OptionHelp.push_back(std::make_pair("-ccc-clang-archs",
- "Comma separate list of architectures "
- "to use the clang compiler for"));
- OptionHelp.push_back(std::make_pair("-ccc-pch-is-pch",
- "Use lazy PCH for precompiled headers"));
- OptionHelp.push_back(std::make_pair("-ccc-pch-is-pth",
- "Use pretokenized headers for precompiled headers"));
-
- OptionHelp.push_back(std::make_pair("\nDEBUG/DEVELOPMENT OPTIONS:",""));
- OptionHelp.push_back(std::make_pair("-ccc-host-triple",
- "Simulate running on the given target"));
- OptionHelp.push_back(std::make_pair("-ccc-install-dir",
- "Simulate installation in the given directory"));
- OptionHelp.push_back(std::make_pair("-ccc-print-options",
- "Dump parsed command line arguments"));
- OptionHelp.push_back(std::make_pair("-ccc-print-phases",
- "Dump list of actions to perform"));
- OptionHelp.push_back(std::make_pair("-ccc-print-bindings",
- "Show bindings of tools to actions"));
- OptionHelp.push_back(std::make_pair("CCC_ADD_ARGS",
- "(ENVIRONMENT VARIABLE) Comma separated list of "
- "arguments to prepend to the command line"));
- }
-
- // Find the maximum option length.
- unsigned OptionFieldWidth = 0;
- for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
- // Skip titles.
- if (!OptionHelp[i].second)
- continue;
-
- // Limit the amount of padding we are willing to give up for alignment.
- unsigned Length = OptionHelp[i].first.size();
- if (Length <= 23)
- OptionFieldWidth = std::max(OptionFieldWidth, Length);
- }
-
- for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
- const std::string &Option = OptionHelp[i].first;
- OS << " " << Option;
- for (int j = Option.length(), e = OptionFieldWidth; j < e; ++j)
- OS << ' ';
- OS << ' ' << OptionHelp[i].second << '\n';
- }
-
- OS.flush();
+ getOpts().PrintHelp(llvm::outs(), Name.c_str(),
+ "clang \"gcc-compatible\" driver", ShowHidden);
}
void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const {
diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp
index d1af95c..72aaf56 100644
--- a/lib/Driver/DriverOptions.cpp
+++ b/lib/Driver/DriverOptions.cpp
@@ -14,7 +14,7 @@
using namespace clang::driver;
using namespace clang::driver::options;
-static OptTable::Info InfoTable[] = {
+static const OptTable::Info InfoTable[] = {
#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
{ NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 280e7c4..1bd123e 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -14,10 +14,11 @@ using namespace clang::driver;
Job::~Job() {}
-Command::Command(const Action &_Source, const char *_Executable,
- const ArgStringList &_Arguments)
- : Job(CommandClass), Source(_Source), Executable(_Executable),
- Arguments(_Arguments) {
+Command::Command(const Action &_Source, const Tool &_Creator,
+ const char *_Executable, const ArgStringList &_Arguments)
+ : Job(CommandClass), Source(_Source), Creator(_Creator),
+ Executable(_Executable), Arguments(_Arguments)
+{
}
PipedJob::PipedJob() : Job(PipedJobClass) {}
diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp
index f68a1d8..f69d5d8 100644
--- a/lib/Driver/OptTable.cpp
+++ b/lib/Driver/OptTable.cpp
@@ -11,9 +11,10 @@
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Option.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
-
+#include <map>
using namespace clang::driver;
using namespace clang::driver::options;
@@ -255,3 +256,122 @@ InputArgList *OptTable::ParseArgs(const char **ArgBegin, const char **ArgEnd,
return Args;
}
+
+static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
+ std::string Name = Opts.getOptionName(Id);
+
+ // Add metavar, if used.
+ switch (Opts.getOptionKind(Id)) {
+ case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
+ assert(0 && "Invalid option with help text.");
+
+ case Option::MultiArgClass: case Option::JoinedAndSeparateClass:
+ assert(0 && "Cannot print metavar for this kind of option.");
+
+ case Option::FlagClass:
+ break;
+
+ case Option::SeparateClass: case Option::JoinedOrSeparateClass:
+ Name += ' ';
+ // FALLTHROUGH
+ case Option::JoinedClass: case Option::CommaJoinedClass:
+ if (const char *MetaVarName = Opts.getOptionMetaVar(Id))
+ Name += MetaVarName;
+ else
+ Name += "<value>";
+ break;
+ }
+
+ return Name;
+}
+
+static void PrintHelpOptionList(llvm::raw_ostream &OS, llvm::StringRef Title,
+ std::vector<std::pair<std::string,
+ const char*> > &OptionHelp) {
+ OS << Title << ":\n";
+
+ // Find the maximum option length.
+ unsigned OptionFieldWidth = 0;
+ for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
+ // Skip titles.
+ if (!OptionHelp[i].second)
+ continue;
+
+ // Limit the amount of padding we are willing to give up for alignment.
+ unsigned Length = OptionHelp[i].first.size();
+ if (Length <= 23)
+ OptionFieldWidth = std::max(OptionFieldWidth, Length);
+ }
+
+ const unsigned InitialPad = 2;
+ for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
+ const std::string &Option = OptionHelp[i].first;
+ int Pad = OptionFieldWidth - int(Option.size());
+ OS.indent(InitialPad) << Option;
+
+ // Break on long option names.
+ if (Pad < 0) {
+ OS << "\n";
+ Pad = OptionFieldWidth + InitialPad;
+ }
+ OS.indent(Pad + 1) << OptionHelp[i].second << '\n';
+ }
+}
+
+static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) {
+ unsigned GroupID = Opts.getOptionGroupID(Id);
+
+ // If not in a group, return the default help group.
+ if (!GroupID)
+ return "OPTIONS";
+
+ // Abuse the help text of the option groups to store the "help group"
+ // name.
+ //
+ // FIXME: Split out option groups.
+ if (const char *GroupHelp = Opts.getOptionHelpText(GroupID))
+ return GroupHelp;
+
+ // Otherwise keep looking.
+ return getOptionHelpGroup(Opts, GroupID);
+}
+
+void OptTable::PrintHelp(llvm::raw_ostream &OS, const char *Name,
+ const char *Title, bool ShowHidden) const {
+ OS << "OVERVIEW: " << Title << "\n";
+ OS << '\n';
+ OS << "USAGE: " << Name << " [options] <inputs>\n";
+ OS << '\n';
+
+ // Render help text into a map of group-name to a list of (option, help)
+ // pairs.
+ typedef std::map<std::string,
+ std::vector<std::pair<std::string, const char*> > > helpmap_ty;
+ helpmap_ty GroupedOptionHelp;
+
+ for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
+ unsigned Id = i + 1;
+
+ // FIXME: Split out option groups.
+ if (getOptionKind(Id) == Option::GroupClass)
+ continue;
+
+ if (!ShowHidden && isOptionHelpHidden(Id))
+ continue;
+
+ if (const char *Text = getOptionHelpText(Id)) {
+ const char *HelpGroup = getOptionHelpGroup(*this, Id);
+ const std::string &OptName = getOptionHelpName(*this, Id);
+ GroupedOptionHelp[HelpGroup].push_back(std::make_pair(OptName, Text));
+ }
+ }
+
+ for (helpmap_ty::iterator it = GroupedOptionHelp .begin(),
+ ie = GroupedOptionHelp.end(); it != ie; ++it) {
+ if (it != GroupedOptionHelp .begin())
+ OS << "\n";
+ PrintHelpOptionList(OS, it->first, it->second);
+ }
+
+ OS.flush();
+}
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index af63952..420573d 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -510,7 +510,7 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args,
DAL->append(DAL->MakeJoinedArg(0, MArch, "armv7a"));
else
- llvm::llvm_unreachable("invalid Darwin arch");
+ llvm_unreachable("invalid Darwin arch");
}
return DAL;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index eb165cf..70597ab 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -9,6 +9,7 @@
#include "Tools.h"
+#include "clang/Basic/Version.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
@@ -419,14 +420,17 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
//
// FIXME: This changes CPP defines, we need -target-soft-float.
CmdArgs.push_back("-msoft-float");
- CmdArgs.push_back("-mfloat-abi=soft");
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("soft");
} else if (FloatABI == "softfp") {
// Floating point operations are hard, but argument passing is soft.
- CmdArgs.push_back("-mfloat-abi=soft");
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("soft");
} else {
// Floating point operations and argument passing are hard.
assert(FloatABI == "hard" && "Invalid float abi!");
- CmdArgs.push_back("-mfloat-abi=hard");
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("hard");
}
}
@@ -590,6 +594,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
+ // Invoke ourselves in -cc1 mode.
+ //
+ // FIXME: Implement custom jobs for internal actions.
+ CmdArgs.push_back("-cc1");
+
// Add the "effective" target triple.
CmdArgs.push_back("-triple");
std::string TripleStr = getEffectiveClangTriple(D, getToolChain(), Args);
@@ -647,6 +656,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Enable region store model by default.
CmdArgs.push_back("-analyzer-store=region");
+ // Treat blocks as analysis entry points.
+ CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks");
+
// Add default argument set.
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
CmdArgs.push_back("-warn-dead-stores");
@@ -787,7 +799,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Arg *Unsupported;
if ((Unsupported = Args.getLastArg(options::OPT_MG)) ||
(Unsupported = Args.getLastArg(options::OPT_MQ)) ||
- (Unsupported = Args.getLastArg(options::OPT_iframework)))
+ (Unsupported = Args.getLastArg(options::OPT_iframework)) ||
+ (Unsupported = Args.getLastArg(options::OPT_fshort_enums)))
D.Diag(clang::diag::err_drv_clang_unsupported)
<< Unsupported->getOption().getName();
@@ -803,7 +816,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_nostdinc);
Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc);
- Args.AddLastArg(CmdArgs, options::OPT_isysroot);
+ // Pass the path to compiler resource files.
+ //
+ // FIXME: Get this from a configuration object.
+ llvm::sys::Path P(D.Dir);
+ P.eraseComponent(); // Remove /bin from foo/bin
+ P.appendComponent("lib");
+ P.appendComponent("clang");
+ P.appendComponent(CLANG_VERSION_STRING);
+ CmdArgs.push_back("-resource-dir");
+ CmdArgs.push_back(Args.MakeArgString(P.str()));
// Add preprocessing options like -I, -D, etc. if we are using the
// preprocessor.
@@ -877,7 +899,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(llvm::Twine(N)));
}
- // Forward -f options which we can pass directly.
+ if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ)) {
+ CmdArgs.push_back("-fvisibility");
+ CmdArgs.push_back(A->getValue(Args));
+ }
+
+ // Forward -f (flag) options which we can pass directly.
+ Args.AddLastArg(CmdArgs, options::OPT_fcatch_undefined_behavior);
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
Args.AddLastArg(CmdArgs, options::OPT_ffreestanding);
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
@@ -890,7 +918,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
- Args.AddLastArg(CmdArgs, options::OPT_fvisibility_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings);
Args.AddLastArg(CmdArgs, options::OPT_pthread);
@@ -1027,7 +1054,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Default to -fno-builtin-str{cat,cpy} on Darwin for ARM.
//
- // FIXME: This is disabled until clang-cc supports -fno-builtin-foo. PR4941.
+ // FIXME: This is disabled until clang -cc1 supports -fno-builtin-foo. PR4941.
#if 0
if (getToolChain().getTriple().getOS() == llvm::Triple::Darwin &&
(getToolChain().getTriple().getArch() == llvm::Triple::arm ||
@@ -1077,8 +1104,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_undef);
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(C, "clang-cc"));
- Dest.addCommand(new Command(JA, Exec, CmdArgs));
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "clang"));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
// Explicitly warn that these options are unsupported, even though
// we are allowing compilation to continue.
@@ -1200,7 +1227,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().getHost().getDriver().CCCGenericGCCName.c_str();
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, GCCName));
- Dest.addCommand(new Command(JA, Exec, CmdArgs));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
void gcc::Preprocess::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
@@ -1589,7 +1616,7 @@ void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA,
const char *CC1Name = getCC1Name(Inputs[0].getType());
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name));
- Dest.addCommand(new Command(JA, Exec, CmdArgs));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
@@ -1683,7 +1710,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
const char *CC1Name = getCC1Name(Inputs[0].getType());
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name));
- Dest.addCommand(new Command(JA, Exec, CmdArgs));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -1738,7 +1765,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, "as"));
- Dest.addCommand(new Command(JA, Exec, CmdArgs));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
/// Helper routine for seeing if we should use dsymutil; this is a
@@ -2152,7 +2179,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, "ld"));
- Dest.addCommand(new Command(JA, Exec, CmdArgs));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
// Find the first non-empty base input (we want to ignore linker
// inputs).
@@ -2182,7 +2209,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.MakeArgString(getToolChain().GetProgramPath(C, "dsymutil"));
ArgStringList CmdArgs;
CmdArgs.push_back(Output.getFilename());
- C.getJobs().addCommand(new Command(JA, Exec, CmdArgs));
+ C.getJobs().addCommand(new Command(JA, *this, Exec, CmdArgs));
}
}
}
@@ -2208,7 +2235,7 @@ void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, "lipo"));
- Dest.addCommand(new Command(JA, Exec, CmdArgs));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -2238,7 +2265,7 @@ void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, "gas"));
- Dest.addCommand(new Command(JA, Exec, CmdArgs));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA,
@@ -2339,7 +2366,7 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, "ld"));
- Dest.addCommand(new Command(JA, Exec, CmdArgs));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -2369,7 +2396,7 @@ void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, "as"));
- Dest.addCommand(new Command(JA, Exec, CmdArgs));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
@@ -2469,7 +2496,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, "ld"));
- Dest.addCommand(new Command(JA, Exec, CmdArgs));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -2504,7 +2531,7 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, "as"));
- Dest.addCommand(new Command(JA, Exec, CmdArgs));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
@@ -2617,7 +2644,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, "ld"));
- Dest.addCommand(new Command(JA, Exec, CmdArgs));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
/// DragonFly Tools
@@ -2656,7 +2683,7 @@ void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, "as"));
- Dest.addCommand(new Command(JA, Exec, CmdArgs));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
@@ -2780,5 +2807,5 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(C, "ld"));
- Dest.addCommand(new Command(JA, Exec, CmdArgs));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 3397677..433af03 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -23,7 +23,7 @@ struct TypeInfo {
ID PreprocessedType;
};
-static TypeInfo TypeInfos[] = {
+static const TypeInfo TypeInfos[] = {
#define TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, FLAGS) \
{ NAME, FLAGS, TEMP_SUFFIX, TY_##PP_TYPE, },
#include "clang/Driver/Types.def"
@@ -31,7 +31,7 @@ static TypeInfo TypeInfos[] = {
};
static const unsigned numTypes = sizeof(TypeInfos) / sizeof(TypeInfos[0]);
-static TypeInfo &getInfo(unsigned id) {
+static const TypeInfo &getInfo(unsigned id) {
assert(id > 0 && id - 1 < numTypes && "Invalid Type ID.");
return TypeInfos[id - 1];
}
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 9a30f59..f1a6666 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -28,8 +28,6 @@
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
-#include <cstdio>
-
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -405,8 +403,13 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "<objc property> " << OPD->getNameAsString() << "\n";
break;
}
+ case Decl::FunctionTemplate: {
+ FunctionTemplateDecl* FTD = cast<FunctionTemplateDecl>(*I);
+ Out << "<function template> " << FTD->getNameAsString() << "\n";
+ break;
+ }
default:
- fprintf(stderr, "DeclKind: %d \"%s\"\n", DK, I->getDeclKindName());
+ Out << "DeclKind: " << DK << '"' << I->getDeclKindName() << "\"\n";
assert(0 && "decl unhandled");
}
}
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index f647c8a..48296c7 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -17,27 +17,29 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Job.h"
+#include "clang/Driver/Tool.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Diagnostic.h"
-#include "llvm/LLVMContext.h"
+#include "llvm/System/Host.h"
#include "llvm/System/Path.h"
using namespace clang;
-ASTUnit::ASTUnit(DiagnosticClient *diagClient) : tempFile(false) {
- Diags.setClient(diagClient ? diagClient : new TextDiagnosticBuffer());
+ASTUnit::ASTUnit(bool _MainFileIsAST)
+ : tempFile(false), MainFileIsAST(_MainFileIsAST) {
}
ASTUnit::~ASTUnit() {
if (tempFile)
llvm::sys::Path(getPCHFileName()).eraseFromDisk();
-
- // The ASTUnit object owns the DiagnosticClient.
- delete Diags.getClient();
}
namespace {
@@ -90,19 +92,19 @@ public:
} // anonymous namespace
const std::string &ASTUnit::getOriginalSourceFileName() {
- return dyn_cast<PCHReader>(Ctx->getExternalSource())->getOriginalSourceFile();
+ return OriginalSourceFile;
}
const std::string &ASTUnit::getPCHFileName() {
+ assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
return dyn_cast<PCHReader>(Ctx->getExternalSource())->getFileName();
}
ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
- std::string *ErrMsg,
- DiagnosticClient *diagClient,
+ Diagnostic &Diags,
bool OnlyLocalDecls,
bool UseBumpAllocator) {
- llvm::OwningPtr<ASTUnit> AST(new ASTUnit(diagClient));
+ llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
@@ -118,7 +120,7 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
llvm::OwningPtr<ExternalASTSource> Source;
Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
- AST->Diags));
+ Diags));
Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
Predefines, Counter));
@@ -128,11 +130,12 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
case PCHReader::Failure:
case PCHReader::IgnorePCH:
- if (ErrMsg)
- *ErrMsg = "Could not load PCH file";
+ Diags.Report(diag::err_fe_unable_to_load_pch);
return NULL;
}
+ AST->OriginalSourceFile = Reader->getOriginalSourceFile();
+
// PCH loaded successfully. Now create the preprocessor.
// Get information about the target being compiled for.
@@ -143,8 +146,8 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
TargetOpts.CPU = "";
TargetOpts.Features.clear();
TargetOpts.Triple = TargetTriple;
- AST->Target.reset(TargetInfo::CreateTargetInfo(AST->Diags, TargetOpts));
- AST->PP.reset(new Preprocessor(AST->Diags, LangInfo, *AST->Target.get(),
+ AST->Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts));
+ AST->PP.reset(new Preprocessor(Diags, LangInfo, *AST->Target.get(),
AST->getSourceManager(), HeaderInfo));
Preprocessor &PP = *AST->PP.get();
@@ -177,13 +180,30 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
namespace {
-class NullAction : public ASTFrontendAction {
+class TopLevelDeclTrackerConsumer : public ASTConsumer {
+ ASTUnit &Unit;
+
+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);
+ }
+};
+
+class TopLevelDeclTrackerAction : public ASTFrontendAction {
+public:
+ ASTUnit &Unit;
+
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
- return new ASTConsumer();
+ return new TopLevelDeclTrackerConsumer(Unit);
}
public:
+ TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
+
virtual bool hasCodeCompletionSupport() const { return false; }
};
@@ -191,12 +211,11 @@ public:
ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
Diagnostic &Diags,
- bool OnlyLocalDecls,
- bool UseBumpAllocator) {
+ bool OnlyLocalDecls) {
// Create the compiler instance to use for building the AST.
- CompilerInstance Clang(&llvm::getGlobalContext(), false);
+ CompilerInstance Clang;
llvm::OwningPtr<ASTUnit> AST;
- NullAction Act;
+ llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
Clang.getInvocation() = CI;
@@ -221,9 +240,10 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
"FIXME: AST inputs not yet supported here!");
// Create the AST unit.
- //
- // FIXME: Use the provided diagnostic client.
- AST.reset(new ASTUnit());
+ AST.reset(new ASTUnit(false));
+
+ AST->OnlyLocalDecls = OnlyLocalDecls;
+ AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
// Create a file manager object to provide access to and cache the filesystem.
Clang.setFileManager(&AST->getFileManager());
@@ -234,20 +254,22 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
// Create the preprocessor.
Clang.createPreprocessor();
- if (!Act.BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
+ Act.reset(new TopLevelDeclTrackerAction(*AST));
+ if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
/*IsAST=*/false))
goto error;
- Act.Execute();
+ Act->Execute();
- // Steal the created context and preprocessor, and take back the source and
- // file managers.
+ // Steal the created target, context, and preprocessor, and take back the
+ // source and file managers.
AST->Ctx.reset(Clang.takeASTContext());
AST->PP.reset(Clang.takePreprocessor());
Clang.takeSourceManager();
Clang.takeFileManager();
+ AST->Target.reset(Clang.takeTarget());
- Act.EndSourceFile();
+ Act->EndSourceFile();
Clang.takeDiagnosticClient();
Clang.takeDiagnostics();
@@ -261,3 +283,53 @@ error:
Clang.takeDiagnostics();
return 0;
}
+
+ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
+ const char **ArgEnd,
+ Diagnostic &Diags,
+ llvm::StringRef ResourceFilesPath,
+ bool OnlyLocalDecls,
+ bool UseBumpAllocator) {
+ llvm::SmallVector<const char *, 16> Args;
+ Args.push_back("<clang>"); // FIXME: Remove dummy argument.
+ Args.insert(Args.end(), ArgBegin, ArgEnd);
+
+ // FIXME: Find a cleaner way to force the driver into restricted modes. We
+ // also want to force it to use clang.
+ Args.push_back("-fsyntax-only");
+
+ // FIXME: We shouldn't have to pass in the path info.
+ driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(),
+ "a.out", false, Diags);
+ llvm::OwningPtr<driver::Compilation> C(
+ TheDriver.BuildCompilation(Args.size(), Args.data()));
+
+ // We expect to get back exactly one command job, if we didn't something
+ // failed.
+ const driver::JobList &Jobs = C->getJobs();
+ if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
+ llvm::SmallString<256> Msg;
+ llvm::raw_svector_ostream OS(Msg);
+ C->PrintJob(OS, C->getJobs(), "; ", true);
+ Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
+ return 0;
+ }
+
+ const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
+ if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
+ Diags.Report(diag::err_fe_expected_clang_command);
+ return 0;
+ }
+
+ const driver::ArgStringList &CCArgs = Cmd->getArguments();
+ CompilerInvocation CI;
+ CompilerInvocation::CreateFromArgs(CI, (const char**) CCArgs.data(),
+ (const char**) CCArgs.data()+CCArgs.size(),
+ Diags);
+
+ // Override the resources path.
+ CI.getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
+
+ CI.getFrontendOpts().DisableFree = UseBumpAllocator;
+ return LoadFromCompilerInvocation(CI, Diags, OnlyLocalDecls);
+}
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index 5df1ece..a74bbc2 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -139,13 +139,17 @@ public:
return;
declDisplayed = true;
- // FIXME: Is getCodeDecl() always a named decl?
+ SourceManager &SM = Mgr->getASTContext().getSourceManager();
+ PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
+ llvm::errs() << "ANALYZE: " << Loc.getFilename();
+
if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
const NamedDecl *ND = cast<NamedDecl>(D);
- SourceManager &SM = Mgr->getASTContext().getSourceManager();
- llvm::errs() << "ANALYZE: "
- << SM.getPresumedLoc(ND->getLocation()).getFilename()
- << ' ' << ND->getNameAsString() << '\n';
+ llvm::errs() << ' ' << ND->getNameAsString() << '\n';
+ }
+ else if (isa<BlockDecl>(D)) {
+ llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:"
+ << Loc.getColumn() << '\n';
}
}
@@ -167,7 +171,6 @@ public:
Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
PP.getLangOptions(), PD,
CreateStoreMgr, CreateConstraintMgr,
- Opts.AnalyzerDisplayProgress,
Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
Opts.PurgeDead, Opts.EagerlyAssume,
Opts.TrimGraph));
@@ -265,10 +268,21 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
// 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.
+ // side-effects in PathDiagnosticClient's destructor. This is required when
+ // used with option -disable-free.
Mgr.reset(NULL);
}
+static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) {
+ if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
+ WL.push_back(BD);
+
+ for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
+ I!=E; ++I)
+ if (DeclContext *DC = dyn_cast<DeclContext>(*I))
+ FindBlocks(DC, WL);
+}
+
void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) {
// Don't run the actions if an error has occured with parsing the file.
@@ -285,8 +299,16 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) {
Mgr->ClearContexts();
// Dispatch on the actions.
+ llvm::SmallVector<Decl*, 10> WL;
+ WL.push_back(D);
+
+ if (Body && Opts.AnalyzeNestedBlocks)
+ FindBlocks(cast<DeclContext>(D), WL);
+
for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
- (*I)(*this, *Mgr, D);
+ for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
+ WI != WE; ++WI)
+ (*I)(*this, *Mgr, *WI);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp
index 9dc109d..9be6786 100644
--- a/lib/Frontend/Backend.cpp
+++ b/lib/Frontend/Backend.cpp
@@ -15,6 +15,7 @@
#include "clang/Basic/TargetOptions.h"
#include "clang/CodeGen/CodeGenOptions.h"
#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/PassManager.h"
@@ -31,12 +32,14 @@
#include "llvm/Target/SubtargetFeature.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegistry.h"
using namespace clang;
using namespace llvm;
namespace {
class BackendConsumer : public ASTConsumer {
+ Diagnostic &Diags;
BackendAction Action;
const CodeGenOptions &CodeGenOpts;
const LangOptions &LangOpts;
@@ -64,21 +67,20 @@ namespace {
void CreatePasses();
- /// AddEmitPasses - Add passes necessary to emit assembly or LLVM
- /// IR.
+ /// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR.
///
- /// \return True on success. On failure \arg Error will be set to
- /// a user readable error message.
- bool AddEmitPasses(std::string &Error);
+ /// \return True on success.
+ bool AddEmitPasses();
void EmitAssembly();
public:
- BackendConsumer(BackendAction action, Diagnostic &Diags,
+ BackendConsumer(BackendAction action, Diagnostic &_Diags,
const LangOptions &langopts, const CodeGenOptions &compopts,
const TargetOptions &targetopts, bool TimePasses,
const std::string &infile, llvm::raw_ostream *OS,
LLVMContext& C) :
+ Diags(_Diags),
Action(action),
CodeGenOpts(compopts),
LangOpts(langopts),
@@ -195,7 +197,7 @@ FunctionPassManager *BackendConsumer::getPerFunctionPasses() const {
return PerFunctionPasses;
}
-bool BackendConsumer::AddEmitPasses(std::string &Error) {
+bool BackendConsumer::AddEmitPasses() {
if (Action == Backend_EmitNothing)
return true;
@@ -207,48 +209,68 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
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) {
- Error = std::string("Unable to get target machine: ") + Error;
+ 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);
+
+ // 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.AsmVerbose)
- BackendArgs.push_back("-asm-verbose");
- if (!CodeGenOpts.CodeModel.empty()) {
- BackendArgs.push_back("-code-model");
- BackendArgs.push_back(CodeGenOpts.CodeModel.c_str());
- }
if (!CodeGenOpts.DebugPass.empty()) {
BackendArgs.push_back("-debug-pass");
BackendArgs.push_back(CodeGenOpts.DebugPass.c_str());
}
- if (CodeGenOpts.DisableFPElim)
- BackendArgs.push_back("-disable-fp-elim");
- if (!CodeGenOpts.FloatABI.empty()) {
- BackendArgs.push_back("-float-abi");
- BackendArgs.push_back(CodeGenOpts.FloatABI.c_str());
- }
if (!CodeGenOpts.LimitFloatPrecision.empty()) {
BackendArgs.push_back("-limit-float-precision");
BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str());
}
- if (CodeGenOpts.NoZeroInitializedInBSS)
- BackendArgs.push_back("-nozero-initialized-in-bss");
- if (CodeGenOpts.SoftFloat)
- BackendArgs.push_back("-soft-float");
- BackendArgs.push_back("-relocation-model");
- BackendArgs.push_back(CodeGenOpts.RelocationModel.c_str());
if (llvm::TimePassesIsEnabled)
BackendArgs.push_back("-time-passes");
- if (CodeGenOpts.UnwindTables)
- BackendArgs.push_back("-unwind-tables");
BackendArgs.push_back(0);
llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
(char**) &BackendArgs[0]);
@@ -290,7 +312,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
TargetMachine::AssemblyFile, OptLevel)) {
default:
case FileModel::Error:
- Error = "Unable to interface with target machine!\n";
+ Diags.Report(diag::err_fe_unable_to_interface_with_target);
return false;
case FileModel::AsmFile:
break;
@@ -298,7 +320,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
if (TM->addPassesToEmitFileFinish(*CodeGenPasses, (MachineCodeEmitter *)0,
OptLevel)) {
- Error = "Unable to interface with target machine!\n";
+ Diags.Report(diag::err_fe_unable_to_interface_with_target);
return false;
}
}
@@ -329,8 +351,14 @@ void BackendConsumer::CreatePasses() {
switch (Inlining) {
case CodeGenOptions::NoInlining: break;
case CodeGenOptions::NormalInlining: {
- // Inline small functions
- unsigned Threshold = (CodeGenOpts.OptimizeSize || OptLevel < 3) ? 50 : 200;
+ // Set the inline threshold following llvm-gcc.
+ //
+ // FIXME: Derive these constants in a principled fashion.
+ unsigned Threshold = 200;
+ if (CodeGenOpts.OptimizeSize)
+ Threshold = 50;
+ else if (OptLevel > 2)
+ Threshold = 250;
InliningPass = createFunctionInliningPass(Threshold);
break;
}
@@ -372,13 +400,8 @@ void BackendConsumer::EmitAssembly() {
assert(TheModule == M && "Unexpected module change during IR generation");
CreatePasses();
-
- std::string Error;
- if (!AddEmitPasses(Error)) {
- // FIXME: Don't fail this way.
- llvm::errs() << "ERROR: " << Error << "\n";
- ::exit(1);
- }
+ if (!AddEmitPasses())
+ return;
// Run passes. For now we do all passes at once, but eventually we
// would like to have the option of streaming code generation.
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 1083d5e..2a6a8a8 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -95,7 +95,7 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
return;
}
- (*OS) << "clang-cc command line arguments: ";
+ (*OS) << "clang -cc1 command line arguments: ";
for (unsigned i = 0; i != argc; ++i)
(*OS) << argv[i] << ' ';
(*OS) << '\n';
@@ -172,10 +172,6 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
if (!PPOpts.TokenCache.empty())
PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags);
- // FIXME: Don't fail like this.
- if (Diags.hasErrorOccurred())
- exit(1);
-
// Create the Preprocessor.
HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr);
Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target,
@@ -287,7 +283,7 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
}
// Truncate the named file at the given line/column.
- PP.getSourceManager().truncateFileAt(Entry, Line, Column);
+ PP.SetCodeCompletionPoint(Entry, Line, Column);
// Set up the creation routine for code-completion.
if (UseDebugPrinter)
@@ -332,9 +328,9 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
InFile, Extension,
&OutputPathName);
if (!OS) {
- // FIXME: Don't fail this way.
- llvm::errs() << "error: " << Error << "\n";
- ::exit(1);
+ getDiagnostics().Report(diag::err_fe_unable_to_open_output)
+ << OutputPath << Error;
+ return 0;
}
// Add the output file -- but don't try to remove "-", since this means we are
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index c537507..7a3388f 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -31,7 +31,7 @@ using namespace clang;
static const char *getAnalysisName(Analyses Kind) {
switch (Kind) {
default:
- llvm::llvm_unreachable("Unknown analysis store!");
+ llvm_unreachable("Unknown analysis kind!");
#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\
case NAME: return "-" CMDFLAG;
#include "clang/Frontend/Analyses.def"
@@ -41,7 +41,7 @@ static const char *getAnalysisName(Analyses Kind) {
static const char *getAnalysisStoreName(AnalysisStores Kind) {
switch (Kind) {
default:
- llvm::llvm_unreachable("Unknown analysis store!");
+ llvm_unreachable("Unknown analysis store!");
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \
case NAME##Model: return CMDFLAG;
#include "clang/Frontend/Analyses.def"
@@ -51,7 +51,7 @@ static const char *getAnalysisStoreName(AnalysisStores Kind) {
static const char *getAnalysisConstraintName(AnalysisConstraints Kind) {
switch (Kind) {
default:
- llvm::llvm_unreachable("Unknown analysis constraints!");
+ llvm_unreachable("Unknown analysis constraints!");
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \
case NAME##Model: return CMDFLAG;
#include "clang/Frontend/Analyses.def"
@@ -61,7 +61,7 @@ static const char *getAnalysisConstraintName(AnalysisConstraints Kind) {
static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) {
switch (Kind) {
default:
- llvm::llvm_unreachable("Unknown analysis client!");
+ llvm_unreachable("Unknown analysis client!");
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE) \
case PD_##NAME: return CMDFLAG;
#include "clang/Frontend/Analyses.def"
@@ -96,6 +96,8 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
Res.push_back("-analyzer-opt-analyze-headers");
if (Opts.AnalyzerDisplayProgress)
Res.push_back("-analyzer-display-progress");
+ if (Opts.AnalyzeNestedBlocks)
+ Res.push_back("-analyzer-opt-analyze-nested-blocks");
if (Opts.EagerlyAssume)
Res.push_back("-analyzer-eagerly-assume");
if (!Opts.PurgeDead)
@@ -244,7 +246,7 @@ static const char *getInputKindName(FrontendOptions::InputKind Kind) {
case FrontendOptions::IK_PreprocessedObjCXX:return "objective-c++-cpp-output";
}
- llvm::llvm_unreachable("Unexpected language kind!");
+ llvm_unreachable("Unexpected language kind!");
return 0;
}
@@ -252,7 +254,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
switch (Kind) {
case frontend::PluginAction:
case frontend::InheritanceView:
- llvm::llvm_unreachable("Invalid kind!");
+ llvm_unreachable("Invalid kind!");
case frontend::ASTDump: return "-ast-dump";
case frontend::ASTPrint: return "-ast-print";
@@ -282,7 +284,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
case frontend::RunPreprocessorOnly: return "-Eonly";
}
- llvm::llvm_unreachable("Unexpected language kind!");
+ llvm_unreachable("Unexpected language kind!");
return 0;
}
@@ -296,12 +298,16 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-empty-input-only");
if (Opts.RelocatablePCH)
Res.push_back("-relocatable-pch");
+ if (Opts.ShowHelp)
+ Res.push_back("-help");
if (Opts.ShowMacrosInCodeCompletion)
Res.push_back("-code-completion-macros");
if (Opts.ShowStats)
Res.push_back("-print-stats");
if (Opts.ShowTimers)
Res.push_back("-ftime-report");
+ if (Opts.ShowVersion)
+ Res.push_back("-version");
bool NeedLang = false;
for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i)
@@ -345,6 +351,10 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-plugin");
Res.push_back(Opts.ActionName);
}
+ for (unsigned i = 0, e = Opts.Plugins.size(); i != e; ++i) {
+ Res.push_back("-load");
+ Res.push_back(Opts.Plugins[i]);
+ }
}
static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
@@ -399,8 +409,9 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
// FIXME: Provide an option for this, and move env detection to driver.
llvm::llvm_report_error("Not yet implemented!");
}
- if (!Opts.BuiltinIncludePath.empty()) {
- // FIXME: Provide an option for this, and move to driver.
+ if (!Opts.ResourceDir.empty()) {
+ Res.push_back("-resource-dir");
+ Res.push_back(Opts.ResourceDir);
}
if (!Opts.UseStandardIncludes)
Res.push_back("-nostdinc");
@@ -437,6 +448,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fno-operator-names");
if (Opts.PascalStrings)
Res.push_back("-fpascal-strings");
+ if (Opts.CatchUndefined)
+ Res.push_back("-fcatch-undefined-behavior");
if (Opts.WritableStrings)
Res.push_back("-fwritable-strings");
if (!Opts.LaxVectorConversions)
@@ -445,7 +458,7 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-faltivec");
if (Opts.Exceptions)
Res.push_back("-fexceptions");
- if (!Opts.Rtti)
+ if (!Opts.RTTI)
Res.push_back("-fno-rtti");
if (!Opts.NeXTRuntime)
Res.push_back("-fgnu-runtime");
@@ -550,6 +563,11 @@ static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
assert(Opts.ImplicitPTHInclude == Opts.TokenCache &&
"Unsupported option combination!");
}
+ for (unsigned i = 0, e = Opts.RemappedFiles.size(); i != e; ++i) {
+ Res.push_back("-remap-file");
+ Res.push_back(Opts.RemappedFiles[i].first + ";" +
+ Opts.RemappedFiles[i].second);
+ }
}
static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts,
@@ -696,6 +714,8 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph);
Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers);
Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress);
+ Opts.AnalyzeNestedBlocks =
+ Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks);
Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead);
Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume);
Opts.AnalyzeSpecificFunction = getLastArgValue(Args, OPT_analyze_function);
@@ -877,10 +897,13 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
}
Opts.OutputFile = getLastArgValue(Args, OPT_o);
+ Opts.Plugins = getAllArgValues(Args, OPT_load);
Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch);
+ Opts.ShowHelp = Args.hasArg(OPT_help);
Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros);
Opts.ShowStats = Args.hasArg(OPT_print_stats);
Opts.ShowTimers = Args.hasArg(OPT_ftime_report);
+ Opts.ShowVersion = Args.hasArg(OPT_version);
Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view);
FrontendOptions::InputKind DashX = FrontendOptions::IK_None;
@@ -929,8 +952,8 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
return DashX;
}
-static std::string GetBuiltinIncludePath(const char *Argv0,
- void *MainAddr) {
+std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
+ void *MainAddr) {
llvm::sys::Path P = llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
if (!P.isEmpty()) {
@@ -941,22 +964,18 @@ static std::string GetBuiltinIncludePath(const char *Argv0,
P.appendComponent("lib");
P.appendComponent("clang");
P.appendComponent(CLANG_VERSION_STRING);
- P.appendComponent("include");
}
return P.str();
}
-static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
- const char *Argv0, void *MainAddr) {
+static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
using namespace cc1options;
Opts.Sysroot = getLastArgValue(Args, OPT_isysroot, "/");
Opts.Verbose = Args.hasArg(OPT_v);
+ Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc);
Opts.UseStandardIncludes = !Args.hasArg(OPT_nostdinc);
- Opts.BuiltinIncludePath = "";
- // FIXME: Add an option for this, its a slow call.
- if (!Args.hasArg(OPT_nobuiltininc))
- Opts.BuiltinIncludePath = GetBuiltinIncludePath(Argv0, MainAddr);
+ Opts.ResourceDir = getLastArgValue(Args, OPT_resource_dir);
// Add -I... and -F... options in order.
for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F),
@@ -1115,7 +1134,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
if (Args.hasArg(OPT_fno_lax_vector_conversions))
Opts.LaxVectorConversions = 0;
Opts.Exceptions = Args.hasArg(OPT_fexceptions);
- Opts.Rtti = !Args.hasArg(OPT_fno_rtti);
+ Opts.RTTI = !Args.hasArg(OPT_fno_rtti);
Opts.Blocks = Args.hasArg(OPT_fblocks);
Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char);
Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
@@ -1131,6 +1150,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.ObjCConstantStringClass = getLastArgValue(Args,
OPT_fconstant_string_class);
Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi);
+ Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior);
Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls);
Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags);
Opts.Static = Args.hasArg(OPT_static_define);
@@ -1160,7 +1180,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
}
}
-static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args) {
+static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
+ Diagnostic &Diags) {
using namespace cc1options;
Opts.ImplicitPCHInclude = getLastArgValue(Args, OPT_include_pch);
Opts.ImplicitPTHInclude = getLastArgValue(Args, OPT_include_pth);
@@ -1188,16 +1209,27 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args) {
// PCH is handled specially, we need to extra the original include path.
if (it->getOption().matches(OPT_include_pch)) {
std::string OriginalFile =
- PCHReader::getOriginalSourceFile(it->getValue(Args));
-
- // FIXME: Don't fail like this.
+ PCHReader::getOriginalSourceFile(it->getValue(Args), Diags);
if (OriginalFile.empty())
- exit(1);
+ continue;
Opts.Includes.push_back(OriginalFile);
} else
Opts.Includes.push_back(it->getValue(Args));
}
+
+ for (arg_iterator it = Args.filtered_begin(OPT_remap_file),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ std::pair<llvm::StringRef,llvm::StringRef> Split =
+ llvm::StringRef(it->getValue(Args)).split(';');
+
+ if (Split.second.empty()) {
+ Diags.Report(diag::err_drv_invalid_remap_file) << it->getAsString(Args);
+ continue;
+ }
+
+ Opts.addRemappedFile(Split.first, Split.second);
+ }
}
static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
@@ -1227,8 +1259,6 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
const char **ArgBegin,
const char **ArgEnd,
- const char *Argv0,
- void *MainAddr,
Diagnostic &Diags) {
// Parse the arguments.
llvm::OwningPtr<OptTable> Opts(createCC1OptTable());
@@ -1252,11 +1282,10 @@ void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags);
FrontendOptions::InputKind DashX =
ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags);
- ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args,
- Argv0, MainAddr);
+ ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args);
if (DashX != FrontendOptions::IK_AST)
ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags);
- ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args);
+ ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, Diags);
ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args);
ParseTargetArgs(Res.getTargetOpts(), *Args);
}
diff --git a/lib/Frontend/DiagChecker.cpp b/lib/Frontend/DiagChecker.cpp
index e7a66b1..a50cc99 100644
--- a/lib/Frontend/DiagChecker.cpp
+++ b/lib/Frontend/DiagChecker.cpp
@@ -17,7 +17,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
-#include <cstdio>
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
typedef TextDiagnosticBuffer::DiagList DiagList;
@@ -190,12 +190,10 @@ static bool PrintProblem(SourceManager &SourceMgr,
const char *Msg) {
if (diag_begin == diag_end) return false;
- fprintf(stderr, "%s\n", Msg);
-
+ llvm::errs() << Msg << "\n";
for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I)
- fprintf(stderr, " Line %d: %s\n",
- SourceMgr.getInstantiationLineNumber(I->first),
- I->second.c_str());
+ llvm::errs() << " Line " << SourceMgr.getInstantiationLineNumber(I->first)
+ << " " << I->second << "\n";
return true;
}
diff --git a/lib/Frontend/FixItRewriter.cpp b/lib/Frontend/FixItRewriter.cpp
index dddcaa9..4fa2b3c 100644
--- a/lib/Frontend/FixItRewriter.cpp
+++ b/lib/Frontend/FixItRewriter.cpp
@@ -66,7 +66,7 @@ bool FixItRewriter::WriteFixedFile(const std::string &InFileName,
Rewrite.getRewriteBufferFor(MainFileID)) {
*OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
} else {
- std::fprintf(stderr, "Main file is unchanged\n");
+ Diag(FullSourceLoc(), diag::note_fixit_main_file_unchanged);
}
OutFile->flush();
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index 91c946c..96a68c9 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -46,11 +46,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
assert(hasASTSupport() && "This action does not have AST support!");
std::string Error;
- ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, &Error);
- if (!AST) {
- CI.getDiagnostics().Report(diag::err_fe_invalid_ast_file) << Error;
+ ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, CI.getDiagnostics());
+ if (!AST)
goto failure;
- }
setCurrentFile(Filename, AST);
@@ -224,5 +222,5 @@ void ASTFrontendAction::ExecuteAction() {
ASTConsumer *
PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
- llvm::llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
+ llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
}
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 27e194e..e3c313a 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -35,13 +35,16 @@ ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI,
ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
- return CreateASTPrinter(CI.createDefaultOutputFile(false, InFile));
+ if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
+ return CreateASTPrinter(OS);
+ return 0;
}
ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
- return CreateASTPrinterXML(CI.createDefaultOutputFile(false, InFile,
- "xml"));
+ if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "xml"))
+ return CreateASTPrinterXML(OS);
+ return 0;
}
ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI,
@@ -74,6 +77,9 @@ ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
}
llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile);
+ if (!OS)
+ return 0;
+
if (CI.getFrontendOpts().RelocatablePCH)
return CreatePCHGenerator(CI.getPreprocessor(), OS, Sysroot.c_str());
@@ -82,8 +88,9 @@ ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
- return CreateHTMLPrinter(CI.createDefaultOutputFile(false, InFile),
- CI.getPreprocessor());
+ if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
+ return CreateHTMLPrinter(OS, CI.getPreprocessor());
+ return 0;
}
ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI,
@@ -140,10 +147,11 @@ void FixItAction::EndSourceFileAction() {
ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
- return CreateObjCRewriter(InFile,
- CI.createDefaultOutputFile(true, InFile, "cpp"),
- CI.getDiagnostics(), CI.getLangOpts(),
- CI.getDiagnosticOpts().NoRewriteMacros);
+ if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp"))
+ return CreateObjCRewriter(InFile, OS,
+ CI.getDiagnostics(), CI.getLangOpts(),
+ CI.getDiagnosticOpts().NoRewriteMacros);
+ return 0;
}
ASTConsumer *RewriteBlocksAction::CreateASTConsumer(CompilerInstance &CI,
@@ -162,12 +170,21 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
BackendAction BA = static_cast<BackendAction>(Act);
llvm::OwningPtr<llvm::raw_ostream> OS;
- if (BA == Backend_EmitAssembly)
+ switch (BA) {
+ case Backend_EmitAssembly:
OS.reset(CI.createDefaultOutputFile(false, InFile, "s"));
- else if (BA == Backend_EmitLL)
+ break;
+ case Backend_EmitLL:
OS.reset(CI.createDefaultOutputFile(false, InFile, "ll"));
- else if (BA == Backend_EmitBC)
+ break;
+ case Backend_EmitBC:
OS.reset(CI.createDefaultOutputFile(true, InFile, "bc"));
+ break;
+ case Backend_EmitNothing:
+ break;
+ }
+ if (BA != Backend_EmitNothing && !OS)
+ return 0;
return CreateBackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(),
CI.getCodeGenOpts(), CI.getTargetOpts(),
@@ -228,6 +245,8 @@ void GeneratePTHAction::ExecuteAction() {
}
llvm::raw_fd_ostream *OS =
CI.createDefaultOutputFile(true, getCurrentFile());
+ if (!OS) return;
+
CacheTokens(CI.getPreprocessor(), OS);
}
@@ -255,6 +274,8 @@ void PrintParseAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
Preprocessor &PP = getCompilerInstance().getPreprocessor();
llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
+ if (!OS) return;
+
llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS));
Parser P(PP, *PA);
@@ -265,6 +286,8 @@ void PrintParseAction::ExecuteAction() {
void PrintPreprocessedAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
+ if (!OS) return;
+
DoPrintPreprocessedInput(CI.getPreprocessor(), OS,
CI.getPreprocessorOutputOpts());
}
@@ -272,11 +295,15 @@ void PrintPreprocessedAction::ExecuteAction() {
void RewriteMacrosAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
+ if (!OS) return;
+
RewriteMacrosInInput(CI.getPreprocessor(), OS);
}
void RewriteTestAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
+ if (!OS) return;
+
DoRewriteTest(CI.getPreprocessor(), OS);
}
diff --git a/lib/Frontend/HTMLPrint.cpp b/lib/Frontend/HTMLPrint.cpp
index 75e6184..9ea8cb3 100644
--- a/lib/Frontend/HTMLPrint.cpp
+++ b/lib/Frontend/HTMLPrint.cpp
@@ -41,9 +41,9 @@ namespace {
bool _SyntaxHighlight, bool _HighlightMacros)
: Out(OS), PP(pp), SyntaxHighlight(_SyntaxHighlight),
HighlightMacros(_HighlightMacros) {}
- virtual ~HTMLPrinter();
void Initialize(ASTContext &context);
+ void HandleTranslationUnit(ASTContext &Ctx);
};
}
@@ -58,7 +58,7 @@ void HTMLPrinter::Initialize(ASTContext &context) {
R.setSourceMgr(context.getSourceManager(), context.getLangOptions());
}
-HTMLPrinter::~HTMLPrinter() {
+void HTMLPrinter::HandleTranslationUnit(ASTContext &Ctx) {
if (PP.getDiagnostics().hasErrorOccurred())
return;
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index a40a569..b4ea257 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -21,10 +21,10 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
#include "llvm/Config/config.h"
-#include <cstdio>
#ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
@@ -50,27 +50,27 @@ public:
: Headers(HS), Verbose(verbose), isysroot(iSysroot) {}
/// AddPath - Add the specified path to the specified group list.
- void AddPath(const llvm::StringRef &Path, IncludeDirGroup Group,
+ void AddPath(const llvm::Twine &Path, IncludeDirGroup Group,
bool isCXXAware, bool isUserSupplied,
bool isFramework, bool IgnoreSysRoot = false);
/// AddGnuCPlusPlusIncludePaths - Add the necessary paths to suport a gnu
/// libstdc++.
- void AddGnuCPlusPlusIncludePaths(const std::string &Base,
- const char *ArchDir,
- const char *Dir32,
- const char *Dir64,
+ void AddGnuCPlusPlusIncludePaths(llvm::StringRef Base,
+ llvm::StringRef ArchDir,
+ llvm::StringRef Dir32,
+ llvm::StringRef Dir64,
const llvm::Triple &triple);
/// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to suport a MinGW
/// libstdc++.
- void AddMinGWCPlusPlusIncludePaths(const std::string &Base,
- const char *Arch,
- const char *Version);
+ void AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base,
+ llvm::StringRef Arch,
+ llvm::StringRef Version);
/// AddDelimitedPaths - Add a list of paths delimited by the system PATH
/// separator. The processing follows that of the CPATH variable for gcc.
- void AddDelimitedPaths(const char *String);
+ void AddDelimitedPaths(llvm::StringRef String);
// AddDefaultCIncludePaths - Add paths that should always be searched.
void AddDefaultCIncludePaths(const llvm::Triple &triple);
@@ -91,25 +91,26 @@ public:
}
-void InitHeaderSearch::AddPath(const llvm::StringRef &Path,
+void InitHeaderSearch::AddPath(const llvm::Twine &Path,
IncludeDirGroup Group, bool isCXXAware,
bool isUserSupplied, bool isFramework,
bool IgnoreSysRoot) {
- assert(!Path.empty() && "can't handle empty path here");
+ assert(!Path.isTriviallyEmpty() && "can't handle empty path here");
FileManager &FM = Headers.getFileMgr();
// Compute the actual path, taking into consideration -isysroot.
- llvm::SmallString<256> MappedPath;
+ llvm::SmallString<256> MappedPathStr;
+ llvm::raw_svector_ostream MappedPath(MappedPathStr);
// Handle isysroot.
if (Group == System && !IgnoreSysRoot) {
// FIXME: Portability. This should be a sys::Path interface, this doesn't
// handle things like C:\ right, nor win32 \\network\device\blah.
if (isysroot.size() != 1 || isysroot[0] != '/') // Add isysroot if present.
- MappedPath.append(isysroot.begin(), isysroot.end());
+ MappedPath << isysroot;
}
- MappedPath.append(Path.begin(), Path.end());
+ Path.print(MappedPath);
// Compute the DirectoryLookup type.
SrcMgr::CharacteristicKind Type;
@@ -146,29 +147,29 @@ void InitHeaderSearch::AddPath(const llvm::StringRef &Path,
}
-void InitHeaderSearch::AddDelimitedPaths(const char *at) {
- if (*at == 0) // Empty string should not add '.' path.
+void InitHeaderSearch::AddDelimitedPaths(llvm::StringRef at) {
+ if (at.empty()) // Empty string should not add '.' path.
return;
- const char* delim = strchr(at, llvm::sys::PathSeparator);
- while (delim != 0) {
- if (delim-at == 0)
+ llvm::StringRef::size_type delim;
+ while ((delim = at.find(llvm::sys::PathSeparator)) != llvm::StringRef::npos) {
+ if (delim == 0)
AddPath(".", Angled, false, true, false);
else
- AddPath(llvm::StringRef(at, delim-at), Angled, false, true, false);
- at = delim + 1;
- delim = strchr(at, llvm::sys::PathSeparator);
+ AddPath(at.substr(0, delim), Angled, false, true, false);
+ at = at.substr(delim + 1);
}
- if (*at == 0)
+
+ if (at.empty())
AddPath(".", Angled, false, true, false);
else
AddPath(at, Angled, false, true, false);
}
-void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base,
- const char *ArchDir,
- const char *Dir32,
- const char *Dir64,
+void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base,
+ llvm::StringRef ArchDir,
+ llvm::StringRef Dir32,
+ llvm::StringRef Dir64,
const llvm::Triple &triple) {
// Add the base dir
AddPath(Base, System, true, false, false);
@@ -185,10 +186,10 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base,
AddPath(Base + "/backward", System, true, false, false);
}
-void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(const std::string &Base,
- const char *Arch,
- const char *Version) {
- std::string localBase = Base + "/" + Arch + "/" + Version + "/include";
+void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base,
+ llvm::StringRef Arch,
+ llvm::StringRef Version) {
+ llvm::Twine localBase = Base + "/" + Arch + "/" + Version + "/include";
AddPath(localBase, System, true, false, false);
AddPath(localBase + "/c++", System, true, false, false);
AddPath(localBase + "/c++/backward", System, true, false, false);
@@ -258,25 +259,25 @@ bool getSystemRegistryString(const char *keyPath, const char *valueName,
int bestIndex = -1;
double bestValue = 0.0;
DWORD index, size = sizeof(keyName) - 1;
- for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL,
- NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
- const char *sp = keyName;
- while (*sp && !isdigit(*sp))
- sp++;
- if (!*sp)
- continue;
- const char *ep = sp + 1;
- while (*ep && (isdigit(*ep) || (*ep == '.')))
- ep++;
- char numBuf[32];
- strncpy(numBuf, sp, sizeof(numBuf) - 1);
- numBuf[sizeof(numBuf) - 1] = '\0';
- double value = strtod(numBuf, NULL);
- if (value > bestValue) {
- bestIndex = (int)index;
- bestValue = value;
- strcpy(bestName, keyName);
- }
+ for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL,
+ NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
+ const char *sp = keyName;
+ while (*sp && !isdigit(*sp))
+ sp++;
+ if (!*sp)
+ continue;
+ const char *ep = sp + 1;
+ while (*ep && (isdigit(*ep) || (*ep == '.')))
+ ep++;
+ char numBuf[32];
+ strncpy(numBuf, sp, sizeof(numBuf) - 1);
+ numBuf[sizeof(numBuf) - 1] = '\0';
+ double value = strtod(numBuf, NULL);
+ if (value > bestValue) {
+ bestIndex = (int)index;
+ bestValue = value;
+ strcpy(bestName, keyName);
+ }
size = sizeof(keyName) - 1;
}
// If we found the highest versioned key, open the key and get the value.
@@ -500,6 +501,10 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1",
"i586-redhat-linux","", "", triple);
+ // Fedora 12
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ "i686-redhat-linux","", "", triple);
+
// openSUSE 11.1 32 bit
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
"i586-suse-linux", "", "", triple);
@@ -643,11 +648,11 @@ static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
}
if (Verbose) {
- fprintf(stderr, "ignoring duplicate directory \"%s\"\n",
- CurEntry.getName());
+ llvm::errs() << "ignoring duplicate directory \""
+ << CurEntry.getName() << "\"\n";
if (DirToRemove != i)
- fprintf(stderr, " as it is a non-system directory that duplicates"
- " a system directory\n");
+ llvm::errs() << " as it is a non-system directory that duplicates "
+ << "a system directory\n";
}
// This is reached if the current entry is a duplicate. Remove the
@@ -680,11 +685,11 @@ void InitHeaderSearch::Realize() {
// If verbose, print the list of directories that will be searched.
if (Verbose) {
- fprintf(stderr, "#include \"...\" search starts here:\n");
+ llvm::errs() << "#include \"...\" search starts here:\n";
unsigned QuotedIdx = IncludeGroup[Quoted].size();
for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {
if (i == QuotedIdx)
- fprintf(stderr, "#include <...> search starts here:\n");
+ llvm::errs() << "#include <...> search starts here:\n";
const char *Name = SearchList[i].getName();
const char *Suffix;
if (SearchList[i].isNormalDir())
@@ -695,9 +700,9 @@ void InitHeaderSearch::Realize() {
assert(SearchList[i].isHeaderMap() && "Unknown DirectoryLookup");
Suffix = " (headermap)";
}
- fprintf(stderr, " %s%s\n", Name, Suffix);
+ llvm::errs() << " " << Name << Suffix << "\n";
}
- fprintf(stderr, "End of search list.\n");
+ llvm::errs() << "End of search list.\n";
}
}
@@ -715,21 +720,22 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
}
// Add entries from CPATH and friends.
- Init.AddDelimitedPaths(HSOpts.EnvIncPath.c_str());
+ Init.AddDelimitedPaths(HSOpts.EnvIncPath);
if (Lang.CPlusPlus && Lang.ObjC1)
- Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath.c_str());
+ Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath);
else if (Lang.CPlusPlus)
- Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath.c_str());
+ Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath);
else if (Lang.ObjC1)
- Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath.c_str());
+ Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath);
else
- Init.AddDelimitedPaths(HSOpts.CEnvIncPath.c_str());
+ Init.AddDelimitedPaths(HSOpts.CEnvIncPath);
- if (!HSOpts.BuiltinIncludePath.empty()) {
+ if (HSOpts.UseBuiltinIncludes) {
// Ignore the sys root, we *always* look for clang headers relative to
// supplied path.
- Init.AddPath(HSOpts.BuiltinIncludePath, System,
- false, false, false, /*IgnoreSysRoot=*/ true);
+ llvm::sys::Path P(HSOpts.ResourceDir);
+ P.appendComponent("include");
+ Init.AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true);
}
if (HSOpts.UseStandardIncludes)
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 972c21f..c1fc92d 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -13,17 +13,23 @@
#include "clang/Frontend/Utils.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/PreprocessorOptions.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/System/Path.h"
using namespace clang;
// Append a #define line to Buf for Macro. Macro should be of the form XXX,
// in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit
// "#define XXX Y z W". To get a #define with no value, use "XXX=".
-static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) {
+static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro,
+ Diagnostic *Diags = 0) {
const char *Command = "#define ";
Buf.insert(Buf.end(), Command, Command+strlen(Command));
if (const char *Equal = strchr(Macro, '=')) {
@@ -34,9 +40,9 @@ static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) {
// Per GCC -D semantics, the macro ends at \n if it exists.
const char *End = strpbrk(Equal, "\n\r");
if (End) {
- fprintf(stderr, "warning: macro '%s' contains embedded newline, text "
- "after the newline is ignored.\n",
- std::string(Macro, Equal).c_str());
+ assert(Diags && "Unexpected macro with embedded newline!");
+ Diags->Report(diag::warn_fe_macro_contains_embedded_newline)
+ << std::string(Macro, Equal);
} else {
End = Equal+strlen(Equal);
}
@@ -118,11 +124,9 @@ static void AddImplicitIncludePTH(std::vector<char> &Buf, Preprocessor &PP,
const char *OriginalFile = P->getOriginalSourceFile();
if (!OriginalFile) {
- assert(!ImplicitIncludePTH.empty());
- fprintf(stderr, "error: PTH file '%s' does not designate an original "
- "source header file for -include-pth\n",
- ImplicitIncludePTH.c_str());
- exit (1);
+ PP.getDiagnostics().Report(diag::err_fe_pth_file_has_no_source_header)
+ << ImplicitIncludePTH;
+ return;
}
AddImplicitInclude(Buf, OriginalFile);
@@ -358,6 +362,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineBuiltinMacro(Buf, "__int16=__INT16_TYPE__");
DefineBuiltinMacro(Buf, "__int32=__INT32_TYPE__");
DefineBuiltinMacro(Buf, "__int64=__INT64_TYPE__");
+ // Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however
+ // VC++ appears to only like __FUNCTION__.
+ DefineBuiltinMacro(Buf, "__PRETTY_FUNCTION__=__FUNCTION__");
// Work around some issues with Visual C++ headerws.
if (LangOpts.CPlusPlus) {
// Since we define wchar_t in C++ mode.
@@ -478,6 +485,52 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
TI.getTargetDefines(LangOpts, Buf);
}
+// Initialize the remapping of files to alternative contents, e.g.,
+// those specified through other files.
+static void InitializeFileRemapping(Diagnostic &Diags,
+ SourceManager &SourceMgr,
+ FileManager &FileMgr,
+ const PreprocessorOptions &InitOpts) {
+ // Remap files in the source manager.
+ for (PreprocessorOptions::remapped_file_iterator
+ Remap = InitOpts.remapped_file_begin(),
+ RemapEnd = InitOpts.remapped_file_end();
+ Remap != RemapEnd;
+ ++Remap) {
+ // Find the file that we're mapping to.
+ const FileEntry *ToFile = FileMgr.getFile(Remap->second);
+ if (!ToFile) {
+ Diags.Report(diag::err_fe_remap_missing_to_file)
+ << Remap->first << Remap->second;
+ continue;
+ }
+
+ // Create the file entry for the file that we're mapping from.
+ const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first,
+ ToFile->getSize(),
+ 0);
+ if (!FromFile) {
+ Diags.Report(diag::err_fe_remap_missing_from_file)
+ << Remap->first;
+ continue;
+ }
+
+ // Load the contents of the file we're mapping to.
+ std::string ErrorStr;
+ const llvm::MemoryBuffer *Buffer
+ = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr);
+ if (!Buffer) {
+ Diags.Report(diag::err_fe_error_opening)
+ << Remap->second << ErrorStr;
+ continue;
+ }
+
+ // Override the contents of the "from" file with the contents of
+ // the "to" file.
+ SourceMgr.overrideFileContents(FromFile, Buffer);
+ }
+}
+
/// InitializePreprocessor - Initialize the preprocessor getting it and the
/// environment ready to process a single file. This returns true on error.
///
@@ -486,6 +539,9 @@ void clang::InitializePreprocessor(Preprocessor &PP,
const HeaderSearchOptions &HSOpts) {
std::vector<char> PredefineBuffer;
+ InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(),
+ PP.getFileManager(), InitOpts);
+
const char *LineDirective = "# 1 \"<built-in>\" 3\n";
PredefineBuffer.insert(PredefineBuffer.end(),
LineDirective, LineDirective+strlen(LineDirective));
@@ -506,7 +562,8 @@ void clang::InitializePreprocessor(Preprocessor &PP,
if (InitOpts.Macros[i].second) // isUndef
UndefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str());
else
- DefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str());
+ DefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str(),
+ &PP.getDiagnostics());
}
// If -imacros are specified, include them now. These are processed before
@@ -523,6 +580,11 @@ void clang::InitializePreprocessor(Preprocessor &PP,
AddImplicitInclude(PredefineBuffer, Path);
}
+ // Exit the command line and go back to <built-in> (2 is LC_LEAVE).
+ LineDirective = "# 1 \"<built-in>\" 2\n";
+ PredefineBuffer.insert(PredefineBuffer.end(),
+ LineDirective, LineDirective+strlen(LineDirective));
+
// Null terminate PredefinedBuffer and add it.
PredefineBuffer.push_back(0);
PP.setPredefines(&PredefineBuffer[0]);
diff --git a/lib/Frontend/LangStandards.cpp b/lib/Frontend/LangStandards.cpp
index 771a58c..ed0ea1f 100644
--- a/lib/Frontend/LangStandards.cpp
+++ b/lib/Frontend/LangStandards.cpp
@@ -14,13 +14,13 @@ using namespace clang;
using namespace clang::frontend;
#define LANGSTANDARD(id, name, desc, features) \
- static LangStandard Lang_##id = { name, desc, features };
+ static const LangStandard Lang_##id = { name, desc, features };
#include "clang/Frontend/LangStandards.def"
const LangStandard &LangStandard::getLangStandardForKind(Kind K) {
switch (K) {
default:
- llvm::llvm_unreachable("Invalid language kind!");
+ llvm_unreachable("Invalid language kind!");
case lang_unspecified:
llvm::llvm_report_error("getLangStandardForKind() on unspecified kind");
#define LANGSTANDARD(id, name, desc, features) \
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index cb96bcb..48ef2ac 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -116,6 +116,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
diag::warn_pch_stack_protector);
PARSE_LANGOPT_BENIGN(InstantiationDepth);
PARSE_LANGOPT_IMPORTANT(OpenCL, diag::warn_pch_opencl);
+ PARSE_LANGOPT_BENIGN(CatchUndefined);
PARSE_LANGOPT_IMPORTANT(ElideConstructors, diag::warn_pch_elide_constructors);
#undef PARSE_LANGOPT_IRRELEVANT
#undef PARSE_LANGOPT_BENIGN
@@ -1569,13 +1570,14 @@ void PCHReader::InitializeContext(ASTContext &Ctx) {
/// \brief Retrieve the name of the original source file name
/// directly from the PCH file, without actually loading the PCH
/// file.
-std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) {
+std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName,
+ Diagnostic &Diags) {
// Open the PCH file.
std::string ErrStr;
llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
Buffer.reset(llvm::MemoryBuffer::getFile(PCHFileName.c_str(), &ErrStr));
if (!Buffer) {
- fprintf(stderr, "error: %s\n", ErrStr.c_str());
+ Diags.Report(diag::err_fe_unable_to_read_pch_file) << ErrStr;
return std::string();
}
@@ -1591,9 +1593,7 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) {
Stream.Read(8) != 'P' ||
Stream.Read(8) != 'C' ||
Stream.Read(8) != 'H') {
- fprintf(stderr,
- "error: '%s' does not appear to be a precompiled header file\n",
- PCHFileName.c_str());
+ Diags.Report(diag::err_fe_not_a_pch_file) << PCHFileName;
return std::string();
}
@@ -1608,14 +1608,14 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) {
switch (BlockID) {
case pch::PCH_BLOCK_ID:
if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
- fprintf(stderr, "error: malformed block record in PCH file\n");
+ Diags.Report(diag::err_fe_pch_malformed_block) << PCHFileName;
return std::string();
}
break;
default:
if (Stream.SkipBlock()) {
- fprintf(stderr, "error: malformed block record in PCH file\n");
+ Diags.Report(diag::err_fe_pch_malformed_block) << PCHFileName;
return std::string();
}
break;
@@ -1625,7 +1625,7 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) {
if (Code == llvm::bitc::END_BLOCK) {
if (Stream.ReadBlockEnd()) {
- fprintf(stderr, "error: error at end of module block in PCH file\n");
+ Diags.Report(diag::err_fe_pch_error_at_end_block) << PCHFileName;
return std::string();
}
continue;
@@ -1720,6 +1720,8 @@ bool PCHReader::ParseLanguageOptions(
++Idx;
PARSE_LANGOPT(InstantiationDepth);
PARSE_LANGOPT(OpenCL);
+ PARSE_LANGOPT(CatchUndefined);
+ // FIXME: Missing ElideConstructors?!
#undef PARSE_LANGOPT
return Listener->ReadLanguageOptions(LangOpts);
@@ -1881,6 +1883,10 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
Exceptions.data());
}
+ case pch::TYPE_UNRESOLVED_USING:
+ return Context->getTypeDeclType(
+ cast<UnresolvedUsingTypenameDecl>(GetDecl(Record[0])));
+
case pch::TYPE_TYPEDEF:
assert(Record.size() == 1 && "incorrect encoding of typedef type");
return Context->getTypeDeclType(cast<TypedefDecl>(GetDecl(Record[0])));
@@ -2045,6 +2051,9 @@ void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) {
VisitFunctionTypeLoc(TL);
}
+void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
@@ -2107,17 +2116,17 @@ void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
TL.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++]));
}
-DeclaratorInfo *PCHReader::GetDeclaratorInfo(const RecordData &Record,
+TypeSourceInfo *PCHReader::GetTypeSourceInfo(const RecordData &Record,
unsigned &Idx) {
QualType InfoTy = GetType(Record[Idx++]);
if (InfoTy.isNull())
return 0;
- DeclaratorInfo *DInfo = getContext()->CreateDeclaratorInfo(InfoTy);
+ TypeSourceInfo *TInfo = getContext()->CreateTypeSourceInfo(InfoTy);
TypeLocReader TLR(*this, Record, Idx);
- for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
+ for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
TLR.Visit(TL);
- return DInfo;
+ return TInfo;
}
QualType PCHReader::GetType(pch::TypeID ID) {
@@ -2183,7 +2192,7 @@ PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
case TemplateArgument::Expression:
return ReadDeclExpr();
case TemplateArgument::Type:
- return GetDeclaratorInfo(Record, Index);
+ return GetTypeSourceInfo(Record, Index);
case TemplateArgument::Template: {
SourceLocation
QualStart = SourceLocation::getFromRawEncoding(Record[Index++]),
@@ -2198,7 +2207,7 @@ PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
case TemplateArgument::Pack:
return TemplateArgumentLocInfo();
}
- llvm::llvm_unreachable("unexpected template argument loc");
+ llvm_unreachable("unexpected template argument loc");
return TemplateArgumentLocInfo();
}
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index 03f3b4767..01e1a41 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -107,7 +107,7 @@ void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
// the type associated with the TypedefDecl.
VisitNamedDecl(TD);
uint64_t TypeData = Record[Idx++];
- TD->setTypeDeclaratorInfo(Reader.GetDeclaratorInfo(Record, Idx));
+ TD->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
TD->setTypeForDecl(Reader.GetType(TypeData).getTypePtr());
}
@@ -126,6 +126,7 @@ void PCHDeclReader::VisitTagDecl(TagDecl *TD) {
void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) {
VisitTagDecl(ED);
ED->setIntegerType(Reader.GetType(Record[Idx++]));
+ ED->setPromotionType(Reader.GetType(Record[Idx++]));
// FIXME: C++ InstantiatedFrom
}
@@ -150,9 +151,9 @@ void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) {
void PCHDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
VisitValueDecl(DD);
- DeclaratorInfo *DInfo = Reader.GetDeclaratorInfo(Record, Idx);
- if (DInfo)
- DD->setDeclaratorInfo(DInfo);
+ TypeSourceInfo *TInfo = Reader.GetTypeSourceInfo(Record, Idx);
+ if (TInfo)
+ DD->setTypeSourceInfo(TInfo);
}
void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index 00734a0..f28e61e 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -349,7 +349,7 @@ unsigned PCHStmtReader::VisitPredefinedExpr(PredefinedExpr *E) {
unsigned PCHStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
VisitExpr(E);
- E->setDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++])));
E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
// FIXME: read qualifier
// FIXME: read explicit template arguments
@@ -428,7 +428,7 @@ unsigned PCHStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
E->setArgument(cast<Expr>(StmtStack.back()));
++Idx;
} else {
- E->setArgument(Reader.GetDeclaratorInfo(Record, Idx));
+ E->setArgument(Reader.GetTypeSourceInfo(Record, Idx));
}
E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
@@ -456,7 +456,7 @@ unsigned PCHStmtReader::VisitCallExpr(CallExpr *E) {
unsigned PCHStmtReader::VisitMemberExpr(MemberExpr *E) {
VisitExpr(E);
E->setBase(cast<Expr>(StmtStack.back()));
- E->setMemberDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setMemberDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++])));
E->setMemberLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
E->setArrow(Record[Idx++]);
return 1;
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index e79f9c9..681c1ff 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -166,6 +166,14 @@ void PCHTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
Code = pch::TYPE_FUNCTION_PROTO;
}
+#if 0
+// For when we want it....
+void PCHTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
+ Writer.AddDeclRef(T->getDecl(), Record);
+ Code = pch::TYPE_UNRESOLVED_USING;
+}
+#endif
+
void PCHTypeWriter::VisitTypedefType(const TypedefType *T) {
Writer.AddDeclRef(T->getDecl(), Record);
Code = pch::TYPE_TYPEDEF;
@@ -337,6 +345,9 @@ void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) {
VisitFunctionTypeLoc(TL);
}
+void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
@@ -770,6 +781,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
Record.push_back(LangOpts.getStackProtectorMode());
Record.push_back(LangOpts.InstantiationDepth);
Record.push_back(LangOpts.OpenCL);
+ Record.push_back(LangOpts.CatchUndefined);
Record.push_back(LangOpts.ElideConstructors);
Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record);
}
@@ -2129,7 +2141,7 @@ void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg,
AddStmt(Arg.getLocInfo().getAsExpr());
break;
case TemplateArgument::Type:
- AddDeclaratorInfo(Arg.getLocInfo().getAsDeclaratorInfo(), Record);
+ AddTypeSourceInfo(Arg.getLocInfo().getAsTypeSourceInfo(), Record);
break;
case TemplateArgument::Template:
Record.push_back(
@@ -2145,15 +2157,15 @@ void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg,
}
}
-void PCHWriter::AddDeclaratorInfo(DeclaratorInfo *DInfo, RecordData &Record) {
- if (DInfo == 0) {
+void PCHWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordData &Record) {
+ if (TInfo == 0) {
AddTypeRef(QualType(), Record);
return;
}
- AddTypeRef(DInfo->getType(), Record);
+ AddTypeRef(TInfo->getType(), Record);
TypeLocWriter TLW(*this, Record);
- for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
+ for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
TLW.Visit(TL);
}
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index c7bfee2..049cdb0 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -14,9 +14,9 @@
#include "clang/Frontend/PCHWriter.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Bitcode/BitstreamWriter.h"
-#include <cstdio>
-
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -106,7 +106,7 @@ void PCHDeclWriter::VisitTypeDecl(TypeDecl *D) {
void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
VisitTypeDecl(D);
- Writer.AddDeclaratorInfo(D->getTypeDeclaratorInfo(), Record);
+ Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
Code = pch::DECL_TYPEDEF;
}
@@ -123,6 +123,7 @@ void PCHDeclWriter::VisitTagDecl(TagDecl *D) {
void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) {
VisitTagDecl(D);
Writer.AddTypeRef(D->getIntegerType(), Record);
+ Writer.AddTypeRef(D->getPromotionType(), Record);
// FIXME: C++ InstantiatedFrom
Code = pch::DECL_ENUM;
}
@@ -151,7 +152,7 @@ void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) {
void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
VisitValueDecl(D);
- Writer.AddDeclaratorInfo(D->getDeclaratorInfo(), Record);
+ Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
}
void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
@@ -370,7 +371,7 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
// If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here
// we dynamically check for the properties that we optimize for, but don't
// know are true of all PARM_VAR_DECLs.
- if (!D->getDeclaratorInfo() &&
+ if (!D->getTypeSourceInfo() &&
!D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed() &&
@@ -568,12 +569,9 @@ void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) {
W.Visit(D);
if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset);
- if (!W.Code) {
- fprintf(stderr, "Cannot serialize declaration of kind %s\n",
- D->getDeclKindName());
- assert(false && "Unhandled declaration kind while generating PCH");
- exit(-1);
- }
+ if (!W.Code)
+ llvm::llvm_report_error(llvm::StringRef("unexpected declaration kind '") +
+ D->getDeclKindName() + "'");
Stream.EmitRecord(W.Code, Record, W.AbbrevToUse);
// If the declaration had any attributes, write them now.
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index 27b83ed..22f7ad6 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -388,7 +388,7 @@ void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
VisitExpr(E);
Record.push_back(E->isSizeOf());
if (E->isArgumentType())
- Writer.AddDeclaratorInfo(E->getArgumentTypeInfo(), Record);
+ Writer.AddTypeSourceInfo(E->getArgumentTypeInfo(), Record);
else {
Record.push_back(0);
Writer.WriteSubStmt(E->getArgumentExpr());
diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp
index 80ee2c2..92cafe6 100644
--- a/lib/Frontend/PlistDiagnostics.cpp
+++ b/lib/Frontend/PlistDiagnostics.cpp
@@ -30,6 +30,40 @@ namespace clang {
}
namespace {
+struct CompareDiagnostics {
+ // Compare if 'X' is "<" than 'Y'.
+ bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
+ // First compare by location
+ const FullSourceLoc &XLoc = X->getLocation().asLocation();
+ const FullSourceLoc &YLoc = Y->getLocation().asLocation();
+ if (XLoc < YLoc)
+ return true;
+ if (XLoc != YLoc)
+ return false;
+
+ // Next, compare by bug type.
+ llvm::StringRef XBugType = X->getBugType();
+ llvm::StringRef YBugType = Y->getBugType();
+ if (XBugType < YBugType)
+ return true;
+ if (XBugType != YBugType)
+ return false;
+
+ // Next, compare by bug description.
+ llvm::StringRef XDesc = X->getDescription();
+ llvm::StringRef YDesc = Y->getDescription();
+ if (XDesc < YDesc)
+ return true;
+ if (XDesc != YDesc)
+ return false;
+
+ // FIXME: Further refine by comparing PathDiagnosticPieces?
+ return false;
+ }
+};
+}
+
+namespace {
class PlistDiagnostics : public PathDiagnosticClient {
std::vector<const PathDiagnostic*> BatchedDiags;
const std::string OutputFile;
@@ -314,6 +348,11 @@ void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string>
return;
flushed = true;
+
+ // Sort the diagnostics so that they are always emitted in a deterministic
+ // order.
+ if (!BatchedDiags.empty())
+ std::sort(BatchedDiags.begin(), BatchedDiags.end(), CompareDiagnostics());
// Build up a set of FIDs that we use by scanning the locations and
// ranges of the diagnostics.
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 3742405..d9708d8 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -36,22 +36,23 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI,
if (MI.isFunctionLike()) {
OS << '(';
- if (MI.arg_empty())
- ;
- else if (MI.getNumArgs() == 1)
- OS << (*MI.arg_begin())->getName();
- else {
+ if (!MI.arg_empty()) {
MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end();
- OS << (*AI++)->getName();
- while (AI != E)
- OS << ',' << (*AI++)->getName();
- }
-
- if (MI.isVariadic()) {
- if (!MI.arg_empty())
+ for (; AI+1 != E; ++AI) {
+ OS << (*AI)->getName();
OS << ',';
- OS << "...";
+ }
+
+ // Last argument.
+ if ((*AI)->getName() == "__VA_ARGS__")
+ OS << "...";
+ else
+ OS << (*AI)->getName();
}
+
+ if (MI.isGNUVarargs())
+ OS << "..."; // #define foo(x...)
+
OS << ')';
}
@@ -94,6 +95,7 @@ private:
bool Initialized;
bool DisableLineMarkers;
bool DumpDefines;
+ bool UseLineDirective;
public:
PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os,
bool lineMarkers, bool defines)
@@ -105,6 +107,9 @@ public:
EmittedMacroOnThisLine = false;
FileType = SrcMgr::C_User;
Initialized = false;
+
+ // If we're in microsoft mode, use normal #line instead of line markers.
+ UseLineDirective = PP.getLangOptions().Microsoft;
}
void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
@@ -141,17 +146,24 @@ void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
EmittedMacroOnThisLine = false;
}
- OS << '#' << ' ' << LineNo << ' ' << '"';
- OS.write(&CurFilename[0], CurFilename.size());
- OS << '"';
-
- if (ExtraLen)
- OS.write(Extra, ExtraLen);
-
- if (FileType == SrcMgr::C_System)
- OS.write(" 3", 2);
- else if (FileType == SrcMgr::C_ExternCSystem)
- OS.write(" 3 4", 4);
+ // Emit #line directives or GNU line markers depending on what mode we're in.
+ if (UseLineDirective) {
+ OS << "#line" << ' ' << LineNo << ' ' << '"';
+ OS.write(&CurFilename[0], CurFilename.size());
+ OS << '"';
+ } else {
+ OS << '#' << ' ' << LineNo << ' ' << '"';
+ OS.write(&CurFilename[0], CurFilename.size());
+ OS << '"';
+
+ if (ExtraLen)
+ OS.write(Extra, ExtraLen);
+
+ if (FileType == SrcMgr::C_System)
+ OS.write(" 3", 2);
+ else if (FileType == SrcMgr::C_ExternCSystem)
+ OS.write(" 3 4", 4);
+ }
OS << '\n';
}
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index 710fa55..df85c13 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -255,7 +255,10 @@ namespace {
Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp);
- void WarnAboutReturnGotoContinueOrBreakStmts(Stmt *S);
+ void WarnAboutReturnGotoStmts(Stmt *S);
+ void HasReturnStmts(Stmt *S, bool &hasReturns);
+ void RewriteTryReturnStmts(Stmt *S);
+ void RewriteSyncReturnStmts(Stmt *S, std::string buf);
Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S);
Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S);
Stmt *RewriteObjCCatchStmt(ObjCAtCatchStmt *S);
@@ -328,11 +331,16 @@ namespace {
const char *funcName, std::string Tag);
std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
const char *funcName, std::string Tag);
- std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
- bool hasCopyDisposeHelpers);
+ std::string SynthesizeBlockImpl(BlockExpr *CE,
+ std::string Tag, std::string Desc);
+ std::string SynthesizeBlockDescriptor(std::string DescTag,
+ std::string ImplTag,
+ int i, const char *funcName,
+ unsigned hasCopy);
Stmt *SynthesizeBlockCall(CallExpr *Exp);
void SynthesizeBlockLiterals(SourceLocation FunLocStart,
const char *FunName);
+ void RewriteRecordBody(RecordDecl *RD);
void CollectBlockDeclRefInfo(BlockExpr *Exp);
void GetBlockCallExprs(Stmt *S);
@@ -547,14 +555,21 @@ void RewriteObjC::Initialize(ASTContext &context) {
Preamble += "struct __block_impl {\n";
Preamble += " void *isa;\n";
Preamble += " int Flags;\n";
- Preamble += " int Size;\n";
+ Preamble += " int Reserved;\n";
Preamble += " void *FuncPtr;\n";
Preamble += "};\n";
Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n";
- Preamble += "__OBJC_RW_STATICIMPORT void _Block_object_assign(void *, const void *, const int);\n";
- Preamble += "__OBJC_RW_STATICIMPORT void _Block_object_dispose(const void *, const int);\n";
- Preamble += "__OBJC_RW_STATICIMPORT void *_NSConcreteGlobalBlock[32];\n";
- Preamble += "__OBJC_RW_STATICIMPORT void *_NSConcreteStackBlock[32];\n";
+ Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n";
+ Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_assign(void *, const void *, const int);\n";
+ Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n";
+ Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n";
+ Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n";
+ Preamble += "#else\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n";
+ Preamble += "#endif\n";
Preamble += "#endif\n";
if (LangOpts.Microsoft) {
Preamble += "#undef __OBJC_RW_DLLIMPORT\n";
@@ -1325,7 +1340,12 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
// type elem;
NamedDecl* D = cast<NamedDecl>(DS->getSingleDecl());
QualType ElementType = cast<ValueDecl>(D)->getType();
- elementTypeAsString = ElementType.getAsString();
+ if (ElementType->isObjCQualifiedIdType() ||
+ ElementType->isObjCQualifiedInterfaceType())
+ // Simply use 'id' for all qualified types.
+ elementTypeAsString = "id";
+ else
+ elementTypeAsString = ElementType.getAsString();
buf += elementTypeAsString;
buf += " ";
elementName = D->getNameAsCString();
@@ -1335,8 +1355,13 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
else {
DeclRefExpr *DR = cast<DeclRefExpr>(S->getElement());
elementName = DR->getDecl()->getNameAsCString();
- elementTypeAsString
- = cast<ValueDecl>(DR->getDecl())->getType().getAsString();
+ ValueDecl *VD = cast<ValueDecl>(DR->getDecl());
+ if (VD->getType()->isObjCQualifiedIdType() ||
+ VD->getType()->isObjCQualifiedInterfaceType())
+ // Simply use 'id' for all qualified types.
+ elementTypeAsString = "id";
+ else
+ elementTypeAsString = VD->getType().getAsString();
}
// struct __objcFastEnumerationState enumState = { 0 };
@@ -1502,7 +1527,9 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
buf += "}\n";
buf += "{ /* implicit finally clause */\n";
buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
- buf += " objc_sync_exit(";
+
+ std::string syncBuf;
+ syncBuf += " objc_sync_exit(";
Expr *syncExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(),
CastExpr::CK_Unknown,
S->getSynchExpr(),
@@ -1513,31 +1540,102 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
llvm::raw_string_ostream syncExprBuf(syncExprBufS);
syncExpr->printPretty(syncExprBuf, *Context, 0,
PrintingPolicy(LangOpts));
- buf += syncExprBuf.str();
- buf += ");\n";
- buf += " if (_rethrow) objc_exception_throw(_rethrow);\n";
+ syncBuf += syncExprBuf.str();
+ syncBuf += ");";
+
+ buf += syncBuf;
+ buf += "\n if (_rethrow) objc_exception_throw(_rethrow);\n";
buf += "}\n";
buf += "}";
ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
+
+ bool hasReturns = false;
+ HasReturnStmts(S->getSynchBody(), hasReturns);
+ if (hasReturns)
+ RewriteSyncReturnStmts(S->getSynchBody(), syncBuf);
+
return 0;
}
-void RewriteObjC::WarnAboutReturnGotoContinueOrBreakStmts(Stmt *S) {
+void RewriteObjC::WarnAboutReturnGotoStmts(Stmt *S)
+{
// Perform a bottom up traversal of all children.
for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
CI != E; ++CI)
if (*CI)
- WarnAboutReturnGotoContinueOrBreakStmts(*CI);
+ WarnAboutReturnGotoStmts(*CI);
- if (isa<ReturnStmt>(S) || isa<ContinueStmt>(S) ||
- isa<BreakStmt>(S) || isa<GotoStmt>(S)) {
+ if (isa<ReturnStmt>(S) || isa<GotoStmt>(S)) {
Diags.Report(Context->getFullLoc(S->getLocStart()),
TryFinallyContainsReturnDiag);
}
return;
}
+void RewriteObjC::HasReturnStmts(Stmt *S, bool &hasReturns)
+{
+ // Perform a bottom up traversal of all children.
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++CI)
+ if (*CI)
+ HasReturnStmts(*CI, hasReturns);
+
+ if (isa<ReturnStmt>(S))
+ hasReturns = true;
+ return;
+}
+
+void RewriteObjC::RewriteTryReturnStmts(Stmt *S) {
+ // Perform a bottom up traversal of all children.
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++CI)
+ if (*CI) {
+ RewriteTryReturnStmts(*CI);
+ }
+ if (isa<ReturnStmt>(S)) {
+ SourceLocation startLoc = S->getLocStart();
+ const char *startBuf = SM->getCharacterData(startLoc);
+
+ const char *semiBuf = strchr(startBuf, ';');
+ assert((*semiBuf == ';') && "RewriteTryReturnStmts: can't find ';'");
+ SourceLocation onePastSemiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf+1);
+
+ std::string buf;
+ buf = "{ objc_exception_try_exit(&_stack); return";
+
+ ReplaceText(startLoc, 6, buf.c_str(), buf.size());
+ InsertText(onePastSemiLoc, "}", 1);
+ }
+ return;
+}
+
+void RewriteObjC::RewriteSyncReturnStmts(Stmt *S, std::string syncExitBuf) {
+ // Perform a bottom up traversal of all children.
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++CI)
+ if (*CI) {
+ RewriteSyncReturnStmts(*CI, syncExitBuf);
+ }
+ if (isa<ReturnStmt>(S)) {
+ SourceLocation startLoc = S->getLocStart();
+ const char *startBuf = SM->getCharacterData(startLoc);
+
+ const char *semiBuf = strchr(startBuf, ';');
+ assert((*semiBuf == ';') && "RewriteSyncReturnStmts: can't find ';'");
+ SourceLocation onePastSemiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf+1);
+
+ std::string buf;
+ buf = "{ objc_exception_try_exit(&_stack);";
+ buf += syncExitBuf;
+ buf += " return";
+
+ ReplaceText(startLoc, 6, buf.c_str(), buf.size());
+ InsertText(onePastSemiLoc, "}", 1);
+ }
+ return;
+}
+
Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
// Get the start location and compute the semi location.
SourceLocation startLoc = S->getLocStart();
@@ -1689,13 +1787,21 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
lastCurlyLoc = body->getLocEnd();
// Now check for any return/continue/go statements within the @try.
- WarnAboutReturnGotoContinueOrBreakStmts(S->getTryBody());
+ WarnAboutReturnGotoStmts(S->getTryBody());
} else { /* no finally clause - make sure we synthesize an implicit one */
buf = "{ /* implicit finally clause */\n";
buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
buf += " if (_rethrow) objc_exception_throw(_rethrow);\n";
buf += "}";
ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
+
+ // Now check for any return/continue/go statements within the @try.
+ // The implicit finally clause won't called if the @try contains any
+ // jump statements.
+ bool hasReturns = false;
+ HasReturnStmts(S->getTryBody(), hasReturns);
+ if (hasReturns)
+ RewriteTryReturnStmts(S->getTryBody());
}
// Now emit the final closing curly brace...
lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1);
@@ -1878,6 +1984,10 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
return;
Type = proto->getResultType();
}
+ else if (FieldDecl *FD = dyn_cast<FieldDecl>(Dcl)) {
+ Loc = FD->getLocation();
+ Type = FD->getType();
+ }
else
return;
@@ -2134,8 +2244,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
PrintingPolicy(LangOpts));
Preamble += prettyBuf.str();
Preamble += ",";
- // The minus 2 removes the begin/end double quotes.
- Preamble += utostr(prettyBuf.str().size()-2) + "};\n";
+ Preamble += utostr(Exp->getString()->getByteLength()) + "};\n";
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
&Context->Idents.get(S.c_str()), strType, 0,
@@ -2569,7 +2678,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// Build sizeof(returnType)
SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true,
- Context->getTrivialDeclaratorInfo(returnType),
+ Context->getTrivialTypeSourceInfo(returnType),
Context->getSizeType(),
SourceLocation(), SourceLocation());
// (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
@@ -2609,12 +2718,12 @@ Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) {
// typedef struct objc_object Protocol;
QualType RewriteObjC::getProtocolType() {
if (!ProtocolTypeDecl) {
- DeclaratorInfo *DInfo
- = Context->getTrivialDeclaratorInfo(Context->getObjCIdType());
+ TypeSourceInfo *TInfo
+ = Context->getTrivialTypeSourceInfo(Context->getObjCIdType());
ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl,
SourceLocation(),
&Context->Idents.get("Protocol"),
- DInfo);
+ TInfo);
}
return Context->getTypeDeclType(ProtocolTypeDecl);
}
@@ -2737,7 +2846,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
ReplaceText(LocStart, endHeader-startBuf, Result.c_str(), Result.size());
} else {
// rewrite the original header *without* disturbing the '{'
- ReplaceText(LocStart, cursor-startBuf-1, Result.c_str(), Result.size());
+ ReplaceText(LocStart, cursor-startBuf, Result.c_str(), Result.size());
}
if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) {
Result = "\n struct ";
@@ -3689,20 +3798,18 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
return S;
}
-std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
- bool hasCopyDisposeHelpers) {
+std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
+ std::string Desc) {
std::string S = "\nstruct " + Tag;
std::string Constructor = " " + Tag;
S += " {\n struct __block_impl impl;\n";
+ S += " struct " + Desc;
+ S += "* Desc;\n";
- if (hasCopyDisposeHelpers)
- S += " void *copy;\n void *dispose;\n";
-
- Constructor += "(void *fp";
-
- if (hasCopyDisposeHelpers)
- Constructor += ", void *copyHelp, void *disposeHelp";
+ Constructor += "(void *fp, "; // Invoke function pointer.
+ Constructor += "struct " + Desc; // Descriptor pointer.
+ Constructor += " *desc";
if (BlockDeclRefs.size()) {
// Output all "by copy" declarations.
@@ -3765,11 +3872,9 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n";
else
Constructor += " impl.isa = &_NSConcreteStackBlock;\n";
- Constructor += " impl.Size = sizeof(";
- Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
+ Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n";
- if (hasCopyDisposeHelpers)
- Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
+ Constructor += " Desc = desc;\n";
// Initialize all "by copy" arguments.
for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
@@ -3800,10 +3905,8 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n";
else
Constructor += " impl.isa = &_NSConcreteStackBlock;\n";
- Constructor += " impl.Size = sizeof(";
- Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
- if (hasCopyDisposeHelpers)
- Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
+ Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n";
+ Constructor += " Desc = desc;\n";
}
Constructor += " ";
Constructor += "}\n";
@@ -3812,6 +3915,29 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
return S;
}
+std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag,
+ std::string ImplTag, int i,
+ const char *FunName,
+ unsigned hasCopy) {
+ std::string S = "\nstatic struct " + DescTag;
+
+ S += " {\n unsigned long reserved;\n";
+ S += " unsigned long Block_size;\n";
+ if (hasCopy) {
+ S += " void *copy;\n void *dispose;\n";
+ }
+ S += "} ";
+
+ S += DescTag + "_DATA = { 0, sizeof(struct ";
+ S += ImplTag + ")";
+ if (hasCopy) {
+ S += ", __" + std::string(FunName) + "_block_copy_" + utostr(i);
+ S += ", __" + std::string(FunName) + "_block_dispose_" + utostr(i);
+ }
+ S += "};\n";
+ return S;
+}
+
void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
const char *FunName) {
// Insert closures that were part of the function.
@@ -3819,21 +3945,24 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
CollectBlockDeclRefInfo(Blocks[i]);
- std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i);
+ std::string ImplTag = "__" + std::string(FunName) + "_block_impl_" + utostr(i);
+ std::string DescTag = "__" + std::string(FunName) + "_block_desc_" + utostr(i);
- std::string CI = SynthesizeBlockImpl(Blocks[i], Tag,
- ImportedBlockDecls.size() > 0);
+ std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag);
InsertText(FunLocStart, CI.c_str(), CI.size());
- std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag);
+ std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag);
InsertText(FunLocStart, CF.c_str(), CF.size());
if (ImportedBlockDecls.size()) {
- std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, Tag);
+ std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag);
InsertText(FunLocStart, HF.c_str(), HF.size());
}
+ std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName,
+ ImportedBlockDecls.size() > 0);
+ InsertText(FunLocStart, BD.c_str(), BD.size());
BlockDeclRefs.clear();
BlockByRefDecls.clear();
@@ -4243,25 +4372,21 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
SourceLocation());
InitExprs.push_back(castExpr);
- if (ImportedBlockDecls.size()) {
- std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber;
- FD = SynthBlockInitFunctionDecl(Buf.c_str());
- Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
- castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy,
- CastExpr::CK_Unknown, Arg,
- Context->VoidPtrTy, SourceLocation(),
- SourceLocation());
- InitExprs.push_back(castExpr);
-
- Buf = "__" + FuncName + "_block_dispose_" + BlockNumber;
- FD = SynthBlockInitFunctionDecl(Buf.c_str());
- Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
- castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy,
- CastExpr::CK_Unknown, Arg,
- Context->VoidPtrTy, SourceLocation(),
- SourceLocation());
- InitExprs.push_back(castExpr);
- }
+ // Initialize the block descriptor.
+ std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA";
+
+ VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
+ &Context->Idents.get(DescData.c_str()),
+ Context->VoidPtrTy, 0,
+ VarDecl::Static);
+ UnaryOperator *DescRefExpr = new (Context) UnaryOperator(
+ new (Context) DeclRefExpr(NewVD,
+ Context->VoidPtrTy, SourceLocation()),
+ UnaryOperator::AddrOf,
+ Context->getPointerType(Context->VoidPtrTy),
+ SourceLocation());
+ InitExprs.push_back(DescRefExpr);
+
// Add initializers for any closure decl refs.
if (BlockDeclRefs.size()) {
Expr *Exp;
@@ -4297,6 +4422,17 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
InitExprs.push_back(Exp);
}
}
+ if (ImportedBlockDecls.size()) { // generate "1<<25" to indicate we have helper functions.
+ unsigned IntSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
+ BinaryOperator *Exp = new (Context) BinaryOperator(
+ new (Context) IntegerLiteral(llvm::APInt(IntSize, 1),
+ Context->IntTy,SourceLocation()),
+ new (Context) IntegerLiteral(llvm::APInt(IntSize, 25),
+ Context->IntTy, SourceLocation()),
+ BinaryOperator::Shl, Context->IntTy, SourceLocation());
+ InitExprs.push_back(Exp);
+ }
NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(),
FType, SourceLocation());
NewRep = new (Context) UnaryOperator(NewRep, UnaryOperator::AddrOf,
@@ -4486,7 +4622,14 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
// FIXME: What we're doing here is modifying the type-specifier that
// precedes the first Decl. In the future the DeclGroup should have
// a separate type-specifier that we can rewrite.
- RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin());
+ // NOTE: We need to avoid rewriting the DeclStmt if it is within
+ // the context of an ObjCForCollectionStmt. For example:
+ // NSArray *someArray;
+ // for (id <FooProtocol> index in someArray) ;
+ // This is because RewriteObjCForCollectionStmt() does textual rewriting
+ // and it depends on the original text locations/positions.
+ if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))
+ RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin());
// Blocks rewrite rules.
for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
@@ -4552,6 +4695,18 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
return S;
}
+void RewriteObjC::RewriteRecordBody(RecordDecl *RD) {
+ for (RecordDecl::field_iterator i = RD->field_begin(),
+ e = RD->field_end(); i != e; ++i) {
+ FieldDecl *FD = *i;
+ if (isTopLevelBlockPointerType(FD->getType()))
+ RewriteBlockPointerDecl(FD);
+ if (FD->getType()->isObjCQualifiedIdType() ||
+ FD->getType()->isObjCQualifiedInterfaceType())
+ RewriteObjCQualifiedInterfaceTypes(FD);
+ }
+}
+
/// HandleDeclInMainFile - This is called for each top-level decl defined in the
/// main file of the input.
void RewriteObjC::HandleDeclInMainFile(Decl *D) {
@@ -4618,6 +4773,10 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
RewriteCastExpr(CE);
}
}
+ } else if (VD->getType()->isRecordType()) {
+ RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl();
+ if (RD->isDefinition())
+ RewriteRecordBody(RD);
}
if (VD->getInit()) {
GlobalVarDecl = VD;
@@ -4645,17 +4804,16 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
RewriteBlockPointerDecl(TD);
else if (TD->getUnderlyingType()->isFunctionPointerType())
CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ else if (TD->getUnderlyingType()->isRecordType()) {
+ RecordDecl *RD = TD->getUnderlyingType()->getAs<RecordType>()->getDecl();
+ if (RD->isDefinition())
+ RewriteRecordBody(RD);
+ }
return;
}
if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
- if (RD->isDefinition()) {
- for (RecordDecl::field_iterator i = RD->field_begin(),
- e = RD->field_end(); i != e; ++i) {
- FieldDecl *FD = *i;
- if (isTopLevelBlockPointerType(FD->getType()))
- RewriteBlockPointerDecl(FD);
- }
- }
+ if (RD->isDefinition())
+ RewriteRecordBody(RD);
return;
}
// Nothing yet.
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 6ab0e16..61f8a70 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -279,13 +279,14 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
assert(!Loc.isInvalid() && "must have a valid source location here");
// If this is a macro ID, first emit information about where this was
- // instantiated (recursively) then emit information about where. the token was
+ // instantiated (recursively) then emit information about where the token was
// spelled from.
if (!Loc.isFileID()) {
SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first;
// FIXME: Map ranges?
EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns);
+ // Map the location.
Loc = SM.getImmediateSpellingLoc(Loc);
// Map the ranges.
@@ -295,15 +296,22 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
if (E.isMacroID()) E = SM.getImmediateSpellingLoc(E);
Ranges[i] = SourceRange(S, E);
}
+
+ // Get the pretty name, according to #line directives etc.
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+
+ // If this diagnostic is not in the main file, print out the "included from"
+ // lines.
+ if (LastWarningLoc != PLoc.getIncludeLoc()) {
+ LastWarningLoc = PLoc.getIncludeLoc();
+ PrintIncludeStack(LastWarningLoc, SM);
+ }
if (DiagOpts->ShowLocation) {
- std::pair<FileID, unsigned> IInfo = SM.getDecomposedInstantiationLoc(Loc);
-
// Emit the file/line/column that this expansion came from.
- OS << SM.getBuffer(IInfo.first)->getBufferIdentifier() << ':'
- << SM.getLineNumber(IInfo.first, IInfo.second) << ':';
+ OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':';
if (DiagOpts->ShowColumn)
- OS << SM.getColumnNumber(IInfo.first, IInfo.second) << ':';
+ OS << PLoc.getColumn() << ':';
OS << ' ';
}
OS << "note: instantiated from:\n";
@@ -489,12 +497,17 @@ static inline char findMatchingPunctuation(char c) {
///
/// \returns the index pointing one character past the end of the
/// word.
-unsigned findEndOfWord(unsigned Start,
- const llvm::SmallVectorImpl<char> &Str,
- unsigned Length, unsigned Column,
- unsigned Columns) {
+static unsigned findEndOfWord(unsigned Start,
+ const llvm::SmallVectorImpl<char> &Str,
+ unsigned Length, unsigned Column,
+ unsigned Columns) {
+ assert(Start < Str.size() && "Invalid start position!");
unsigned End = Start + 1;
+ // If we are already at the end of the string, take that as the word.
+ if (End == Str.size())
+ return End;
+
// Determine if the start of the string is actually opening
// punctuation, e.g., a quote or parentheses.
char EndPunct = findMatchingPunctuation(Str[Start]);
@@ -645,11 +658,17 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
if (DiagOpts->ShowLocation) {
if (DiagOpts->ShowColors)
OS.changeColor(savedColor, true);
- OS << PLoc.getFilename() << ':' << LineNo << ':';
- if (DiagOpts->ShowColumn)
- if (unsigned ColNo = PLoc.getColumn())
- OS << ColNo << ':';
-
+
+ // Emit a Visual Studio compatible line number syntax.
+ if (LangOpts && LangOpts->Microsoft) {
+ OS << PLoc.getFilename() << '(' << LineNo << ')';
+ OS << " : ";
+ } else {
+ OS << PLoc.getFilename() << ':' << LineNo << ':';
+ if (DiagOpts->ShowColumn)
+ if (unsigned ColNo = PLoc.getColumn())
+ OS << ColNo << ':';
+ }
if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) {
FileID CaretFileID =
SM.getFileID(SM.getInstantiationLoc(Info.getLocation()));
diff --git a/lib/Headers/limits.h b/lib/Headers/limits.h
index e4909ab..2627533 100644
--- a/lib/Headers/limits.h
+++ b/lib/Headers/limits.h
@@ -49,7 +49,6 @@
#undef LONG_MAX
#undef ULONG_MAX
-#undef MB_LEN_MAX
#undef CHAR_BIT
#undef CHAR_MIN
#undef CHAR_MAX
diff --git a/lib/Headers/tmmintrin.h b/lib/Headers/tmmintrin.h
index 374a27e..7adb776 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)))
+#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n*8)))
static inline __m128i __attribute__((__always_inline__, __nodebug__))
_mm_hadd_epi16(__m128i a, __m128i b)
diff --git a/lib/Index/ASTVisitor.h b/lib/Index/ASTVisitor.h
index 0ae78fb..943c720 100644
--- a/lib/Index/ASTVisitor.h
+++ b/lib/Index/ASTVisitor.h
@@ -52,8 +52,8 @@ public:
void VisitDeclaratorDecl(DeclaratorDecl *D) {
BaseDeclVisitor::VisitDeclaratorDecl(D);
- if (DeclaratorInfo *DInfo = D->getDeclaratorInfo())
- Visit(DInfo->getTypeLoc());
+ if (TypeSourceInfo *TInfo = D->getTypeSourceInfo())
+ Visit(TInfo->getTypeLoc());
}
void VisitFunctionDecl(FunctionDecl *D) {
@@ -104,7 +104,7 @@ public:
}
void VisitBlockExpr(BlockExpr *Node) {
- Visit(Node->getBlockDecl());
+ // The BlockDecl is also visited by 'VisitDeclContext()'. No need to visit it twice.
}
void VisitStmt(Stmt *Node) {
diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt
index 5f81817..4d67035 100644
--- a/lib/Index/CMakeLists.txt
+++ b/lib/Index/CMakeLists.txt
@@ -3,6 +3,7 @@ set(LLVM_NO_RTTI 1)
add_clang_library(clangIndex
ASTLocation.cpp
Analyzer.cpp
+ CallGraph.cpp
DeclReferenceMap.cpp
Entity.cpp
GlobalSelector.cpp
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Index/CallGraph.cpp
index c1040f0..6403319 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Index/CallGraph.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/CallGraph.h"
+#include "clang/Index/CallGraph.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/StmtVisitor.h"
diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp
index c7379f7..81a5de4 100644
--- a/lib/Index/ResolveLocation.cpp
+++ b/lib/Index/ResolveLocation.cpp
@@ -30,7 +30,7 @@ protected:
ASTContext &Ctx;
SourceLocation Loc;
- ASTLocation ResolveInDeclarator(Decl *D, Stmt *Stm, DeclaratorInfo *DInfo);
+ ASTLocation ResolveInDeclarator(Decl *D, Stmt *Stm, TypeSourceInfo *TInfo);
enum RangePos {
BeforeLoc,
@@ -39,13 +39,13 @@ protected:
};
RangePos CheckRange(SourceRange Range);
- RangePos CheckRange(DeclaratorInfo *DInfo);
+ RangePos CheckRange(TypeSourceInfo *TInfo);
RangePos CheckRange(Decl *D) {
if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D))
- if (ContainsLocation(DD->getDeclaratorInfo()))
+ if (ContainsLocation(DD->getTypeSourceInfo()))
return ContainsLoc;
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D))
- if (ContainsLocation(TD->getTypeDeclaratorInfo()))
+ if (ContainsLocation(TD->getTypeSourceInfo()))
return ContainsLoc;
return CheckRange(D->getSourceRange());
@@ -142,9 +142,9 @@ StmtLocResolver::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
"Should visit only after verifying that loc is in range");
if (Node->isArgumentType()) {
- DeclaratorInfo *DInfo = Node->getArgumentTypeInfo();
- if (ContainsLocation(DInfo))
- return ResolveInDeclarator(Parent, Node, DInfo);
+ TypeSourceInfo *TInfo = Node->getArgumentTypeInfo();
+ if (ContainsLocation(TInfo))
+ return ResolveInDeclarator(Parent, Node, TInfo);
} else {
Expr *SubNode = Node->getArgumentExpr();
if (ContainsLocation(SubNode))
@@ -245,8 +245,8 @@ ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) {
assert(ContainsLocation(D) &&
"Should visit only after verifying that loc is in range");
- if (ContainsLocation(D->getDeclaratorInfo()))
- return ResolveInDeclarator(D, 0, D->getDeclaratorInfo());
+ if (ContainsLocation(D->getTypeSourceInfo()))
+ return ResolveInDeclarator(D, 0, D->getTypeSourceInfo());
// First, search through the parameters of the function.
for (FunctionDecl::param_iterator
@@ -296,8 +296,8 @@ ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) {
ASTLocation DeclLocResolver::VisitDeclaratorDecl(DeclaratorDecl *D) {
assert(ContainsLocation(D) &&
"Should visit only after verifying that loc is in range");
- if (ContainsLocation(D->getDeclaratorInfo()))
- return ResolveInDeclarator(D, /*Stmt=*/0, D->getDeclaratorInfo());
+ if (ContainsLocation(D->getTypeSourceInfo()))
+ return ResolveInDeclarator(D, /*Stmt=*/0, D->getTypeSourceInfo());
return ASTLocation(D);
}
@@ -306,8 +306,8 @@ ASTLocation DeclLocResolver::VisitTypedefDecl(TypedefDecl *D) {
assert(ContainsLocation(D) &&
"Should visit only after verifying that loc is in range");
- if (ContainsLocation(D->getTypeDeclaratorInfo()))
- return ResolveInDeclarator(D, /*Stmt=*/0, D->getTypeDeclaratorInfo());
+ if (ContainsLocation(D->getTypeSourceInfo()))
+ return ResolveInDeclarator(D, /*Stmt=*/0, D->getTypeSourceInfo());
return ASTLocation(D);
}
@@ -321,8 +321,8 @@ ASTLocation DeclLocResolver::VisitVarDecl(VarDecl *D) {
if (Init && ContainsLocation(Init))
return StmtLocResolver(Ctx, Loc, D).Visit(Init);
- if (ContainsLocation(D->getDeclaratorInfo()))
- return ResolveInDeclarator(D, 0, D->getDeclaratorInfo());
+ if (ContainsLocation(D->getTypeSourceInfo()))
+ return ResolveInDeclarator(D, 0, D->getTypeSourceInfo());
return ASTLocation(D);
}
@@ -491,12 +491,12 @@ ASTLocation TypeLocResolver::VisitTypeLoc(TypeLoc TL) {
}
ASTLocation LocResolverBase::ResolveInDeclarator(Decl *D, Stmt *Stm,
- DeclaratorInfo *DInfo) {
- assert(ContainsLocation(DInfo) &&
+ TypeSourceInfo *TInfo) {
+ assert(ContainsLocation(TInfo) &&
"Should visit only after verifying that loc is in range");
(void)TypeLocResolver(Ctx, Loc, D);
- for (TypeLoc TL = DInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc())
+ for (TypeLoc TL = TInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc())
if (ContainsLocation(TL))
return TypeLocResolver(Ctx, Loc, D).Visit(TL);
@@ -504,11 +504,11 @@ ASTLocation LocResolverBase::ResolveInDeclarator(Decl *D, Stmt *Stm,
return ASTLocation(D, Stm);
}
-LocResolverBase::RangePos LocResolverBase::CheckRange(DeclaratorInfo *DInfo) {
- if (!DInfo)
+LocResolverBase::RangePos LocResolverBase::CheckRange(TypeSourceInfo *TInfo) {
+ if (!TInfo)
return BeforeLoc; // Keep looking.
- for (TypeLoc TL = DInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc())
+ for (TypeLoc TL = TInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc())
if (ContainsLocation(TL))
return ContainsLoc;
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 52a7a04..a91e404 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -33,7 +33,7 @@
#include <cctype>
using namespace clang;
-static void InitCharacterInfo();
+static void InitCharacterInfo(LangOptions);
//===----------------------------------------------------------------------===//
// Token Class Implementation
@@ -59,7 +59,7 @@ tok::ObjCKeywordKind Token::getObjCKeywordID() const {
void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
const char *BufEnd) {
- InitCharacterInfo();
+ InitCharacterInfo(Features);
BufferStart = BufStart;
BufferPtr = BufPtr;
@@ -70,7 +70,7 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
" to simplify lexing!");
Is_PragmaLexer = false;
- IsEofCodeCompletion = false;
+ IsInConflictMarker = false;
// Start of the file is a start of line.
IsAtStartOfLine = true;
@@ -105,10 +105,6 @@ Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP)
// Default to keeping comments if the preprocessor wants them.
SetCommentRetentionState(PP.getCommentRetentionState());
-
- // If the input file is truncated, the EOF is a code-completion token.
- if (PP.getSourceManager().isTruncatedFile(FID))
- IsEofCodeCompletion = true;
}
/// Lexer constructor - Create a new raw lexer object. This object is only
@@ -258,7 +254,7 @@ enum {
// Statically initialize CharInfo table based on ASCII character set
// Reference: FreeBSD 7.2 /usr/share/misc/ascii
-static const unsigned char CharInfo[256] =
+static unsigned char CharInfo[256] =
{
// 0 NUL 1 SOH 2 STX 3 ETX
// 4 EOT 5 ENQ 6 ACK 7 BEL
@@ -326,7 +322,7 @@ static const unsigned char CharInfo[256] =
0 , 0 , 0 , 0
};
-static void InitCharacterInfo() {
+static void InitCharacterInfo(LangOptions Features) {
static bool isInited = false;
if (isInited) return;
// check the statically-initialized CharInfo table
@@ -344,6 +340,11 @@ static void InitCharacterInfo() {
}
for (unsigned i = '0'; i <= '9'; ++i)
assert(CHAR_NUMBER == CharInfo[i]);
+
+ if (Features.Microsoft)
+ // Hack to treat DOS & CP/M EOF (^Z) as horizontal whitespace.
+ CharInfo[26/*sub*/] = CHAR_HORZ_WS;
+
isInited = true;
}
@@ -1326,24 +1327,16 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
// Otherwise, check if we are code-completing, then issue diagnostics for
// unterminated #if and missing newline.
- if (IsEofCodeCompletion) {
- bool isIntendedFile = true;
- if (PP && FileLoc.isFileID()) {
- SourceManager &SM = PP->getSourceManager();
- isIntendedFile = SM.isTruncatedFile(SM.getFileID(FileLoc));
- }
+ if (PP && PP->isCodeCompletionFile(FileLoc)) {
+ // We're at the end of the file, but we've been asked to consider the
+ // end of the file to be a code-completion token. Return the
+ // code-completion token.
+ Result.startToken();
+ FormTokenWithChars(Result, CurPtr, tok::code_completion);
- if (isIntendedFile) {
- // We're at the end of the file, but we've been asked to consider the
- // end of the file to be a code-completion token. Return the
- // code-completion token.
- Result.startToken();
- FormTokenWithChars(Result, CurPtr, tok::code_completion);
-
- // Only do the eof -> code_completion translation once.
- IsEofCodeCompletion = false;
- return true;
- }
+ // Only do the eof -> code_completion translation once.
+ PP->SetCodeCompletionPoint(0, 0, 0);
+ return true;
}
// If we are in a #if directive, emit an error.
@@ -1398,6 +1391,105 @@ unsigned Lexer::isNextPPTokenLParen() {
return Tok.is(tok::l_paren);
}
+/// FindConflictEnd - Find the end of a version control conflict marker.
+static const char *FindConflictEnd(const char *CurPtr, const char *BufferEnd) {
+ llvm::StringRef RestOfBuffer(CurPtr+7, BufferEnd-CurPtr-7);
+ size_t Pos = RestOfBuffer.find(">>>>>>>");
+ while (Pos != llvm::StringRef::npos) {
+ // Must occur at start of line.
+ if (RestOfBuffer[Pos-1] != '\r' &&
+ RestOfBuffer[Pos-1] != '\n') {
+ RestOfBuffer = RestOfBuffer.substr(Pos+7);
+ continue;
+ }
+ return RestOfBuffer.data()+Pos;
+ }
+ return 0;
+}
+
+/// IsStartOfConflictMarker - If the specified pointer is the start of a version
+/// control conflict marker like '<<<<<<<', recognize it as such, emit an error
+/// and recover nicely. This returns true if it is a conflict marker and false
+/// if not.
+bool Lexer::IsStartOfConflictMarker(const char *CurPtr) {
+ // Only a conflict marker if it starts at the beginning of a line.
+ if (CurPtr != BufferStart &&
+ CurPtr[-1] != '\n' && CurPtr[-1] != '\r')
+ return false;
+
+ // Check to see if we have <<<<<<<.
+ if (BufferEnd-CurPtr < 8 ||
+ llvm::StringRef(CurPtr, 7) != "<<<<<<<")
+ return false;
+
+ // If we have a situation where we don't care about conflict markers, ignore
+ // it.
+ if (IsInConflictMarker || isLexingRawMode())
+ return false;
+
+ // Check to see if there is a >>>>>>> somewhere in the buffer at the start of
+ // a line to terminate this conflict marker.
+ if (FindConflictEnd(CurPtr+7, BufferEnd)) {
+ // We found a match. We are really in a conflict marker.
+ // Diagnose this, and ignore to the end of line.
+ Diag(CurPtr, diag::err_conflict_marker);
+ IsInConflictMarker = true;
+
+ // Skip ahead to the end of line. We know this exists because the
+ // end-of-conflict marker starts with \r or \n.
+ while (*CurPtr != '\r' && *CurPtr != '\n') {
+ assert(CurPtr != BufferEnd && "Didn't find end of line");
+ ++CurPtr;
+ }
+ BufferPtr = CurPtr;
+ return true;
+ }
+
+ // No end of conflict marker found.
+ return false;
+}
+
+
+/// HandleEndOfConflictMarker - If this is a '=======' or '|||||||' or '>>>>>>>'
+/// marker, then it is the end of a conflict marker. Handle it by ignoring up
+/// until the end of the line. This returns true if it is a conflict marker and
+/// false if not.
+bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) {
+ // Only a conflict marker if it starts at the beginning of a line.
+ if (CurPtr != BufferStart &&
+ CurPtr[-1] != '\n' && CurPtr[-1] != '\r')
+ return false;
+
+ // If we have a situation where we don't care about conflict markers, ignore
+ // it.
+ if (!IsInConflictMarker || isLexingRawMode())
+ return false;
+
+ // Check to see if we have the marker (7 characters in a row).
+ for (unsigned i = 1; i != 7; ++i)
+ if (CurPtr[i] != CurPtr[0])
+ return false;
+
+ // If we do have it, search for the end of the conflict marker. This could
+ // fail if it got skipped with a '#if 0' or something. Note that CurPtr might
+ // be the end of conflict marker.
+ if (const char *End = FindConflictEnd(CurPtr, BufferEnd)) {
+ CurPtr = End;
+
+ // Skip ahead to the end of line.
+ while (CurPtr != BufferEnd && *CurPtr != '\r' && *CurPtr != '\n')
+ ++CurPtr;
+
+ BufferPtr = CurPtr;
+
+ // No longer in the conflict marker.
+ IsInConflictMarker = false;
+ return true;
+ }
+
+ return false;
+}
+
/// LexTokenInternal - This implements a simple C family lexer. It is an
/// extremely performance critical piece of code. This assumes that the buffer
@@ -1764,14 +1856,20 @@ LexNextToken:
Char = getCharAndSize(CurPtr, SizeTmp);
if (ParsingFilename) {
return LexAngledStringLiteral(Result, CurPtr);
- } else if (Char == '<' &&
- getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '=') {
- Kind = tok::lesslessequal;
- CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
- SizeTmp2, Result);
} else if (Char == '<') {
- CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
- Kind = tok::lessless;
+ char After = getCharAndSize(CurPtr+SizeTmp, SizeTmp2);
+ if (After == '=') {
+ Kind = tok::lesslessequal;
+ CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result);
+ } else if (After == '<' && IsStartOfConflictMarker(CurPtr-1)) {
+ // If this is actually a '<<<<<<<' version control conflict marker,
+ // recognize it as such and recover nicely.
+ goto LexNextToken;
+ } else {
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Kind = tok::lessless;
+ }
} else if (Char == '=') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::lessequal;
@@ -1790,14 +1888,20 @@ LexNextToken:
if (Char == '=') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::greaterequal;
- } else if (Char == '>' &&
- getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '=') {
- CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
- SizeTmp2, Result);
- Kind = tok::greatergreaterequal;
} else if (Char == '>') {
- CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
- Kind = tok::greatergreater;
+ char After = getCharAndSize(CurPtr+SizeTmp, SizeTmp2);
+ if (After == '=') {
+ CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result);
+ Kind = tok::greatergreaterequal;
+ } else if (After == '>' && HandleEndOfConflictMarker(CurPtr-1)) {
+ // If this is '>>>>>>>' and we're in a conflict marker, ignore it.
+ goto LexNextToken;
+ } else {
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Kind = tok::greatergreater;
+ }
+
} else {
Kind = tok::greater;
}
@@ -1817,6 +1921,9 @@ LexNextToken:
Kind = tok::pipeequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else if (Char == '|') {
+ // If this is '|||||||' and we're in a conflict marker, ignore it.
+ if (CurPtr[1] == '|' && HandleEndOfConflictMarker(CurPtr-1))
+ goto LexNextToken;
Kind = tok::pipepipe;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
@@ -1841,6 +1948,10 @@ LexNextToken:
case '=':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '=') {
+ // If this is '=======' and we're in a conflict marker, ignore it.
+ if (CurPtr[1] == '=' && HandleEndOfConflictMarker(CurPtr-1))
+ goto LexNextToken;
+
Kind = tok::equalequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index c14d7c4..376cce8 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -20,7 +20,8 @@ using namespace clang;
/// MacroArgs ctor function - This destroys the vector passed in.
MacroArgs *MacroArgs::create(const MacroInfo *MI,
const Token *UnexpArgTokens,
- unsigned NumToks, bool VarargsElided) {
+ unsigned NumToks, bool VarargsElided,
+ Preprocessor &PP) {
assert(MI->isFunctionLike() &&
"Can't have args for an object-like macro!");
@@ -40,13 +41,26 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI,
/// destroy - Destroy and deallocate the memory for this object.
///
-void MacroArgs::destroy() {
+void MacroArgs::destroy(Preprocessor &PP) {
// Run the dtor to deallocate the vectors.
this->~MacroArgs();
// Release the memory for the object.
free(this);
}
+/// deallocate - This should only be called by the Preprocessor when managing
+/// its freelist.
+MacroArgs *MacroArgs::deallocate() {
+ MacroArgs *Next = ArgCache;
+
+ // Run the dtor to deallocate the vectors.
+ this->~MacroArgs();
+ // Release the memory for the object.
+ free(this);
+
+ return Next;
+}
+
/// getArgLength - Given a pointer to an expanded or unexpanded argument,
/// return the number of tokens, not counting the EOF, that make up the
diff --git a/lib/Lex/MacroArgs.h b/lib/Lex/MacroArgs.h
index 8dee5b3..fa040c7 100644
--- a/lib/Lex/MacroArgs.h
+++ b/lib/Lex/MacroArgs.h
@@ -30,6 +30,13 @@ class MacroArgs {
/// concatenated together, with 'EOF' markers at the end of each argument.
unsigned NumUnexpArgTokens;
+ /// VarargsElided - True if this is a C99 style varargs macro invocation and
+ /// there was no argument specified for the "..." argument. If the argument
+ /// was specified (even empty) or this isn't a C99 style varargs function, or
+ /// if in strict mode and the C99 varargs macro had only a ... argument, this
+ /// is false.
+ bool VarargsElided;
+
/// PreExpArgTokens - Pre-expanded tokens for arguments that need them. Empty
/// if not yet computed. This includes the EOF marker at the end of the
/// stream.
@@ -39,26 +46,24 @@ class MacroArgs {
/// stringified form of an argument has not yet been computed, this is empty.
std::vector<Token> StringifiedArgs;
- /// VarargsElided - True if this is a C99 style varargs macro invocation and
- /// there was no argument specified for the "..." argument. If the argument
- /// was specified (even empty) or this isn't a C99 style varargs function, or
- /// if in strict mode and the C99 varargs macro had only a ... argument, this
- /// is false.
- bool VarargsElided;
-
+ /// ArgCache - This is a linked list of MacroArgs objects that the
+ /// Preprocessor owns which we use to avoid thrashing malloc/free.
+ MacroArgs *ArgCache;
+
MacroArgs(unsigned NumToks, bool varargsElided)
- : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided) {}
+ : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided), ArgCache(0) {}
~MacroArgs() {}
public:
/// MacroArgs ctor function - Create a new MacroArgs object with the specified
/// macro and argument info.
static MacroArgs *create(const MacroInfo *MI,
const Token *UnexpArgTokens,
- unsigned NumArgTokens, bool VarargsElided);
+ unsigned NumArgTokens, bool VarargsElided,
+ Preprocessor &PP);
/// destroy - Destroy and deallocate the memory for this object.
///
- void destroy();
+ void destroy(Preprocessor &PP);
/// ArgNeedsPreexpansion - If we can prove that the argument won't be affected
/// by pre-expansion, return false. Otherwise, conservatively return true.
@@ -102,6 +107,11 @@ public:
///
static Token StringifyArgument(const Token *ArgToks,
Preprocessor &PP, bool Charify = false);
+
+
+ /// deallocate - This should only be called by the Preprocessor when managing
+ /// its freelist.
+ MacroArgs *deallocate();
};
} // end namespace clang
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 9caca33..f5c60eb 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -481,11 +481,11 @@ void Preprocessor::HandleDirective(Token &Result) {
CurPPLexer->ParsingPreprocessorDirective = true;
++NumDirectives;
-
+
// We are about to read a token. For the multiple-include optimization FA to
// work, we have to remember if we had read any tokens *before* this
// pp-directive.
- bool ReadAnyTokensBeforeDirective = CurPPLexer->MIOpt.getHasReadAnyTokensVal();
+ bool ReadAnyTokensBeforeDirective =CurPPLexer->MIOpt.getHasReadAnyTokensVal();
// Save the '#' token in case we need to return it later.
Token SavedHash = Result;
@@ -1112,9 +1112,10 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
}
// Finally, if all is good, enter the new file!
- if (EnterSourceFile(FID, CurDir))
+ std::string ErrorStr;
+ if (EnterSourceFile(FID, CurDir, ErrorStr))
Diag(FilenameTok, diag::err_pp_error_opening_file)
- << std::string(SourceMgr.getFileEntryForID(FID)->getName());
+ << std::string(SourceMgr.getFileEntryForID(FID)->getName()) << ErrorStr;
}
/// HandleIncludeNextDirective - Implements #include_next.
@@ -1548,8 +1549,9 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
// Should we include the stuff contained by this directive?
if (!MI == isIfndef) {
// Yes, remember that we are inside a conditional, then lex the next token.
- CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(), /*wasskip*/false,
- /*foundnonskip*/true, /*foundelse*/false);
+ CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(),
+ /*wasskip*/false, /*foundnonskip*/true,
+ /*foundelse*/false);
} else {
// No, skip the contents of this block and return the first token after it.
SkipExcludedConditionalBlock(DirectiveTok.getLocation(),
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index b54dfe0..2a6b2a7 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -72,8 +72,8 @@ struct DefinedTracker {
};
/// EvaluateDefined - Process a 'defined(sym)' expression.
-static bool EvaluateDefined(PPValue &Result, Token &PeekTok,
- DefinedTracker &DT, bool ValueLive, Preprocessor &PP) {
+static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
+ bool ValueLive, Preprocessor &PP) {
IdentifierInfo *II;
Result.setBegin(PeekTok.getLocation());
@@ -142,22 +142,21 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// 'defined' or if it is a macro. Note that we check here because many
// keywords are pp-identifiers, so we can't check the kind.
if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) {
- if (II->isStr("defined")) {
- // Handle "defined X" and "defined(X)".
+ // Handle "defined X" and "defined(X)".
+ if (II->isStr("defined"))
return(EvaluateDefined(Result, PeekTok, DT, ValueLive, PP));
- } else {
- // If this identifier isn't 'defined' or one of the special
- // preprocessor keywords and it wasn't macro expanded, it turns
- // into a simple 0, unless it is the C++ keyword "true", in which case it
- // turns into "1".
- if (ValueLive)
- PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II;
- Result.Val = II->getTokenID() == tok::kw_true;
- Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
- Result.setRange(PeekTok.getLocation());
- PP.LexNonComment(PeekTok);
- return false;
- }
+
+ // If this identifier isn't 'defined' or one of the special
+ // preprocessor keywords and it wasn't macro expanded, it turns
+ // into a simple 0, unless it is the C++ keyword "true", in which case it
+ // turns into "1".
+ if (ValueLive)
+ PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II;
+ Result.Val = II->getTokenID() == tok::kw_true;
+ Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
+ Result.setRange(PeekTok.getLocation());
+ PP.LexNonComment(PeekTok);
+ return false;
}
switch (PeekTok.getKind()) {
@@ -677,6 +676,15 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
/// to "!defined(X)" return X in IfNDefMacro.
bool Preprocessor::
EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
+ // Save the current state of 'DisableMacroExpansion' and reset it to false. If
+ // 'DisableMacroExpansion' is true, then we must be in a macro argument list
+ // in which case a directive is undefined behavior. We want macros to be able
+ // to recursively expand in order to get more gcc-list behavior, so we force
+ // DisableMacroExpansion to false and restore it when we're done parsing the
+ // expression.
+ bool DisableMacroExpansionAtStartOfDirective = DisableMacroExpansion;
+ DisableMacroExpansion = false;
+
// Peek ahead one token.
Token Tok;
Lex(Tok);
@@ -690,6 +698,9 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
// Parse error, skip the rest of the macro line.
if (Tok.isNot(tok::eom))
DiscardUntilEndOfDirective();
+
+ // Restore 'DisableMacroExpansion'.
+ DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
return false;
}
@@ -702,6 +713,8 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
if (DT.State == DefinedTracker::NotDefinedMacro)
IfNDefMacro = DT.TheMacro;
+ // Restore 'DisableMacroExpansion'.
+ DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
return ResVal.Val != 0;
}
@@ -712,6 +725,9 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
// Parse error, skip the rest of the macro line.
if (Tok.isNot(tok::eom))
DiscardUntilEndOfDirective();
+
+ // Restore 'DisableMacroExpansion'.
+ DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
return false;
}
@@ -722,6 +738,8 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
DiscardUntilEndOfDirective();
}
+ // Restore 'DisableMacroExpansion'.
+ DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
return ResVal.Val != 0;
}
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index 8a61d7b..ce1b19c 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -64,7 +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) {
+bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
+ std::string &ErrorStr) {
assert(CurTokenLexer == 0 && "Cannot #include a file inside a macro!");
++NumEnteredSourceFiles;
@@ -79,8 +80,9 @@ bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir) {
}
// Get the MemoryBuffer for this FID, if it fails, we fail.
- const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID);
- if (InputFile == 0)
+ const llvm::MemoryBuffer *InputFile =
+ getSourceManager().getBuffer(FID, &ErrorStr);
+ if (!ErrorStr.empty())
return true;
EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir);
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 699b701..dfb14ff 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -204,7 +204,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// expansion stack, only to take it right back off.
if (MI->getNumTokens() == 0) {
// No need for arg info.
- if (Args) Args->destroy();
+ if (Args) Args->destroy(*this);
// Ignore this macro use, just return the next token in the current
// buffer.
@@ -232,7 +232,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// "#define VAL 42".
// No need for arg info.
- if (Args) Args->destroy();
+ if (Args) Args->destroy(*this);
// Propagate the isAtStartOfLine/hasLeadingSpace markers of the macro
// identifier to the expanded token.
@@ -446,7 +446,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
}
return MacroArgs::create(MI, ArgTokens.data(), ArgTokens.size(),
- isVarargsElided);
+ isVarargsElided, *this);
}
/// ComputeDATE_TIME - Compute the current time, enter it into the specified
@@ -486,6 +486,12 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
case 6:
if (II->isStr("blocks")) return LangOpts.Blocks;
return false;
+ case 8:
+ if (II->isStr("cxx_rtti")) return LangOpts.RTTI;
+ return false;
+ case 14:
+ if (II->isStr("cxx_exceptions")) return LangOpts.Exceptions;
+ return false;
case 19:
if (II->isStr("objc_nonfragile_abi")) return LangOpts.ObjCNonFragileABI;
return false;
@@ -667,7 +673,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// __BASE_FILE__ is a GNU extension that returns the top of the presumed
// #include stack instead of the current file.
if (II == Ident__BASE_FILE__) {
- Diag(Tok, diag::ext_pp_base_file);
SourceLocation NextLoc = PLoc.getIncludeLoc();
while (NextLoc.isValid()) {
PLoc = SourceMgr.getPresumedLoc(NextLoc);
@@ -697,8 +702,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Tok.getLocation(),
Tok.getLength()));
} else if (II == Ident__INCLUDE_LEVEL__) {
- Diag(Tok, diag::ext_pp_include_level);
-
// Compute the presumed include depth of this token. This can be affected
// by GNU line markers.
unsigned Depth = 0;
@@ -715,7 +718,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
} else if (II == Ident__TIMESTAMP__) {
// MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be
// of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime.
- Diag(Tok, diag::ext_pp_timestamp);
// Get the file that we are lexing out of. If we're currently lexing from
// a macro, dig into the include stack.
@@ -725,7 +727,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
if (TheLexer)
CurFile = SourceMgr.getFileEntryForID(TheLexer->getFileID());
- // If this file is older than the file it depends on, emit a diagnostic.
const char *Result;
if (CurFile) {
time_t TT = CurFile->getModificationTime();
@@ -741,8 +742,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Tok.setKind(tok::string_literal);
CreateString(TmpBuffer, Len+1, Tok, Tok.getLocation());
} else if (II == Ident__COUNTER__) {
- Diag(Tok, diag::ext_pp_counter);
-
// __COUNTER__ expands to a simple numeric value.
sprintf(TmpBuffer, "%u", CounterValue++);
Tok.setKind(tok::numeric_constant);
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 0669094..d4e441b 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -26,6 +26,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
+#include "MacroArgs.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Pragma.h"
@@ -50,7 +51,8 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
bool OwnsHeaders)
: Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()),
SourceMgr(SM), HeaderInfo(Headers), Identifiers(opts, IILookup),
- BuiltinInfo(Target), CurPPLexer(0), CurDirLookup(0), Callbacks(0) {
+ BuiltinInfo(Target), CodeCompletionFile(0), CurPPLexer(0), CurDirLookup(0),
+ Callbacks(0), MacroArgCache(0) {
ScratchBuf = new ScratchBuffer(SourceMgr);
CounterValue = 0; // __COUNTER__ starts at 0.
OwnsHeaderSearch = OwnsHeaders;
@@ -101,7 +103,7 @@ Preprocessor::~Preprocessor() {
Macros.begin(), E = Macros.end(); I != E; ++I) {
// We don't need to free the MacroInfo objects directly. These
// will be released when the BumpPtrAllocator 'BP' object gets
- // destroyed. We still need to run the dstor, however, to free
+ // destroyed. We still need to run the dtor, however, to free
// memory alocated by MacroInfo.
I->second->Destroy(BP);
I->first->setHasMacroDefinition(false);
@@ -110,6 +112,10 @@ Preprocessor::~Preprocessor() {
// Free any cached macro expanders.
for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i)
delete TokenLexerCache[i];
+
+ // Free any cached MacroArgs.
+ for (MacroArgs *ArgList = MacroArgCache; ArgList; )
+ ArgList = ArgList->deallocate();
// Release pragma information.
delete PragmaHandlers;
@@ -188,6 +194,57 @@ void Preprocessor::PrintStats() {
<< NumFastTokenPaste << " on the fast path.\n";
}
+bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
+ unsigned TruncateAtLine,
+ unsigned TruncateAtColumn) {
+ using llvm::MemoryBuffer;
+
+ CodeCompletionFile = File;
+
+ // Okay to clear out the code-completion point by passing NULL.
+ if (!CodeCompletionFile)
+ return false;
+
+ // Load the actual file's contents.
+ const MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
+ if (!Buffer)
+ return true;
+
+ // Find the byte position of the truncation point.
+ const char *Position = Buffer->getBufferStart();
+ for (unsigned Line = 1; Line < TruncateAtLine; ++Line) {
+ for (; *Position; ++Position) {
+ if (*Position != '\r' && *Position != '\n')
+ continue;
+
+ // Eat \r\n or \n\r as a single line.
+ if ((Position[1] == '\r' || Position[1] == '\n') &&
+ Position[0] != Position[1])
+ ++Position;
+ ++Position;
+ break;
+ }
+ }
+
+ Position += TruncateAtColumn - 1;
+
+ // Truncate the buffer.
+ if (Position < Buffer->getBufferEnd()) {
+ MemoryBuffer *TruncatedBuffer
+ = MemoryBuffer::getMemBufferCopy(Buffer->getBufferStart(), Position,
+ Buffer->getBufferIdentifier());
+ SourceMgr.overrideFileContents(File, TruncatedBuffer);
+ }
+
+ return false;
+}
+
+bool Preprocessor::isCodeCompletionFile(SourceLocation FileLoc) const {
+ return CodeCompletionFile && FileLoc.isFileID() &&
+ SourceMgr.getFileEntryForID(SourceMgr.getFileID(FileLoc))
+ == CodeCompletionFile;
+}
+
//===----------------------------------------------------------------------===//
// Token Spelling
//===----------------------------------------------------------------------===//
@@ -380,7 +437,9 @@ void Preprocessor::EnterMainSourceFile() {
FileID MainFileID = SourceMgr.getMainFileID();
// Enter the main file source buffer.
- EnterSourceFile(MainFileID, 0);
+ std::string ErrorStr;
+ bool Res = EnterSourceFile(MainFileID, 0, ErrorStr);
+ assert(!Res && "Entering main file should not fail!");
// Tell the header info that the main file was entered. If the file is later
// #imported, it won't be re-entered.
@@ -406,7 +465,8 @@ void Preprocessor::EnterMainSourceFile() {
assert(!FID.isInvalid() && "Could not create FileID for predefines?");
// Start parsing the predefines.
- EnterSourceFile(FID, 0);
+ Res = EnterSourceFile(FID, 0, ErrorStr);
+ assert(!Res && "Entering predefines should not fail!");
}
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index f006f5a..a40bb62 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -92,7 +92,7 @@ void TokenLexer::destroy() {
}
// TokenLexer owns its formal arguments.
- if (ActualArgs) ActualArgs->destroy();
+ if (ActualArgs) ActualArgs->destroy(PP);
}
/// Expand the arguments of a function-like macro so that we can quickly
@@ -321,13 +321,12 @@ void TokenLexer::Lex(Token &Tok) {
// If this token is followed by a token paste (##) operator, paste the tokens!
if (!isAtEnd() && Tokens[CurToken].is(tok::hashhash)) {
- if (PasteTokens(Tok)) {
- // When handling the microsoft /##/ extension, the final token is
- // returned by PasteTokens, not the pasted token.
+ // When handling the microsoft /##/ extension, the final token is
+ // returned by PasteTokens, not the pasted token.
+ if (PasteTokens(Tok))
return;
- } else {
- TokenIsFromPaste = true;
- }
+
+ TokenIsFromPaste = true;
}
// The token's current location indicate where the token was lexed from. We
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index f00f33f..4cd8fe8 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -137,7 +137,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) {
case DeclSpec::SCS_private_extern: return "__private_extern__";
case DeclSpec::SCS_mutable: return "mutable";
}
- llvm::llvm_unreachable("Unknown typespec!");
+ llvm_unreachable("Unknown typespec!");
}
const char *DeclSpec::getSpecifierName(TSW W) {
@@ -147,7 +147,7 @@ const char *DeclSpec::getSpecifierName(TSW W) {
case TSW_long: return "long";
case TSW_longlong: return "long long";
}
- llvm::llvm_unreachable("Unknown typespec!");
+ llvm_unreachable("Unknown typespec!");
}
const char *DeclSpec::getSpecifierName(TSC C) {
@@ -156,7 +156,7 @@ const char *DeclSpec::getSpecifierName(TSC C) {
case TSC_imaginary: return "imaginary";
case TSC_complex: return "complex";
}
- llvm::llvm_unreachable("Unknown typespec!");
+ llvm_unreachable("Unknown typespec!");
}
@@ -166,7 +166,7 @@ const char *DeclSpec::getSpecifierName(TSS S) {
case TSS_signed: return "signed";
case TSS_unsigned: return "unsigned";
}
- llvm::llvm_unreachable("Unknown typespec!");
+ llvm_unreachable("Unknown typespec!");
}
const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
@@ -195,7 +195,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
case DeclSpec::TST_decltype: return "(decltype)";
case DeclSpec::TST_error: return "(error)";
}
- llvm::llvm_unreachable("Unknown typespec!");
+ llvm_unreachable("Unknown typespec!");
}
const char *DeclSpec::getSpecifierName(TQ T) {
@@ -205,7 +205,7 @@ const char *DeclSpec::getSpecifierName(TQ T) {
case DeclSpec::TQ_restrict: return "restrict";
case DeclSpec::TQ_volatile: return "volatile";
}
- llvm::llvm_unreachable("Unknown typespec!");
+ llvm_unreachable("Unknown typespec!");
}
bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc,
diff --git a/lib/Parse/ExtensionRAIIObject.h b/lib/Parse/ExtensionRAIIObject.h
deleted file mode 100644
index cc7c8e2..0000000
--- a/lib/Parse/ExtensionRAIIObject.h
+++ /dev/null
@@ -1,40 +0,0 @@
-//===--- ExtensionRAIIObject.h - Use RAII for __extension__ -----*- 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 and implements the ExtensionRAIIObject class.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_PARSE_EXTENSION_RAII_OBJECT_H
-#define LLVM_CLANG_PARSE_EXTENSION_RAII_OBJECT_H
-
-#include "clang/Parse/ParseDiagnostic.h"
-
-namespace clang {
-
- /// ExtensionRAIIObject - This saves the state of extension warnings when
- /// constructed and disables them. When destructed, it restores them back to
- /// the way they used to be. This is used to handle __extension__ in the
- /// parser.
- class ExtensionRAIIObject {
- void operator=(const ExtensionRAIIObject &); // DO NOT IMPLEMENT
- ExtensionRAIIObject(const ExtensionRAIIObject&); // DO NOT IMPLEMENT
- Diagnostic &Diags;
- public:
- ExtensionRAIIObject(Diagnostic &diags) : Diags(diags) {
- Diags.IncrementAllExtensionsSilenced();
- }
-
- ~ExtensionRAIIObject() {
- Diags.DecrementAllExtensionsSilenced();
- }
- };
-}
-
-#endif
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index aa0b89b..8b207fa 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -45,6 +45,7 @@ Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope,
// Defined out-of-line here because of dependency on AttributeList
Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope,
AccessSpecifier AS,
+ bool HasUsingKeyword,
SourceLocation UsingLoc,
const CXXScopeSpec &SS,
UnqualifiedId &Name,
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index b13dc73..5dd78f7 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1,4 +1,3 @@
-
//===--- ParseDecl.cpp - Declaration Parsing ------------------------------===//
//
// The LLVM Compiler Infrastructure
@@ -16,7 +15,7 @@
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Scope.h"
#include "clang/Parse/Template.h"
-#include "ExtensionRAIIObject.h"
+#include "RAIIObjectsForParser.h"
#include "llvm/ADT/SmallSet.h"
using namespace clang;
@@ -825,14 +824,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (DS.hasTypeSpecifier())
goto DoneWithDeclSpec;
+ CXXScopeSpec SS;
+ SS.setScopeRep(Tok.getAnnotationValue());
+ SS.setRange(Tok.getAnnotationRange());
+
// We are looking for a qualified typename.
Token Next = NextToken();
if (Next.is(tok::annot_template_id) &&
static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
->Kind == TNK_Type_template) {
// We have a qualified template-id, e.g., N::A<int>
- CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true);
+ DS.getTypeSpecScope() = SS;
+ ConsumeToken(); // The C++ scope.
assert(Tok.is(tok::annot_template_id) &&
"ParseOptionalCXXScopeSpecifier not working");
AnnotateTemplateIdTokenAsType(&SS);
@@ -840,8 +843,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
}
if (Next.is(tok::annot_typename)) {
- // FIXME: is this scope-specifier getting dropped?
- ConsumeToken(); // the scope-specifier
+ DS.getTypeSpecScope() = SS;
+ ConsumeToken(); // The C++ scope.
if (Tok.getAnnotationValue())
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc,
PrevSpec, DiagID,
@@ -855,10 +858,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (Next.isNot(tok::identifier))
goto DoneWithDeclSpec;
- CXXScopeSpec SS;
- SS.setScopeRep(Tok.getAnnotationValue());
- SS.setRange(Tok.getAnnotationRange());
-
// If the next token is the name of the class type that the C++ scope
// denotes, followed by a '(', then this is a constructor declaration.
// We're done with the decl-specifiers.
@@ -880,6 +879,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
goto DoneWithDeclSpec;
}
+ DS.getTypeSpecScope() = SS;
ConsumeToken(); // The C++ scope.
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
@@ -1545,8 +1545,11 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) {
/// struct-declarator: declarator
/// struct-declarator: declarator[opt] ':' constant-expression
- if (Tok.isNot(tok::colon))
+ if (Tok.isNot(tok::colon)) {
+ // Don't parse FOO:BAR as if it were a typo for FOO::BAR.
+ ColonProtectionRAIIObject X(*this);
ParseDeclarator(DeclaratorInfo.D);
+ }
if (Tok.is(tok::colon)) {
ConsumeToken();
@@ -1616,7 +1619,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
// Check for extraneous top-level semicolon.
if (Tok.is(tok::semi)) {
Diag(Tok, diag::ext_extra_struct_semi)
- << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation()));
+ << CodeModificationHint::CreateRemoval(Tok.getLocation());
ConsumeToken();
continue;
}
@@ -1841,7 +1844,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) {
!(getLang().C99 || getLang().CPlusPlus0x))
Diag(CommaLoc, diag::ext_enumerator_list_comma)
<< getLang().CPlusPlus
- << CodeModificationHint::CreateRemoval((SourceRange(CommaLoc)));
+ << CodeModificationHint::CreateRemoval(CommaLoc);
}
// Eat the }.
@@ -2333,9 +2336,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0,
true);
if (afterCXXScope) {
- // Change the declaration context for name lookup, until this function
- // is exited (and the declarator has been parsed).
- DeclScopeObj.EnterDeclaratorScope();
+ 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) ||
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 505a4d8..d4d19a0 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -17,7 +17,7 @@
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "clang/Parse/Template.h"
-#include "ExtensionRAIIObject.h"
+#include "RAIIObjectsForParser.h"
using namespace clang;
/// ParseNamespace - We know that the current token is a namespace keyword. This
@@ -161,7 +161,8 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
/// 'extern' string-literal '{' declaration-seq[opt] '}'
/// 'extern' string-literal declaration
///
-Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) {
+Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS,
+ unsigned Context) {
assert(Tok.is(tok::string_literal) && "Not a string literal!");
llvm::SmallVector<char, 8> LangBuffer;
// LangBuffer is guaranteed to be big enough.
@@ -185,7 +186,7 @@ Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) {
}
if (Tok.isNot(tok::l_brace)) {
- ParseDeclarationOrFunctionDefinition(Attr.AttrList);
+ ParseDeclarationOrFunctionDefinition(DS, Attr.AttrList);
return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec,
SourceLocation());
}
@@ -356,7 +357,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
AttrList ? "attributes list" : "using declaration",
tok::semi);
- return Actions.ActOnUsingDeclaration(CurScope, AS, UsingLoc, SS, Name,
+ return Actions.ActOnUsingDeclaration(CurScope, AS, true, UsingLoc, SS, Name,
AttrList, IsTypeName, TypenameLoc);
}
@@ -599,11 +600,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
}
// Parse the (optional) nested-name-specifier.
- CXXScopeSpec SS;
- if (getLang().CPlusPlus &&
- ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true))
- if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
- Diag(Tok, diag::err_expected_ident);
+ CXXScopeSpec &SS = DS.getTypeSpecScope();
+ if (getLang().CPlusPlus) {
+ // "FOO : BAR" is not a potential typo for "FOO::BAR".
+ ColonProtectionRAIIObject X(*this);
+
+ if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true))
+ if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
+ Diag(Tok, diag::err_expected_ident);
+ }
TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
@@ -954,7 +959,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) {
if (IsVirtual) {
// Complain about duplicate 'virtual'
Diag(VirtualLoc, diag::err_dup_virtual)
- << CodeModificationHint::CreateRemoval(SourceRange(VirtualLoc));
+ << CodeModificationHint::CreateRemoval(VirtualLoc);
}
IsVirtual = true;
@@ -1060,6 +1065,46 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo,
///
void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
const ParsedTemplateInfo &TemplateInfo) {
+ // Access declarations.
+ if (!TemplateInfo.Kind &&
+ (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) &&
+ TryAnnotateCXXScopeToken() &&
+ Tok.is(tok::annot_cxxscope)) {
+ bool isAccessDecl = false;
+ if (NextToken().is(tok::identifier))
+ isAccessDecl = GetLookAheadToken(2).is(tok::semi);
+ else
+ isAccessDecl = NextToken().is(tok::kw_operator);
+
+ if (isAccessDecl) {
+ // Collect the scope specifier token we annotated earlier.
+ CXXScopeSpec SS;
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType*/ 0, false);
+
+ // Try to parse an unqualified-id.
+ UnqualifiedId Name;
+ if (ParseUnqualifiedId(SS, false, true, true, /*ObjectType*/ 0, Name)) {
+ SkipUntil(tok::semi);
+ return;
+ }
+
+ // TODO: recover from mistakenly-qualified operator declarations.
+ if (ExpectAndConsume(tok::semi,
+ diag::err_expected_semi_after,
+ "access declaration",
+ tok::semi))
+ return;
+
+ Actions.ActOnUsingDeclaration(CurScope, AS,
+ false, SourceLocation(),
+ SS, Name,
+ /* AttrList */ 0,
+ /* IsTypeName */ false,
+ SourceLocation());
+ return;
+ }
+ }
+
// static_assert-declaration
if (Tok.is(tok::kw_static_assert)) {
// FIXME: Check for templates
@@ -1085,11 +1130,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return ParseCXXClassMemberDeclaration(AS, TemplateInfo);
}
+ // Don't parse FOO:BAR as if it were a typo for FOO::BAR.
+ ColonProtectionRAIIObject X(*this);
+
CXX0XAttributeList AttrList;
// Optional C++0x attribute-specifier
- if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
AttrList = ParseCXX0XAttributes();
- }
if (Tok.is(tok::kw_using)) {
// FIXME: Check for template aliases
@@ -1133,6 +1180,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext);
if (Tok.isNot(tok::colon)) {
+ // Don't parse FOO:BAR as if it were a typo for FOO::BAR.
+ ColonProtectionRAIIObject X(*this);
+
// Parse the first declarator.
ParseDeclarator(DeclaratorInfo);
// Error parsing the declarator?
@@ -1349,7 +1399,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// Check for extraneous top-level semicolon.
if (Tok.is(tok::semi)) {
Diag(Tok, diag::ext_extra_struct_semi)
- << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation()));
+ << CodeModificationHint::CreateRemoval(Tok.getLocation());
ConsumeToken();
continue;
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index f780cf1..bdbc67f 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -23,7 +23,7 @@
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "clang/Basic/PrettyStackTrace.h"
-#include "ExtensionRAIIObject.h"
+#include "RAIIObjectsForParser.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -317,6 +317,9 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
OwningExprResult TernaryMiddle(Actions, true);
if (NextTokPrec == prec::Conditional) {
if (Tok.isNot(tok::colon)) {
+ // Don't parse FOO:BAR as if it were a typo for FOO::BAR.
+ ColonProtectionRAIIObject X(*this);
+
// Handle this production specially:
// logical-OR-expression '?' expression ':' conditional-expression
// In particular, the RHS of the '?' is 'expression', not
@@ -562,9 +565,15 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
TypeTy *CastTy;
SourceLocation LParenLoc = Tok.getLocation();
SourceLocation RParenLoc;
- Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
- TypeOfCast, CastTy, RParenLoc);
- if (Res.isInvalid()) return move(Res);
+
+ {
+ // The inside of the parens don't need to be a colon protected scope.
+ ColonProtectionRAIIObject X(*this, false);
+
+ Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
+ TypeOfCast, CastTy, RParenLoc);
+ if (Res.isInvalid()) return move(Res);
+ }
switch (ParenExprType) {
case SimpleExpr: break; // Nothing else to do.
@@ -826,6 +835,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___is_empty:
case tok::kw___is_polymorphic:
case tok::kw___is_abstract:
+ case tok::kw___is_literal:
case tok::kw___has_trivial_constructor:
case tok::kw___has_trivial_copy:
case tok::kw___has_trivial_assign:
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 52003e6..abd26d7 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -214,11 +214,29 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// namespace-name '::'
// nested-name-specifier identifier '::'
Token Next = NextToken();
+
+ // If we get foo:bar, this is almost certainly a typo for foo::bar. Recover
+ // and emit a fixit hint for it.
+ if (Next.is(tok::colon) && !ColonIsSacred &&
+ Actions.IsInvalidUnlessNestedName(CurScope, SS, II, ObjectType,
+ EnteringContext) &&
+ // If the token after the colon isn't an identifier, it's still an
+ // error, but they probably meant something else strange so don't
+ // recover like this.
+ PP.LookAhead(1).is(tok::identifier)) {
+ Diag(Next, diag::err_unexected_colon_in_nested_name_spec)
+ << CodeModificationHint::CreateReplacement(Next.getLocation(), "::");
+
+ // Recover as if the user wrote '::'.
+ Next.setKind(tok::coloncolon);
+ }
+
if (Next.is(tok::coloncolon)) {
// We have an identifier followed by a '::'. Lookup this name
// as the name in a nested-name-specifier.
SourceLocation IdLoc = ConsumeToken();
- assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
+ assert((Tok.is(tok::coloncolon) || Tok.is(tok::colon)) &&
+ "NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
if (!HasScopeSpecifier) {
@@ -1459,6 +1477,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) {
case tok::kw___is_pod: return UTT_IsPOD;
case tok::kw___is_polymorphic: return UTT_IsPolymorphic;
case tok::kw___is_union: return UTT_IsUnion;
+ case tok::kw___is_literal: return UTT_IsLiteral;
}
}
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 295625a..2c53847 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -30,6 +30,11 @@ using namespace clang;
Parser::DeclPtrTy Parser::ParseObjCAtDirectives() {
SourceLocation AtLoc = ConsumeToken(); // the "@"
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, false);
+ ConsumeToken();
+ }
+
switch (Tok.getObjCKeywordID()) {
case tok::objc_class:
return ParseObjCAtClassDeclaration(AtLoc);
@@ -228,6 +233,63 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
return ClsType;
}
+/// The Objective-C property callback. This should be defined where
+/// it's used, but instead it's been lifted to here to support VS2005.
+struct Parser::ObjCPropertyCallback : FieldCallback {
+ Parser &P;
+ DeclPtrTy IDecl;
+ llvm::SmallVectorImpl<DeclPtrTy> &Props;
+ ObjCDeclSpec &OCDS;
+ SourceLocation AtLoc;
+ tok::ObjCKeywordKind MethodImplKind;
+
+ ObjCPropertyCallback(Parser &P, DeclPtrTy IDecl,
+ llvm::SmallVectorImpl<DeclPtrTy> &Props,
+ ObjCDeclSpec &OCDS, SourceLocation AtLoc,
+ tok::ObjCKeywordKind MethodImplKind) :
+ P(P), IDecl(IDecl), Props(Props), OCDS(OCDS), AtLoc(AtLoc),
+ MethodImplKind(MethodImplKind) {
+ }
+
+ DeclPtrTy invoke(FieldDeclarator &FD) {
+ if (FD.D.getIdentifier() == 0) {
+ P.Diag(AtLoc, diag::err_objc_property_requires_field_name)
+ << FD.D.getSourceRange();
+ return DeclPtrTy();
+ }
+ if (FD.BitfieldSize) {
+ P.Diag(AtLoc, diag::err_objc_property_bitfield)
+ << FD.D.getSourceRange();
+ return DeclPtrTy();
+ }
+
+ // Install the property declarator into interfaceDecl.
+ IdentifierInfo *SelName =
+ OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
+
+ Selector GetterSel =
+ P.PP.getSelectorTable().getNullarySelector(SelName);
+ IdentifierInfo *SetterName = OCDS.getSetterName();
+ Selector SetterSel;
+ if (SetterName)
+ SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName);
+ else
+ SetterSel = SelectorTable::constructSetterName(P.PP.getIdentifierTable(),
+ P.PP.getSelectorTable(),
+ FD.D.getIdentifier());
+ bool isOverridingProperty = false;
+ DeclPtrTy Property =
+ P.Actions.ActOnProperty(P.CurScope, AtLoc, FD, OCDS,
+ GetterSel, SetterSel, IDecl,
+ &isOverridingProperty,
+ MethodImplKind);
+ if (!isOverridingProperty)
+ Props.push_back(Property);
+
+ return Property;
+ }
+};
+
/// objc-interface-decl-list:
/// empty
/// objc-interface-decl-list objc-property-decl [OBJC2]
@@ -288,6 +350,12 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
// Otherwise, we have an @ directive, eat the @.
SourceLocation AtLoc = ConsumeToken(); // the "@"
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true);
+ ConsumeToken();
+ break;
+ }
+
tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
if (DirectiveKind == tok::objc_end) { // @end -> terminate list
@@ -329,61 +397,8 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
ParseObjCPropertyAttribute(OCDS, interfaceDecl,
allMethods.data(), allMethods.size());
- struct ObjCPropertyCallback : FieldCallback {
- Parser &P;
- DeclPtrTy IDecl;
- llvm::SmallVectorImpl<DeclPtrTy> &Props;
- ObjCDeclSpec &OCDS;
- SourceLocation AtLoc;
- tok::ObjCKeywordKind MethodImplKind;
-
- ObjCPropertyCallback(Parser &P, DeclPtrTy IDecl,
- llvm::SmallVectorImpl<DeclPtrTy> &Props,
- ObjCDeclSpec &OCDS, SourceLocation AtLoc,
- tok::ObjCKeywordKind MethodImplKind) :
- P(P), IDecl(IDecl), Props(Props), OCDS(OCDS), AtLoc(AtLoc),
- MethodImplKind(MethodImplKind) {
- }
-
- DeclPtrTy invoke(FieldDeclarator &FD) {
- if (FD.D.getIdentifier() == 0) {
- P.Diag(AtLoc, diag::err_objc_property_requires_field_name)
- << FD.D.getSourceRange();
- return DeclPtrTy();
- }
- if (FD.BitfieldSize) {
- P.Diag(AtLoc, diag::err_objc_property_bitfield)
- << FD.D.getSourceRange();
- return DeclPtrTy();
- }
-
- // Install the property declarator into interfaceDecl.
- IdentifierInfo *SelName =
- OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
-
- Selector GetterSel =
- P.PP.getSelectorTable().getNullarySelector(SelName);
- IdentifierInfo *SetterName = OCDS.getSetterName();
- Selector SetterSel;
- if (SetterName)
- SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName);
- else
- SetterSel = SelectorTable::constructSetterName(P.PP.getIdentifierTable(),
- P.PP.getSelectorTable(),
- FD.D.getIdentifier());
- bool isOverridingProperty = false;
- DeclPtrTy Property =
- P.Actions.ActOnProperty(P.CurScope, AtLoc, FD, OCDS,
- GetterSel, SetterSel, IDecl,
- &isOverridingProperty,
- MethodImplKind);
- if (!isOverridingProperty)
- Props.push_back(Property);
-
- return Property;
- }
- } Callback(*this, interfaceDecl, allProperties,
- OCDS, AtLoc, MethodImplKind);
+ ObjCPropertyCallback Callback(*this, interfaceDecl, allProperties,
+ OCDS, AtLoc, MethodImplKind);
// Parse all the comma separated declarators.
DeclSpec DS;
@@ -397,7 +412,10 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
// We break out of the big loop in two cases: when we see @end or when we see
// EOF. In the former case, eat the @end. In the later case, emit an error.
- if (Tok.isObjCAtKeyword(tok::objc_end))
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true);
+ ConsumeToken();
+ } else if (Tok.isObjCAtKeyword(tok::objc_end))
ConsumeToken(); // the "end" identifier
else
Diag(Tok, diag::err_objc_missing_end);
@@ -938,7 +956,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
// Check for extraneous top-level semicolon.
if (Tok.is(tok::semi)) {
Diag(Tok, diag::ext_extra_struct_semi)
- << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation()));
+ << CodeModificationHint::CreateRemoval(Tok.getLocation());
ConsumeToken();
continue;
}
@@ -1503,7 +1521,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() {
if (Tok.is(tok::semi)) {
if (ObjCImpDecl) {
Diag(Tok, diag::warn_semicolon_before_method_body)
- << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation()));
+ << CodeModificationHint::CreateRemoval(Tok.getLocation());
}
ConsumeToken();
}
@@ -1545,12 +1563,21 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() {
}
Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
- if (Tok.isObjCAtKeyword(tok::objc_try)) {
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteObjCAtStatement(CurScope);
+ ConsumeToken();
+ return StmtError();
+ }
+
+ if (Tok.isObjCAtKeyword(tok::objc_try))
return ParseObjCTryStmt(AtLoc);
- } else if (Tok.isObjCAtKeyword(tok::objc_throw))
+
+ if (Tok.isObjCAtKeyword(tok::objc_throw))
return ParseObjCThrowStmt(AtLoc);
- else if (Tok.isObjCAtKeyword(tok::objc_synchronized))
+
+ if (Tok.isObjCAtKeyword(tok::objc_synchronized))
return ParseObjCSynchronizedStmt(AtLoc);
+
OwningExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
if (Res.isInvalid()) {
// If the expression is invalid, skip ahead to the next semicolon. Not
@@ -1559,6 +1586,7 @@ Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
SkipUntil(tok::semi);
return StmtError();
}
+
// Otherwise, eat the semicolon.
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
return Actions.ActOnExprStmt(Actions.FullExpr(Res));
@@ -1566,6 +1594,11 @@ Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
switch (Tok.getKind()) {
+ case tok::code_completion:
+ Actions.CodeCompleteObjCAtExpression(CurScope);
+ ConsumeToken();
+ return ExprError();
+
case tok::string_literal: // primary-expression: string-literal
case tok::wide_string_literal:
return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index c87010e..a2ac646 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
-#include "ExtensionRAIIObject.h"
+#include "RAIIObjectsForParser.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "clang/Basic/Diagnostic.h"
@@ -279,6 +279,11 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) {
ConsumeToken();
}
+ /// We don't want to treat 'case x : y' as a potential typo for 'case x::y'.
+ /// Disable this form of error recovery while we're parsing the case
+ /// expression.
+ ColonProtectionRAIIObject ColonProtection(*this);
+
OwningExprResult LHS(ParseConstantExpression());
if (LHS.isInvalid()) {
SkipUntil(tok::colon);
@@ -298,6 +303,8 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) {
return StmtError();
}
}
+
+ ColonProtection.restore();
if (Tok.isNot(tok::colon)) {
Diag(Tok, diag::err_expected_colon_after) << "'case'";
@@ -1162,7 +1169,20 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() {
Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) &&
Tok.isNot(tok::eof));
}
- return Actions.ActOnNullStmt(Tok.getLocation());
+ llvm::SmallVector<std::string, 4> Names;
+ Token t;
+ t.setKind(tok::string_literal);
+ t.setLiteralData("\"FIXME: not done\"");
+ t.clearFlag(Token::NeedsCleaning);
+ t.setLength(17);
+ OwningExprResult AsmString(Actions.ActOnStringLiteral(&t, 1));
+ ExprVector Constraints(Actions);
+ ExprVector Exprs(Actions);
+ ExprVector Clobbers(Actions);
+ return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, Names.data(),
+ move_arg(Constraints), move_arg(Exprs),
+ move(AsmString), move_arg(Clobbers),
+ Tok.getLocation());
}
/// ParseAsmStatement - Parse a GNU extended asm statement.
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 0dbf37c..cc28541 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -16,6 +16,7 @@
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "clang/Parse/Template.h"
+#include "RAIIObjectsForParser.h"
using namespace clang;
/// \brief Parse a template declaration, explicit instantiation, or
@@ -522,7 +523,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
if (Default.isInvalid()) {
Diag(Tok.getLocation(),
diag::err_default_template_template_parameter_not_template);
- static tok::TokenKind EndToks[] = {
+ static const tok::TokenKind EndToks[] = {
tok::comma, tok::greater, tok::greatergreater
};
SkipUntil(EndToks, 3, true, true);
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index e321564..a864e7c 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -17,7 +17,7 @@
#include "clang/Parse/Scope.h"
#include "clang/Parse/Template.h"
#include "llvm/Support/raw_ostream.h"
-#include "ExtensionRAIIObject.h"
+#include "RAIIObjectsForParser.h"
#include "ParsePragma.h"
using namespace clang;
@@ -36,7 +36,8 @@ public:
Parser::Parser(Preprocessor &pp, Action &actions)
: CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
- GreaterThanIsOperator(true), TemplateParameterDepth(0) {
+ GreaterThanIsOperator(true), ColonIsSacred(false),
+ TemplateParameterDepth(0) {
Tok.setKind(tok::eof);
CurScope = 0;
NumCachedScopes = 0;
@@ -405,7 +406,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr)
case tok::semi:
if (!getLang().CPlusPlus0x)
Diag(Tok, diag::ext_top_level_semi)
- << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation()));
+ << CodeModificationHint::CreateRemoval(Tok.getLocation());
ConsumeToken();
// TODO: Invoke action for top-level semicolon.
@@ -507,12 +508,13 @@ bool Parser::isDeclarationAfterDeclarator() {
/// \brief Determine whether the current token, if it occurs after a
/// declarator, indicates the start of a function definition.
bool Parser::isStartOfFunctionDefinition() {
- return Tok.is(tok::l_brace) || // int X() {}
- (!getLang().CPlusPlus &&
- isDeclarationSpecifier()) || // int X(f) int f; {}
- (getLang().CPlusPlus &&
- (Tok.is(tok::colon) || // X() : Base() {} (used for ctors)
- Tok.is(tok::kw_try))); // X() try { ... }
+ if (Tok.is(tok::l_brace)) // int X() {}
+ return true;
+
+ if (!getLang().CPlusPlus)
+ return isDeclarationSpecifier(); // int X(f) int f; {}
+ return Tok.is(tok::colon) || // X() : Base() {} (used for ctors)
+ Tok.is(tok::kw_try); // X() try { ... }
}
/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or
@@ -532,10 +534,10 @@ bool Parser::isStartOfFunctionDefinition() {
/// [OMP] threadprivate-directive [TODO]
///
Parser::DeclGroupPtrTy
-Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr,
+Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS,
+ AttributeList *Attr,
AccessSpecifier AS) {
// Parse the common declaration-specifiers piece.
- ParsingDeclSpec DS(*this);
if (Attr)
DS.AddAttributes(Attr);
@@ -584,13 +586,20 @@ Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr,
DS.getStorageClassSpec() == DeclSpec::SCS_extern &&
DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) {
DS.abort();
- DeclPtrTy TheDecl = ParseLinkage(Declarator::FileContext);
+ DeclPtrTy TheDecl = ParseLinkage(DS, Declarator::FileContext);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
return ParseDeclGroup(DS, Declarator::FileContext, true);
}
+Parser::DeclGroupPtrTy
+Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr,
+ AccessSpecifier AS) {
+ ParsingDeclSpec DS(*this);
+ return ParseDeclarationOrFunctionDefinition(DS, Attr, AS);
+}
+
/// ParseFunctionDefinition - We parsed and verified that the specified
/// Declarator is well formed. If this is a K&R-style function, read the
/// parameters declaration-list, then start the compound-statement.
@@ -1029,7 +1038,9 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
CXXScopeSpec SS;
if (!ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext))
- return Tok.is(tok::annot_template_id);
+ // If the token left behind is not an identifier, we either had an error or
+ // successfully turned it into an annotation token.
+ return Tok.isNot(tok::identifier);
// Push the current token back into the token stream (or revert it if it is
// cached) and use an annotation scope token for current token.
diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h
new file mode 100644
index 0000000..06bbbc2
--- /dev/null
+++ b/lib/Parse/RAIIObjectsForParser.h
@@ -0,0 +1,85 @@
+//===--- RAIIObjectsForParser.h - RAII helpers for the parser ---*- 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 and implements the some simple RAII objects that are used
+// by the parser to manage bits in recursion.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H
+#define LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H
+
+#include "clang/Parse/ParseDiagnostic.h"
+
+namespace clang {
+ // TODO: move ParsingDeclRAIIObject here.
+ // TODO: move ParsingClassDefinition here.
+ // TODO: move TentativeParsingAction here.
+
+
+ /// ExtensionRAIIObject - This saves the state of extension warnings when
+ /// constructed and disables them. When destructed, it restores them back to
+ /// the way they used to be. This is used to handle __extension__ in the
+ /// parser.
+ class ExtensionRAIIObject {
+ void operator=(const ExtensionRAIIObject &); // DO NOT IMPLEMENT
+ ExtensionRAIIObject(const ExtensionRAIIObject&); // DO NOT IMPLEMENT
+ Diagnostic &Diags;
+ public:
+ ExtensionRAIIObject(Diagnostic &diags) : Diags(diags) {
+ Diags.IncrementAllExtensionsSilenced();
+ }
+
+ ~ExtensionRAIIObject() {
+ Diags.DecrementAllExtensionsSilenced();
+ }
+ };
+
+ /// ColonProtectionRAIIObject - This sets the Parser::ColonIsSacred bool and
+ /// restores it when destroyed. This says that "foo:" should not be
+ /// considered a possible typo for "foo::" for error recovery purposes.
+ class ColonProtectionRAIIObject {
+ Parser &P;
+ bool OldVal;
+ public:
+ ColonProtectionRAIIObject(Parser &p, bool Value = true)
+ : P(p), OldVal(P.ColonIsSacred) {
+ P.ColonIsSacred = Value;
+ }
+
+ /// restore - This can be used to restore the state early, before the dtor
+ /// is run.
+ void restore() {
+ P.ColonIsSacred = OldVal;
+ }
+
+ ~ColonProtectionRAIIObject() {
+ restore();
+ }
+ };
+
+ /// \brief RAII object that makes '>' behave either as an operator
+ /// or as the closing angle bracket for a template argument list.
+ class GreaterThanIsOperatorScope {
+ bool &GreaterThanIsOperator;
+ bool OldGreaterThanIsOperator;
+ public:
+ GreaterThanIsOperatorScope(bool &GTIO, bool Val)
+ : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) {
+ GreaterThanIsOperator = Val;
+ }
+
+ ~GreaterThanIsOperatorScope() {
+ GreaterThanIsOperator = OldGreaterThanIsOperator;
+ }
+ };
+
+} // end namespace clang
+
+#endif
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index 91b16d3..d8ed894 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -46,7 +46,7 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text)
}
case CK_Optional:
- llvm::llvm_unreachable("Optional strings cannot be created from text");
+ llvm_unreachable("Optional strings cannot be created from text");
break;
case CK_LeftParen:
diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h
index e2134a2..78f79ea 100644
--- a/lib/Sema/Lookup.h
+++ b/lib/Sema/Lookup.h
@@ -26,13 +26,6 @@ namespace clang {
/// a single declaration, a set of overloaded functions, or an
/// ambiguity. Use the getKind() method to determine which of these
/// results occurred for a given lookup.
-///
-/// Any non-ambiguous lookup can be converted into a single
-/// (possibly NULL) @c NamedDecl* via the getAsSingleDecl() method.
-/// This permits the common-case usage in C and Objective-C where
-/// name lookup will always return a single declaration. Use of
-/// this is largely deprecated; callers should handle the possibility
-/// of multiple declarations.
class LookupResult {
public:
enum LookupResultKind {
@@ -40,12 +33,11 @@ public:
NotFound = 0,
/// @brief Name lookup found a single declaration that met the
- /// criteria. getAsDecl will return this declaration.
+ /// criteria. getFoundDecl() will return this declaration.
Found,
/// @brief Name lookup found a set of overloaded functions that
- /// met the criteria. getAsDecl will turn this set of overloaded
- /// functions into an OverloadedFunctionDecl.
+ /// met the criteria.
FoundOverloaded,
/// @brief Name lookup found an unresolvable value declaration
@@ -282,13 +274,6 @@ public:
}
}
- /// \brief Fetch this as an unambiguous single declaration
- /// (possibly an overloaded one).
- ///
- /// This is deprecated; users should be written to handle
- /// ambiguous and overloaded lookups.
- NamedDecl *getAsSingleDecl(ASTContext &Context) const;
-
template <class DeclClass>
DeclClass *getAsSingle() const {
if (getResultKind() != Found) return 0;
diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp
index 7c7df4b..898b3c2 100644
--- a/lib/Sema/ParseAST.cpp
+++ b/lib/Sema/ParseAST.cpp
@@ -75,7 +75,7 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
while ((ADecl = P.RetrievePendingObjCImpDecl()))
Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>());
- // process any TopLevelDecls generated by #pragma weak
+ // Process any TopLevelDecls generated by #pragma weak.
for (llvm::SmallVector<Decl*,2>::iterator
I = S.WeakTopLevelDecls().begin(),
E = S.WeakTopLevelDecls().end(); I != E; ++I)
@@ -83,6 +83,13 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
Consumer->HandleTranslationUnit(Ctx);
+ if (ExternalSemaSource *ESS =
+ dyn_cast_or_null<ExternalSemaSource>(Ctx.getExternalSource()))
+ ESS->ForgetSema();
+
+ if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumer))
+ SC->ForgetSema();
+
if (PrintStats) {
fprintf(stderr, "\nSTATISTICS:\n");
P.getActions().PrintStats();
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index f0812bf..ef61474 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -278,20 +278,20 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
PushDeclContext(S, Context.getTranslationUnitDecl());
if (PP.getTargetInfo().getPointerWidth(0) >= 64) {
- DeclaratorInfo *DInfo;
+ TypeSourceInfo *TInfo;
// Install [u]int128_t for 64-bit targets.
- DInfo = Context.getTrivialDeclaratorInfo(Context.Int128Ty);
+ TInfo = Context.getTrivialTypeSourceInfo(Context.Int128Ty);
PushOnScopeChains(TypedefDecl::Create(Context, CurContext,
SourceLocation(),
&Context.Idents.get("__int128_t"),
- DInfo), TUScope);
+ TInfo), TUScope);
- DInfo = Context.getTrivialDeclaratorInfo(Context.UnsignedInt128Ty);
+ TInfo = Context.getTrivialTypeSourceInfo(Context.UnsignedInt128Ty);
PushOnScopeChains(TypedefDecl::Create(Context, CurContext,
SourceLocation(),
&Context.Idents.get("__uint128_t"),
- DInfo), TUScope);
+ TInfo), TUScope);
}
@@ -301,7 +301,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
if (Context.getObjCSelType().isNull()) {
// Create the built-in typedef for 'SEL'.
QualType SelT = Context.getPointerType(Context.ObjCBuiltinSelTy);
- DeclaratorInfo *SelInfo = Context.getTrivialDeclaratorInfo(SelT);
+ TypeSourceInfo *SelInfo = Context.getTrivialTypeSourceInfo(SelT);
TypedefDecl *SelTypedef
= TypedefDecl::Create(Context, CurContext, SourceLocation(),
&Context.Idents.get("SEL"), SelInfo);
@@ -322,7 +322,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
// Create the built-in typedef for 'id'.
if (Context.getObjCIdType().isNull()) {
QualType IdT = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy);
- DeclaratorInfo *IdInfo = Context.getTrivialDeclaratorInfo(IdT);
+ TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(IdT);
TypedefDecl *IdTypedef
= TypedefDecl::Create(Context, CurContext, SourceLocation(),
&Context.Idents.get("id"), IdInfo);
@@ -334,7 +334,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
if (Context.getObjCClassType().isNull()) {
QualType ClassType
= Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy);
- DeclaratorInfo *ClassInfo = Context.getTrivialDeclaratorInfo(ClassType);
+ TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(ClassType);
TypedefDecl *ClassTypedef
= TypedefDecl::Create(Context, CurContext, SourceLocation(),
&Context.Idents.get("Class"), ClassInfo);
@@ -728,18 +728,27 @@ void Sema::DeleteStmt(StmtTy *S) {
/// translation unit when EOF is reached and all but the top-level scope is
/// popped.
void Sema::ActOnEndOfTranslationUnit() {
- // C++: Perform implicit template instantiations.
- //
- // FIXME: When we perform these implicit instantiations, we do not carefully
- // keep track of the point of instantiation (C++ [temp.point]). This means
- // that name lookup that occurs within the template instantiation will
- // always happen at the end of the translation unit, so it will find
- // some names that should not be found. Although this is common behavior
- // for C++ compilers, it is technically wrong. In the future, we either need
- // to be able to filter the results of name lookup or we need to perform
- // template instantiations earlier.
- PerformPendingImplicitInstantiations();
-
+
+ while (1) {
+ // C++: Perform implicit template instantiations.
+ //
+ // FIXME: When we perform these implicit instantiations, we do not carefully
+ // keep track of the point of instantiation (C++ [temp.point]). This means
+ // that name lookup that occurs within the template instantiation will
+ // always happen at the end of the translation unit, so it will find
+ // some names that should not be found. Although this is common behavior
+ // for C++ compilers, it is technically wrong. In the future, we either need
+ // to be able to filter the results of name lookup or we need to perform
+ // template instantiations earlier.
+ PerformPendingImplicitInstantiations();
+
+ /// If ProcessPendingClassesWithUnmarkedVirtualMembers ends up marking
+ /// any virtual member functions it might lead to more pending template
+ /// instantiations, which is why we need to loop here.
+ if (!ProcessPendingClassesWithUnmarkedVirtualMembers())
+ break;
+ }
+
// 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 b594ece..ada8aa1 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -32,6 +32,7 @@
#include "llvm/ADT/OwningPtr.h"
#include <deque>
#include <list>
+#include <map>
#include <string>
#include <vector>
@@ -94,7 +95,10 @@ namespace clang {
class CXXBasePaths;
class CXXTemporary;
class LookupResult;
-
+ class InitializedEntity;
+ class InitializationKind;
+ class InitializationSequence;
+
/// BlockSemaInfo - When a block is being parsed, this contains information
/// about the block. It is pointed to from Sema::CurBlock.
struct BlockSemaInfo {
@@ -131,7 +135,7 @@ struct BlockSemaInfo {
BlockSemaInfo *PrevBlockInfo;
};
-/// \brief Holds a QualType and a DeclaratorInfo* that came out of a declarator
+/// \brief Holds a QualType and a TypeSourceInfo* that came out of a declarator
/// parsing.
///
/// LocInfoType is a "transient" type, only needed for passing to/from Parser
@@ -144,17 +148,17 @@ class LocInfoType : public Type {
LocInfo = (1 << TypeClassBitSize) - 1
};
- DeclaratorInfo *DeclInfo;
+ TypeSourceInfo *DeclInfo;
- LocInfoType(QualType ty, DeclaratorInfo *DInfo)
- : Type((TypeClass)LocInfo, ty, ty->isDependentType()), DeclInfo(DInfo) {
+ LocInfoType(QualType ty, TypeSourceInfo *TInfo)
+ : Type((TypeClass)LocInfo, ty, ty->isDependentType()), DeclInfo(TInfo) {
assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?");
}
friend class Sema;
public:
QualType getType() const { return getCanonicalTypeInternal(); }
- DeclaratorInfo *getDeclaratorInfo() const { return DeclInfo; }
+ TypeSourceInfo *getTypeSourceInfo() const { return DeclInfo; }
virtual void getAsStringInternal(std::string &Str,
const PrintingPolicy &Policy) const;
@@ -335,6 +339,10 @@ public:
typedef std::vector<std::pair<SourceLocation, Decl *> >
PotentiallyReferencedDecls;
+ /// \brief A set of diagnostics that may be emitted.
+ typedef std::vector<std::pair<SourceLocation, PartialDiagnostic> >
+ PotentiallyEmittedDiagnostics;
+
/// \brief Data structure used to record current or nested
/// expression evaluation contexts.
struct ExpressionEvaluationContextRecord {
@@ -354,10 +362,14 @@ public:
/// evaluated.
PotentiallyReferencedDecls *PotentiallyReferenced;
+ /// \brief The set of diagnostics to emit should this potentially
+ /// potentially-evaluated context become evaluated.
+ PotentiallyEmittedDiagnostics *PotentiallyDiagnosed;
+
ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
unsigned NumTemporaries)
: Context(Context), NumTemporaries(NumTemporaries),
- PotentiallyReferenced(0) { }
+ PotentiallyReferenced(0), PotentiallyDiagnosed(0) { }
void addReferencedDecl(SourceLocation Loc, Decl *Decl) {
if (!PotentiallyReferenced)
@@ -365,9 +377,17 @@ public:
PotentiallyReferenced->push_back(std::make_pair(Loc, Decl));
}
+ void addDiagnostic(SourceLocation Loc, const PartialDiagnostic &PD) {
+ if (!PotentiallyDiagnosed)
+ PotentiallyDiagnosed = new PotentiallyEmittedDiagnostics;
+ PotentiallyDiagnosed->push_back(std::make_pair(Loc, PD));
+ }
+
void Destroy() {
delete PotentiallyReferenced;
+ delete PotentiallyDiagnosed;
PotentiallyReferenced = 0;
+ PotentiallyDiagnosed = 0;
}
};
@@ -517,14 +537,14 @@ public:
QualType BuildBlockPointerType(QualType T, unsigned Quals,
SourceLocation Loc, DeclarationName Entity);
QualType GetTypeForDeclarator(Declarator &D, Scope *S,
- DeclaratorInfo **DInfo = 0,
+ TypeSourceInfo **TInfo = 0,
TagDecl **OwnedDecl = 0);
- DeclaratorInfo *GetDeclaratorInfoForDeclarator(Declarator &D, QualType T);
- /// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo.
- QualType CreateLocInfoType(QualType T, DeclaratorInfo *DInfo);
+ TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T);
+ /// \brief Create a LocInfoType to hold the given QualType and TypeSourceInfo.
+ QualType CreateLocInfoType(QualType T, TypeSourceInfo *TInfo);
DeclarationName GetNameForDeclarator(Declarator &D);
DeclarationName GetNameFromUnqualifiedId(const UnqualifiedId &Name);
- static QualType GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo = 0);
+ static QualType GetTypeFromParser(TypeTy *Ty, TypeSourceInfo **TInfo = 0);
bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
bool CheckDistantExceptionSpec(QualType T);
bool CheckEquivalentExceptionSpec(
@@ -596,23 +616,24 @@ public:
SourceLocation NameLoc,
unsigned Diagnostic);
NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, DeclaratorInfo *DInfo,
+ QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous, bool &Redeclaration);
NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, DeclaratorInfo *DInfo,
+ QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous,
MultiTemplateParamsArg TemplateParamLists,
bool &Redeclaration);
void CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous,
bool &Redeclaration);
NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, DeclaratorInfo *DInfo,
+ QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous,
MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition,
bool &Redeclaration);
void AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
- void CheckFunctionDeclaration(FunctionDecl *NewFD, LookupResult &Previous,
+ void CheckFunctionDeclaration(Scope *S,
+ FunctionDecl *NewFD, LookupResult &Previous,
bool IsExplicitSpecialization,
bool &Redeclaration,
bool &OverloadableAttrRequired);
@@ -710,7 +731,7 @@ public:
AccessSpecifier AS);
FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T,
- DeclaratorInfo *DInfo,
+ TypeSourceInfo *TInfo,
RecordDecl *Record, SourceLocation Loc,
bool Mutable, Expr *BitfieldWidth,
SourceLocation TSSL,
@@ -811,19 +832,9 @@ public:
return NULL;
}
- /// OverloadingResult - Capture the result of performing overload
- /// resolution.
- enum OverloadingResult {
- 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.
- };
-
-
/// Subroutines of ActOnDeclarator().
TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
- DeclaratorInfo *DInfo);
+ TypeSourceInfo *TInfo);
void MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls);
bool MergeFunctionDecl(FunctionDecl *New, Decl *Old);
bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old);
@@ -831,8 +842,22 @@ public:
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old);
/// C++ Overloading.
- bool IsOverload(FunctionDecl *New, LookupResult &OldDecls,
- NamedDecl *&OldDecl);
+ enum OverloadKind {
+ /// This is a legitimate overload: the existing declarations are
+ /// functions or function templates with different signatures.
+ Ovl_Overload,
+
+ /// This is not an overload because the signature exactly matches
+ /// an existing declaration.
+ Ovl_Match,
+
+ /// This is not an overload because the lookup results contain a
+ /// non-function.
+ Ovl_NonFunction
+ };
+ OverloadKind CheckOverload(FunctionDecl *New,
+ const LookupResult &OldDecls,
+ NamedDecl *&OldDecl);
bool IsOverload(FunctionDecl *New, FunctionDecl *Old);
ImplicitConversionSequence
@@ -896,7 +921,8 @@ public:
const char *Flavor, bool Elidable = false);
ImplicitConversionSequence
- TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method);
+ TryObjectArgumentInitialization(QualType FromType, CXXMethodDecl *Method,
+ CXXRecordDecl *ActingContext);
bool PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method);
ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From);
@@ -922,18 +948,20 @@ public:
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
void AddMethodCandidate(NamedDecl *Decl,
- Expr *Object, Expr **Args, unsigned NumArgs,
+ QualType ObjectType, Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversion = false,
bool ForceRValue = false);
- void AddMethodCandidate(CXXMethodDecl *Method,
- Expr *Object, Expr **Args, unsigned NumArgs,
+ void AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
+ QualType ObjectType, Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool ForceRValue = false);
void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
+ CXXRecordDecl *ActingContext,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
- Expr *Object, Expr **Args, unsigned NumArgs,
+ QualType ObjectType,
+ Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool ForceRValue = false);
@@ -944,14 +972,17 @@ public:
bool SuppressUserConversions = false,
bool ForceRValue = false);
void AddConversionCandidate(CXXConversionDecl *Conversion,
+ CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet);
void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
+ CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet);
void AddSurrogateCandidate(CXXConversionDecl *Conversion,
+ CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
- Expr *Object, Expr **Args, unsigned NumArgs,
+ QualType ObjectTy, Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet);
void AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
SourceLocation OpLoc,
@@ -990,6 +1021,8 @@ public:
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
bool Complain);
Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
+ OwningExprResult FixOverloadedFunctionReference(OwningExprResult,
+ FunctionDecl *Fn);
void AddOverloadedCallCandidates(llvm::SmallVectorImpl<NamedDecl*>& Callees,
DeclarationName &UnqualifiedName,
@@ -1023,7 +1056,7 @@ public:
SourceLocation RLoc,
ExprArg Base,ExprArg Idx);
- ExprResult
+ OwningExprResult
BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
SourceLocation LParenLoc, Expr **Args,
unsigned NumArgs, SourceLocation *CommaLocs,
@@ -1107,6 +1140,10 @@ public:
/// namespace alias definition, ignoring non-namespace names (C++
/// [basic.lookup.udir]p1).
LookupNamespaceName,
+ /// Look up all declarations in a scope with the given name,
+ /// including resolved using declarations. This is appropriate
+ /// for checking redeclarations for a using declaration.
+ LookupUsingDeclName,
/// Look up an ordinary name that is going to be redeclared as a
/// name with linkage. This lookup ignores any declarations that
/// are outside of the current scope unless they have linkage. See
@@ -1115,9 +1152,7 @@ public:
/// Look up the name of an Objective-C protocol.
LookupObjCProtocolName,
/// Look up the name of an Objective-C implementation
- LookupObjCImplementationName,
- /// Look up the name of an Objective-C category implementation
- LookupObjCCategoryImplName
+ LookupObjCImplementationName
};
enum RedeclarationKind {
@@ -1138,9 +1173,9 @@ public:
case Sema::LookupTagName:
case Sema::LookupMemberName:
case Sema::LookupRedeclarationWithLinkage: // FIXME: check linkage, scoping
+ case Sema::LookupUsingDeclName:
case Sema::LookupObjCProtocolName:
case Sema::LookupObjCImplementationName:
- case Sema::LookupObjCCategoryImplName:
return D->isInIdentifierNamespace(IDNS);
case Sema::LookupOperatorName:
@@ -1160,7 +1195,7 @@ public:
}
/// \brief Look up a name, looking for a single declaration. Return
- /// null if no unambiguous results were found.
+ /// null if the results were absent, ambiguous, or overloaded.
///
/// It is preferable to use the elaborated form and explicitly handle
/// ambiguity and overloaded.
@@ -1176,7 +1211,6 @@ public:
bool EnteringContext = false);
ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II);
- ObjCCategoryImplDecl *LookupObjCCategoryImpl(IdentifierInfo *II);
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
QualType T1, QualType T2,
@@ -1379,7 +1413,7 @@ public:
StmtArg SynchBody);
VarDecl *BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
- DeclaratorInfo *DInfo,
+ TypeSourceInfo *TInfo,
IdentifierInfo *Name,
SourceLocation Loc,
SourceRange Range);
@@ -1438,10 +1472,10 @@ public:
OwningExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS,
DeclarationName Name,
SourceLocation NameLoc,
- bool CheckForImplicitMember,
+ bool isAddressOfOperand,
const TemplateArgumentListInfo *TemplateArgs);
- OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty,
+ OwningExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty,
SourceLocation Loc,
const CXXScopeSpec *SS = 0);
VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
@@ -1451,9 +1485,10 @@ public:
FieldDecl *Field,
Expr *BaseObjectExpr = 0,
SourceLocation OpLoc = SourceLocation());
- OwningExprResult BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs);
+ OwningExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool IsDefiniteInstance);
bool UseArgumentDependentLookup(const CXXScopeSpec &SS,
const LookupResult &R,
bool HasTrailingLParen);
@@ -1498,7 +1533,7 @@ public:
virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Op, ExprArg Input);
- OwningExprResult CreateSizeOfAlignOfExpr(DeclaratorInfo *T,
+ OwningExprResult CreateSizeOfAlignOfExpr(TypeSourceInfo *T,
SourceLocation OpLoc,
bool isSizeOf, SourceRange R);
OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
@@ -1525,6 +1560,7 @@ public:
SourceLocation RLoc);
OwningExprResult BuildMemberReferenceExpr(ExprArg Base,
+ QualType BaseType,
SourceLocation OpLoc,
bool IsArrow,
const CXXScopeSpec &SS,
@@ -1534,23 +1570,24 @@ public:
const TemplateArgumentListInfo *TemplateArgs);
OwningExprResult BuildMemberReferenceExpr(ExprArg Base,
+ QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
const CXXScopeSpec &SS,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs);
OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base,
- bool IsArrow, SourceLocation OpLoc,
+ bool &IsArrow, SourceLocation OpLoc,
const CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
DeclPtrTy ObjCImpDecl);
bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ const CXXScopeSpec &SS,
const LookupResult &R);
OwningExprResult ActOnDependentMemberExpr(ExprArg Base,
+ QualType BaseType,
bool IsArrow,
SourceLocation OpLoc,
const CXXScopeSpec &SS,
@@ -1592,6 +1629,11 @@ public:
MultiExprArg Args,
SourceLocation *CommaLocs,
SourceLocation RParenLoc);
+ OwningExprResult BuildResolvedCallExpr(Expr *Fn,
+ NamedDecl *NDecl,
+ SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RParenLoc);
virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
TypeTy *Ty, SourceLocation RParenLoc,
@@ -1715,6 +1757,21 @@ public:
SourceLocation IdentLoc,
IdentifierInfo *Ident);
+ void HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow);
+ bool CheckUsingShadowDecl(UsingDecl *UD, NamedDecl *Target,
+ const LookupResult &PreviousDecls);
+ UsingShadowDecl *BuildUsingShadowDecl(Scope *S, UsingDecl *UD,
+ NamedDecl *Target);
+
+ bool CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
+ bool isTypeName,
+ const CXXScopeSpec &SS,
+ SourceLocation NameLoc,
+ const LookupResult &Previous);
+ bool CheckUsingDeclQualifier(SourceLocation UsingLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation NameLoc);
+
NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
const CXXScopeSpec &SS,
@@ -1727,6 +1784,7 @@ public:
virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope,
AccessSpecifier AS,
+ bool HasUsingKeyword,
SourceLocation UsingLoc,
const CXXScopeSpec &SS,
UnqualifiedId &Name,
@@ -1809,7 +1867,8 @@ public:
/// getAssignOperatorMethod - Returns the default copy assignmment operator
/// for the class.
- CXXMethodDecl *getAssignOperatorMethod(ParmVarDecl *Decl,
+ CXXMethodDecl *getAssignOperatorMethod(SourceLocation CurrentLocation,
+ ParmVarDecl *Decl,
CXXRecordDecl *ClassDecl);
/// MaybeBindToTemporary - If the passed in expression has a record type with
@@ -1817,14 +1876,6 @@ public:
/// it simply returns the passed in expression.
OwningExprResult MaybeBindToTemporary(Expr *E);
- /// InitializationKind - Represents which kind of C++ initialization
- /// [dcl.init] a routine is to perform.
- enum InitializationKind {
- IK_Direct, ///< Direct initialization
- IK_Copy, ///< Copy initialization
- IK_Default ///< Default initialization
- };
-
CXXConstructorDecl *
TryInitializationByConstructor(QualType ClassType,
Expr **Args, unsigned NumArgs,
@@ -1982,7 +2033,8 @@ public:
IdentifierInfo &II,
QualType ObjectType,
NamedDecl *ScopeLookupResult,
- bool EnteringContext);
+ bool EnteringContext,
+ bool ErrorRecoveryLookup);
virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
const CXXScopeSpec &SS,
@@ -1992,6 +2044,12 @@ public:
TypeTy *ObjectType,
bool EnteringContext);
+ virtual bool IsInvalidUnlessNestedName(Scope *S,
+ const 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
@@ -2006,6 +2064,8 @@ public:
SourceRange TypeRange,
SourceLocation CCLoc);
+ virtual bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS);
+
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
/// scope or nested-name-specifier) is parsed, part of a declarator-id.
/// After this method is called, according to [C++ 3.4.3p3], names should be
@@ -2102,10 +2162,13 @@ public:
MemInitResult BuildMemberInitializer(FieldDecl *Member, Expr **Args,
unsigned NumArgs, SourceLocation IdLoc,
+ SourceLocation LParenLoc,
SourceLocation RParenLoc);
- MemInitResult BuildBaseInitializer(QualType BaseType, Expr **Args,
- unsigned NumArgs, SourceLocation IdLoc,
+ MemInitResult BuildBaseInitializer(QualType BaseType,
+ TypeSourceInfo *BaseTInfo,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation LParenLoc,
SourceLocation RParenLoc,
CXXRecordDecl *ClassDecl);
@@ -2119,12 +2182,34 @@ public:
/// as referenced.
void MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor);
+ /// ClassesWithUnmarkedVirtualMembers - Contains record decls whose virtual
+ /// members might need to be marked as referenced. This is either done when
+ /// the key function definition is emitted (this is handled by by
+ /// MaybeMarkVirtualMembersReferenced), or at the end of the translation unit
+ /// (done by ProcessPendingClassesWithUnmarkedVirtualMembers).
+ std::map<CXXRecordDecl *, SourceLocation> ClassesWithUnmarkedVirtualMembers;
+
+ /// MaybeMarkVirtualMembersReferenced - If the passed in method is the
+ /// 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, CXXRecordDecl *RD);
+
+ /// 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);
virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
MemInitTy **MemInits, unsigned NumMemInits);
+ void CheckCompletedCXXClass(CXXRecordDecl *Record);
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclPtrTy TagDecl,
SourceLocation LBrac,
@@ -2168,6 +2253,14 @@ public:
bool Virtual, AccessSpecifier Access,
QualType BaseType,
SourceLocation BaseLoc);
+
+ /// 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,
@@ -2208,6 +2301,7 @@ public:
bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
const CXXMethodDecl *Old);
+ bool CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange);
//===--------------------------------------------------------------------===//
// C++ Access Control
//
@@ -2452,7 +2546,7 @@ public:
TemplateArgumentListBuilder &Converted);
bool CheckTemplateArgument(TemplateTypeParmDecl *Param,
- DeclaratorInfo *Arg);
+ TypeSourceInfo *Arg);
bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
NamedDecl *&Entity);
bool CheckTemplateArgumentPointerToMember(Expr *Arg,
@@ -3084,7 +3178,7 @@ public:
void PerformPendingImplicitInstantiations();
- DeclaratorInfo *SubstType(DeclaratorInfo *T,
+ TypeSourceInfo *SubstType(TypeSourceInfo *T,
const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc, DeclarationName Entity);
@@ -3490,6 +3584,9 @@ public:
AssignConvertType CheckPointerTypesForAssignment(QualType lhsType,
QualType rhsType);
+ AssignConvertType CheckObjCPointerTypesForAssignment(QualType lhsType,
+ QualType rhsType);
+
// Helper function for CheckAssignmentConstraints involving two
// block pointer types.
AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType,
@@ -3556,6 +3653,9 @@ public:
Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
QualType FindCompositePointerType(Expr *&E1, Expr *&E2); // C++ 5.9
+ 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,
@@ -3718,6 +3818,10 @@ public:
virtual void CodeCompleteNamespaceAliasDecl(Scope *S);
virtual void CodeCompleteOperatorName(Scope *S);
+ virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl,
+ bool InInterface);
+ virtual void CodeCompleteObjCAtStatement(Scope *S);
+ virtual void CodeCompleteObjCAtExpression(Scope *S);
virtual void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS);
virtual void CodeCompleteObjCPropertyGetter(Scope *S, DeclPtrTy ClassDecl,
DeclPtrTy *Methods,
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 5769716..095f537 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -183,20 +183,19 @@ void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers,
LookupResult Lookup(*this, Name, Tok.getLocation(), LookupOrdinaryName);
LookupParsedName(Lookup, curScope, NULL, true);
- NamedDecl *ND = Lookup.getAsSingleDecl(Context);
-
- if (!ND) {
+ if (Lookup.empty()) {
Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
<< Name << SourceRange(Tok.getLocation());
continue;
}
- if (!isa<VarDecl>(ND) || !cast<VarDecl>(ND)->hasLocalStorage()) {
+ VarDecl *VD = Lookup.getAsSingle<VarDecl>();
+ if (!VD || !VD->hasLocalStorage()) {
Diag(PragmaLoc, diag::warn_pragma_unused_expected_localvar)
<< Name << SourceRange(Tok.getLocation());
continue;
}
- ND->addAttr(::new (Context) UnusedAttr());
+ VD->addAttr(::new (Context) UnusedAttr());
}
}
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 6b4f87e..814af90 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "SemaInit.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
@@ -539,6 +540,16 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
return TC_Success;
}
}
+ else if (CStyle && DestType->isObjCObjectPointerType()) {
+ // allow c-style cast of objective-c pointers as they are pervasive.
+ Kind = CastExpr::CK_AnyPointerToObjCPointerCast;
+ return TC_Success;
+ }
+ else if (CStyle && DestType->isBlockPointerType()) {
+ // allow c-style cast of void * to block pointers.
+ Kind = CastExpr::CK_AnyPointerToBlockPointerCast;
+ return TC_Success;
+ }
}
}
@@ -859,7 +870,9 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
if (CXXConstructorDecl *Constructor
= Self.TryInitializationByConstructor(DestType, &SrcExpr, 1,
OpRange.getBegin(),
- Sema::IK_Direct)) {
+ InitializationKind::CreateDirect(OpRange.getBegin(),
+ OpRange.getBegin(),
+ OpRange.getEnd()))) {
ConversionDecl = Constructor;
Kind = CastExpr::CK_ConstructorConversion;
return TC_Success;
@@ -1053,8 +1066,10 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
return TC_Failed;
}
- bool destIsPtr = DestType->isPointerType();
- bool srcIsPtr = SrcType->isPointerType();
+ bool destIsPtr =
+ CStyle? DestType->isAnyPointerType() : DestType->isPointerType();
+ bool srcIsPtr =
+ CStyle ? SrcType->isAnyPointerType() : SrcType->isPointerType();
if (!destIsPtr && !srcIsPtr) {
// Except for std::nullptr_t->integer and lvalue->reference, which are
// handled above, at least one of the two arguments must be a pointer.
@@ -1106,7 +1121,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
msg = diag::err_bad_cxx_cast_const_away;
return TC_Failed;
}
-
+ if (CStyle && DestType->isObjCObjectPointerType()) {
+ Kind = CastExpr::CK_AnyPointerToObjCPointerCast;
+ return TC_Success;
+ }
+
// Not casting away constness, so the only remaining check is for compatible
// pointer categories.
Kind = CastExpr::CK_BitCast;
@@ -1141,7 +1160,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
// Void pointers are not specified, but supported by every compiler out there.
// So we finish by allowing everything that remains - it's got to be two
// object pointers.
- Kind = CastExpr::CK_BitCast;
return TC_Success;
}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 34a5b78..039691f 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -313,7 +313,10 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
LookupName(Found, S);
assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet");
- NamedDecl *Result = Found.getAsSingleDecl(Context);
+ if (!Found.isSingleResult())
+ return 0;
+
+ NamedDecl *Result = Found.getFoundDecl();
if (isAcceptableNestedNameSpecifier(Result))
return Result;
@@ -327,6 +330,12 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
/// that it contains an extra parameter \p ScopeLookupResult, which provides
/// the result of name lookup within the scope of the nested-name-specifier
/// that was computed at template definitino time.
+///
+/// If ErrorRecoveryLookup is true, then this call is used to improve error
+/// recovery. This means that it should not emit diagnostics, it should
+/// just return null on failure. It also means it should only return a valid
+/// 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,
SourceLocation IdLoc,
@@ -334,7 +343,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
IdentifierInfo &II,
QualType ObjectType,
NamedDecl *ScopeLookupResult,
- bool EnteringContext) {
+ bool EnteringContext,
+ bool ErrorRecoveryLookup) {
NestedNameSpecifier *Prefix
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
@@ -400,6 +410,10 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
ObjectTypeSearchedInScope = true;
}
} else if (isDependent) {
+ // Don't speculate if we're just trying to improve error recovery.
+ if (ErrorRecoveryLookup)
+ return 0;
+
// We were not able to compute the declaration context for a dependent
// base object type or prior nested-name-specifier, so this
// nested-name-specifier refers to an unknown specialization. Just build
@@ -414,7 +428,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
}
// FIXME: Deal with ambiguities cleanly.
- NamedDecl *SD = Found.getAsSingleDecl(Context);
+ NamedDecl *SD = Found.getAsSingle<NamedDecl>();
if (isAcceptableNestedNameSpecifier(SD)) {
if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) {
// C++ [basic.lookup.classref]p4:
@@ -429,7 +443,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
if (S) {
LookupResult FoundOuter(*this, &II, IdLoc, LookupNestedNameSpecifierName);
LookupName(FoundOuter, S);
- OuterDecl = FoundOuter.getAsSingleDecl(Context);
+ OuterDecl = FoundOuter.getAsSingle<NamedDecl>();
} else
OuterDecl = ScopeLookupResult;
@@ -439,14 +453,17 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
!Context.hasSameType(
Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)),
Context.getTypeDeclType(cast<TypeDecl>(SD))))) {
+ if (ErrorRecoveryLookup)
+ return 0;
+
Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
<< &II;
Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type)
<< ObjectType;
Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope);
- // Fall through so that we'll pick the name we found in the object type,
- // since that's probably what the user wanted anyway.
+ // Fall through so that we'll pick the name we found in the object
+ // type, since that's probably what the user wanted anyway.
}
}
@@ -466,17 +483,21 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
T.getTypePtr());
}
+ // Otherwise, we have an error case. If we don't want diagnostics, just
+ // return an error now.
+ if (ErrorRecoveryLookup)
+ return 0;
+
// If we didn't find anything during our lookup, try again with
// ordinary name lookup, which can help us produce better error
// messages.
- if (!SD) {
+ if (Found.empty()) {
Found.clear(LookupOrdinaryName);
LookupName(Found, S);
- SD = Found.getAsSingleDecl(Context);
}
unsigned DiagID;
- if (SD)
+ if (!Found.empty())
DiagID = diag::err_expected_class_or_namespace;
else if (SS.isSet()) {
Diag(IdLoc, diag::err_no_member) << &II << LookupCtx << SS.getRange();
@@ -507,7 +528,23 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
bool EnteringContext) {
return BuildCXXNestedNameSpecifier(S, SS, IdLoc, CCLoc, II,
QualType::getFromOpaquePtr(ObjectTypePtr),
- /*ScopeLookupResult=*/0, EnteringContext);
+ /*ScopeLookupResult=*/0, EnteringContext,
+ false);
+}
+
+/// IsInvalidUnlessNestedName - This method is used for error recovery
+/// purposes to determine whether the specified identifier is only valid as
+/// a nested name specifier, for example a namespace name. It is
+/// 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,
+ IdentifierInfo &II, TypeTy *ObjectType,
+ bool EnteringContext) {
+ return BuildCXXNestedNameSpecifier(S, SS, SourceLocation(), SourceLocation(),
+ II, QualType::getFromOpaquePtr(ObjectType),
+ /*ScopeLookupResult=*/0, EnteringContext,
+ true);
}
Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
@@ -522,6 +559,44 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
T.getTypePtr());
}
+bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
+ assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
+
+ NestedNameSpecifier *Qualifier =
+ static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+
+ // There are only two places a well-formed program may qualify a
+ // declarator: first, when defining a namespace or class member
+ // out-of-line, and second, when naming an explicitly-qualified
+ // friend function. The latter case is governed by
+ // C++03 [basic.lookup.unqual]p10:
+ // In a friend declaration naming a member function, a name used
+ // in the function declarator and not part of a template-argument
+ // in a template-id is first looked up in the scope of the member
+ // function's class. If it is not found, or if the name is part of
+ // a template-argument in a template-id, the look up is as
+ // described for unqualified names in the definition of the class
+ // granting friendship.
+ // i.e. we don't push a scope unless it's a class member.
+
+ switch (Qualifier->getKind()) {
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Namespace:
+ // These are always namespace scopes. We never want to enter a
+ // namespace scope from anything but a file context.
+ return CurContext->getLookupContext()->isFileContext();
+
+ case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ // These are never namespace scopes.
+ return true;
+ }
+
+ // Silence bogus warning.
+ return false;
+}
+
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
/// scope or nested-name-specifier) is parsed, part of a declarator-id.
/// After this method is called, according to [C++ 3.4.3p3], names should be
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 9060fe6..28de500 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -700,30 +700,30 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
if (Arg->isTypeDependent())
continue;
- QualType RWType = Arg->getType();
-
- const BuiltinType *BT = RWType->getAs<BuiltinType>();
- llvm::APSInt Result;
- if (!BT || BT->getKind() != BuiltinType::Int)
- return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_argument)
+ 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_argument)
+ return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_arg_ice)
<< SourceRange(Arg->getLocStart(), Arg->getLocEnd());
// FIXME: gcc issues a warning and rewrites these to 0. These
// seems especially odd for the third argument since the default
// is 3.
if (i == 1) {
- if (Result.getSExtValue() < 0 || Result.getSExtValue() > 1)
+ if (Result.getLimitedValue() > 1)
return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
<< "0" << "1" << Arg->getSourceRange();
} else {
- if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3)
+ if (Result.getLimitedValue() > 3)
return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
<< "0" << "3" << Arg->getSourceRange();
}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index b386adb..4ce9330 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -45,11 +45,64 @@ namespace {
/// the result set twice.
llvm::SmallPtrSet<Decl*, 16> AllDeclsFound;
+ typedef std::pair<NamedDecl *, unsigned> DeclIndexPair;
+
+ /// \brief An entry in the shadow map, which is optimized to store
+ /// a single (declaration, index) mapping (the common case) but
+ /// can also store a list of (declaration, index) mappings.
+ class ShadowMapEntry {
+ typedef llvm::SmallVector<DeclIndexPair, 4> DeclIndexPairVector;
+
+ /// \brief Contains either the solitary NamedDecl * or a vector
+ /// of (declaration, index) pairs.
+ llvm::PointerUnion<NamedDecl *, DeclIndexPairVector*> DeclOrVector;
+
+ /// \brief When the entry contains a single declaration, this is
+ /// the index associated with that entry.
+ unsigned SingleDeclIndex;
+
+ public:
+ ShadowMapEntry() : DeclOrVector(), SingleDeclIndex(0) { }
+
+ void Add(NamedDecl *ND, unsigned Index) {
+ if (DeclOrVector.isNull()) {
+ // 0 - > 1 elements: just set the single element information.
+ DeclOrVector = ND;
+ SingleDeclIndex = Index;
+ return;
+ }
+
+ if (NamedDecl *PrevND = DeclOrVector.dyn_cast<NamedDecl *>()) {
+ // 1 -> 2 elements: create the vector of results and push in the
+ // existing declaration.
+ DeclIndexPairVector *Vec = new DeclIndexPairVector;
+ Vec->push_back(DeclIndexPair(PrevND, SingleDeclIndex));
+ DeclOrVector = Vec;
+ }
+
+ // Add the new element to the end of the vector.
+ DeclOrVector.get<DeclIndexPairVector*>()->push_back(
+ DeclIndexPair(ND, Index));
+ }
+
+ void Destroy() {
+ if (DeclIndexPairVector *Vec
+ = DeclOrVector.dyn_cast<DeclIndexPairVector *>()) {
+ delete Vec;
+ DeclOrVector = ((NamedDecl *)0);
+ }
+ }
+
+ // Iteration.
+ class iterator;
+ iterator begin() const;
+ iterator end() const;
+ };
+
/// \brief A mapping from declaration names to the declarations that have
/// this name within a particular scope and their index within the list of
/// results.
- typedef std::multimap<DeclarationName,
- std::pair<NamedDecl *, unsigned> > ShadowMap;
+ typedef llvm::DenseMap<DeclarationName, ShadowMapEntry> ShadowMap;
/// \brief The semantic analysis object for which results are being
/// produced.
@@ -117,6 +170,95 @@ namespace {
};
}
+class ResultBuilder::ShadowMapEntry::iterator {
+ llvm::PointerUnion<NamedDecl*, const DeclIndexPair*> DeclOrIterator;
+ unsigned SingleDeclIndex;
+
+public:
+ typedef DeclIndexPair value_type;
+ typedef value_type reference;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::input_iterator_tag iterator_category;
+
+ class pointer {
+ DeclIndexPair Value;
+
+ public:
+ pointer(const DeclIndexPair &Value) : Value(Value) { }
+
+ const DeclIndexPair *operator->() const {
+ return &Value;
+ }
+ };
+
+ iterator() : DeclOrIterator((NamedDecl *)0), SingleDeclIndex(0) { }
+
+ iterator(NamedDecl *SingleDecl, unsigned Index)
+ : DeclOrIterator(SingleDecl), SingleDeclIndex(Index) { }
+
+ iterator(const DeclIndexPair *Iterator)
+ : DeclOrIterator(Iterator), SingleDeclIndex(0) { }
+
+ iterator &operator++() {
+ if (DeclOrIterator.is<NamedDecl *>()) {
+ DeclOrIterator = (NamedDecl *)0;
+ SingleDeclIndex = 0;
+ return *this;
+ }
+
+ const DeclIndexPair *I = DeclOrIterator.get<const DeclIndexPair*>();
+ ++I;
+ DeclOrIterator = I;
+ return *this;
+ }
+
+ iterator operator++(int) {
+ iterator tmp(*this);
+ ++(*this);
+ return tmp;
+ }
+
+ reference operator*() const {
+ if (NamedDecl *ND = DeclOrIterator.dyn_cast<NamedDecl *>())
+ return reference(ND, SingleDeclIndex);
+
+ return *DeclOrIterator.get<const DeclIndexPair*>();
+ }
+
+ pointer operator->() const {
+ return pointer(**this);
+ }
+
+ friend bool operator==(const iterator &X, const iterator &Y) {
+ return X.DeclOrIterator.getOpaqueValue()
+ == Y.DeclOrIterator.getOpaqueValue() &&
+ X.SingleDeclIndex == Y.SingleDeclIndex;
+ }
+
+ friend bool operator!=(const iterator &X, const iterator &Y) {
+ return !(X == Y);
+ }
+};
+
+ResultBuilder::ShadowMapEntry::iterator
+ResultBuilder::ShadowMapEntry::begin() const {
+ if (DeclOrVector.isNull())
+ return iterator();
+
+ if (NamedDecl *ND = DeclOrVector.dyn_cast<NamedDecl *>())
+ return iterator(ND, SingleDeclIndex);
+
+ return iterator(DeclOrVector.get<DeclIndexPairVector *>()->begin());
+}
+
+ResultBuilder::ShadowMapEntry::iterator
+ResultBuilder::ShadowMapEntry::end() const {
+ if (DeclOrVector.is<NamedDecl *>() || DeclOrVector.isNull())
+ return iterator();
+
+ return iterator(DeclOrVector.get<DeclIndexPairVector *>()->end());
+}
+
/// \brief Determines whether the given hidden result could be found with
/// some extra work, e.g., by qualifying the name.
///
@@ -214,7 +356,16 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
if (isa<FriendDecl>(CanonDecl) ||
(IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend)))
return;
+
+ // Class template (partial) specializations are never added as results.
+ if (isa<ClassTemplateSpecializationDecl>(CanonDecl) ||
+ isa<ClassTemplatePartialSpecializationDecl>(CanonDecl))
+ return;
+ // Using declarations themselves are never added as results.
+ if (isa<UsingDecl>(CanonDecl))
+ return;
+
if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) {
// __va_list_tag is a freak of nature. Find it and skip it.
if (Id->isStr("__va_list_tag") || Id->isStr("__builtin_va_list"))
@@ -241,14 +392,18 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
return;
ShadowMap &SMap = ShadowMaps.back();
- ShadowMap::iterator I, IEnd;
- for (llvm::tie(I, IEnd) = SMap.equal_range(R.Declaration->getDeclName());
- I != IEnd; ++I) {
- NamedDecl *ND = I->second.first;
- unsigned Index = I->second.second;
+ ShadowMapEntry::iterator I, IEnd;
+ ShadowMap::iterator NamePos = SMap.find(R.Declaration->getDeclName());
+ if (NamePos != SMap.end()) {
+ I = NamePos->second.begin();
+ IEnd = NamePos->second.end();
+ }
+
+ for (; I != IEnd; ++I) {
+ NamedDecl *ND = I->first;
+ unsigned Index = I->second;
if (ND->getCanonicalDecl() == CanonDecl) {
// This is a redeclaration. Always pick the newer declaration.
- I->second.first = R.Declaration;
Results[Index].Declaration = R.Declaration;
// Pick the best rank of the two.
@@ -265,23 +420,28 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
std::list<ShadowMap>::iterator SM, SMEnd = ShadowMaps.end();
--SMEnd;
for (SM = ShadowMaps.begin(); SM != SMEnd; ++SM) {
- for (llvm::tie(I, IEnd) = SM->equal_range(R.Declaration->getDeclName());
- I != IEnd; ++I) {
+ ShadowMapEntry::iterator I, IEnd;
+ ShadowMap::iterator NamePos = SM->find(R.Declaration->getDeclName());
+ if (NamePos != SM->end()) {
+ I = NamePos->second.begin();
+ IEnd = NamePos->second.end();
+ }
+ for (; I != IEnd; ++I) {
// A tag declaration does not hide a non-tag declaration.
- if (I->second.first->getIdentifierNamespace() == Decl::IDNS_Tag &&
+ if (I->first->getIdentifierNamespace() == Decl::IDNS_Tag &&
(IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
Decl::IDNS_ObjCProtocol)))
continue;
// Protocols are in distinct namespaces from everything else.
- if (((I->second.first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol)
+ if (((I->first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol)
|| (IDNS & Decl::IDNS_ObjCProtocol)) &&
- I->second.first->getIdentifierNamespace() != IDNS)
+ I->first->getIdentifierNamespace() != IDNS)
continue;
// The newly-added result is hidden by an entry in the shadow map.
if (canHiddenResultBeFound(SemaRef.getLangOptions(), R.Declaration,
- I->second.first)) {
+ I->first)) {
// Note that this result was hidden.
R.Hidden = true;
R.QualifierIsInformative = false;
@@ -327,8 +487,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
// Insert this result into the set of results and into the current shadow
// map.
- SMap.insert(std::make_pair(R.Declaration->getDeclName(),
- std::make_pair(R.Declaration, Results.size())));
+ SMap[R.Declaration->getDeclName()].Add(R.Declaration, Results.size());
Results.push_back(R);
}
@@ -339,6 +498,12 @@ void ResultBuilder::EnterNewScope() {
/// \brief Exit from the current scope.
void ResultBuilder::ExitScope() {
+ for (ShadowMap::iterator E = ShadowMaps.back().begin(),
+ EEnd = ShadowMaps.back().end();
+ E != EEnd;
+ ++E)
+ E->second.Destroy();
+
ShadowMaps.pop_back();
}
@@ -403,18 +568,20 @@ bool ResultBuilder::IsNamespaceOrAlias(NamedDecl *ND) const {
return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
}
-/// \brief Brief determines whether the given declaration is a namespace or
-/// namespace alias.
+/// \brief Determines whether the given declaration is a type.
bool ResultBuilder::IsType(NamedDecl *ND) const {
return isa<TypeDecl>(ND);
}
-/// \brief Since every declaration found within a class is a member that we
-/// care about, always returns true. This predicate exists mostly to
-/// communicate to the result builder that we are performing a lookup for
-/// member access.
+/// \brief Determines which members of a class should be visible via
+/// "." or "->". Only value declarations, nested name specifiers, and
+/// using declarations thereof should show up.
bool ResultBuilder::IsMember(NamedDecl *ND) const {
- return true;
+ if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
+ ND = Using->getTargetDecl();
+
+ return isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND) ||
+ isa<ObjCPropertyDecl>(ND);
}
// Find the next outer declaration context corresponding to this scope.
@@ -615,7 +782,7 @@ static unsigned CollectLookupResults(Scope *S,
}
/// \brief Add type specifiers for the current language as keyword results.
-static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank,
+static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank,
ResultBuilder &Results) {
typedef CodeCompleteConsumer::Result Result;
Results.MaybeAddResult(Result("short", Rank));
@@ -773,10 +940,11 @@ static void AddTemplateParameterChunks(ASTContext &Context,
/// \brief Add a qualifier to the given code-completion string, if the
/// provided nested-name-specifier is non-NULL.
-void AddQualifierToCompletionString(CodeCompletionString *Result,
- NestedNameSpecifier *Qualifier,
- bool QualifierIsInformative,
- ASTContext &Context) {
+static void
+AddQualifierToCompletionString(CodeCompletionString *Result,
+ NestedNameSpecifier *Qualifier,
+ bool QualifierIsInformative,
+ ASTContext &Context) {
if (!Qualifier)
return;
@@ -791,6 +959,23 @@ void AddQualifierToCompletionString(CodeCompletionString *Result,
Result->AddTextChunk(PrintedNNS);
}
+static void AddFunctionTypeQualsToCompletionString(CodeCompletionString *Result,
+ FunctionDecl *Function) {
+ const FunctionProtoType *Proto
+ = Function->getType()->getAs<FunctionProtoType>();
+ if (!Proto || !Proto->getTypeQuals())
+ return;
+
+ std::string QualsStr;
+ if (Proto->getTypeQuals() & Qualifiers::Const)
+ QualsStr += " const";
+ if (Proto->getTypeQuals() & Qualifiers::Volatile)
+ QualsStr += " volatile";
+ if (Proto->getTypeQuals() & Qualifiers::Restrict)
+ QualsStr += " restrict";
+ Result->AddInformativeChunk(QualsStr);
+}
+
/// \brief If possible, create a new code completion string for the given
/// result.
///
@@ -864,6 +1049,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
AddFunctionParameterChunks(S.Context, Function, Result);
Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen));
+ AddFunctionTypeQualsToCompletionString(Result, Function);
return Result;
}
@@ -917,6 +1103,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
AddFunctionParameterChunks(S.Context, Function, Result);
Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen));
+ AddFunctionTypeQualsToCompletionString(Result, Function);
return Result;
}
@@ -1064,13 +1251,54 @@ namespace {
typedef CodeCompleteConsumer::Result Result;
bool isEarlierDeclarationName(DeclarationName X, DeclarationName Y) const {
- if (!X.getObjCSelector().isNull() && !Y.getObjCSelector().isNull()) {
- // Consider all selector kinds to be equivalent.
- } else if (X.getNameKind() != Y.getNameKind())
+ Selector XSel = X.getObjCSelector();
+ Selector YSel = Y.getObjCSelector();
+ if (!XSel.isNull() && !YSel.isNull()) {
+ // We are comparing two selectors.
+ unsigned N = std::min(XSel.getNumArgs(), YSel.getNumArgs());
+ if (N == 0)
+ ++N;
+ for (unsigned I = 0; I != N; ++I) {
+ IdentifierInfo *XId = XSel.getIdentifierInfoForSlot(I);
+ IdentifierInfo *YId = YSel.getIdentifierInfoForSlot(I);
+ if (!XId || !YId)
+ return XId && !YId;
+
+ switch (XId->getName().compare_lower(YId->getName())) {
+ case -1: return true;
+ case 1: return false;
+ default: break;
+ }
+ }
+
+ return XSel.getNumArgs() < YSel.getNumArgs();
+ }
+
+ // For non-selectors, order by kind.
+ if (X.getNameKind() != Y.getNameKind())
return X.getNameKind() < Y.getNameKind();
- return llvm::LowercaseString(X.getAsString())
- < llvm::LowercaseString(Y.getAsString());
+ // Order identifiers by comparison of their lowercased names.
+ if (IdentifierInfo *XId = X.getAsIdentifierInfo())
+ return XId->getName().compare_lower(
+ Y.getAsIdentifierInfo()->getName()) < 0;
+
+ // Order overloaded operators by the order in which they appear
+ // in our list of operators.
+ if (OverloadedOperatorKind XOp = X.getCXXOverloadedOperator())
+ return XOp < Y.getCXXOverloadedOperator();
+
+ // Order C++0x user-defined literal operators lexically by their
+ // lowercased suffixes.
+ if (IdentifierInfo *XLit = X.getCXXLiteralIdentifier())
+ return XLit->getName().compare_lower(
+ Y.getCXXLiteralIdentifier()->getName()) < 0;
+
+ // The only stable ordering we have is to turn the name into a
+ // string and then compare the lower-case strings. This is
+ // inefficient, but thankfully does not happen too often.
+ return llvm::StringRef(X.getAsString()).compare_lower(
+ Y.getAsString()) < 0;
}
bool operator()(const Result &X, const Result &Y) const {
@@ -1088,7 +1316,7 @@ namespace {
: X.Pattern->getTypedText();
const char *YStr = (Y.Kind == Result::RK_Keyword)? Y.Keyword
: Y.Pattern->getTypedText();
- return strcmp(XStr, YStr) < 0;
+ return llvm::StringRef(XStr).compare_lower(YStr) < 0;
}
// Result kinds are ordered by decreasing importance.
@@ -1113,12 +1341,11 @@ namespace {
Y.Declaration->getDeclName());
case Result::RK_Macro:
- return llvm::LowercaseString(X.Macro->getName()) <
- llvm::LowercaseString(Y.Macro->getName());
+ return X.Macro->getName().compare_lower(Y.Macro->getName()) < 0;
case Result::RK_Keyword:
case Result::RK_Pattern:
- llvm::llvm_unreachable("Result kinds handled above");
+ llvm_unreachable("Result kinds handled above");
break;
}
@@ -1153,9 +1380,23 @@ static void HandleCodeCompleteResults(Sema *S,
}
void Sema::CodeCompleteOrdinaryName(Scope *S) {
+ typedef CodeCompleteConsumer::Result Result;
ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName);
unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
0, CurContext, Results);
+
+ Results.EnterNewScope();
+ AddTypeSpecifierResults(getLangOptions(), NextRank, Results);
+
+ if (getLangOptions().ObjC1) {
+ // Add the "super" keyword, if appropriate.
+ if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(CurContext))
+ if (Method->getClassInterface()->getSuperClass())
+ Results.MaybeAddResult(Result("super", NextRank));
+ }
+
+ Results.ExitScope();
+
if (CodeCompleter->includeMacros())
AddMacroResults(PP, NextRank, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
@@ -1257,6 +1498,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
// We could have the start of a nested-name-specifier. Add those
// results as well.
+ // FIXME: We should really walk base classes to produce
+ // nested-name-specifiers so that we produce more-precise results.
Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank,
CurContext, Results);
@@ -1448,14 +1691,21 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
ExprTy **ArgsIn, unsigned NumArgs) {
if (!CodeCompleter)
return;
-
+
+ // When we're code-completing for a call, we fall back to ordinary
+ // name code-completion whenever we can't produce specific
+ // results. We may want to revisit this strategy in the future,
+ // e.g., by merging the two kinds of results.
+
Expr *Fn = (Expr *)FnIn;
Expr **Args = (Expr **)ArgsIn;
-
+
// Ignore type-dependent call expressions entirely.
if (Fn->isTypeDependent() ||
- Expr::hasAnyTypeDependentArguments(Args, NumArgs))
+ Expr::hasAnyTypeDependentArguments(Args, NumArgs)) {
+ CodeCompleteOrdinaryName(S);
return;
+ }
llvm::SmallVector<NamedDecl*,8> Fns;
DeclarationName UnqualifiedName;
@@ -1498,8 +1748,12 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
if (Cand->Viable)
Results.push_back(ResultCandidate(Cand->Function));
}
- CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(),
- Results.size());
+
+ if (Results.empty())
+ CodeCompleteOrdinaryName(S);
+ else
+ CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(),
+ Results.size());
}
void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
@@ -1510,7 +1764,12 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
DeclContext *Ctx = computeDeclContext(SS, EnteringContext);
if (!Ctx)
return;
-
+
+ // Try to instantiate any non-dependent declaration contexts before
+ // we look in them.
+ if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS))
+ return;
+
ResultBuilder Results(*this);
unsigned NextRank = CollectMemberLookupResults(Ctx, 0, Ctx, Results);
@@ -1644,6 +1903,183 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
+void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl,
+ bool InInterface) {
+ typedef CodeCompleteConsumer::Result Result;
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ if (ObjCImpDecl) {
+ // Since we have an implementation, we can end it.
+ Results.MaybeAddResult(Result("end", 0));
+
+ CodeCompletionString *Pattern = 0;
+ Decl *ImpDecl = ObjCImpDecl.getAs<Decl>();
+ if (isa<ObjCImplementationDecl>(ImpDecl) ||
+ isa<ObjCCategoryImplDecl>(ImpDecl)) {
+ // @dynamic
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("dynamic");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("property");
+ Results.MaybeAddResult(Result(Pattern, 0));
+
+ // @synthesize
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("synthesize");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("property");
+ Results.MaybeAddResult(Result(Pattern, 0));
+ }
+ } else if (InInterface) {
+ // Since we have an interface or protocol, we can end it.
+ Results.MaybeAddResult(Result("end", 0));
+
+ if (LangOpts.ObjC2) {
+ // @property
+ Results.MaybeAddResult(Result("property", 0));
+ }
+
+ // @required
+ Results.MaybeAddResult(Result("required", 0));
+
+ // @optional
+ Results.MaybeAddResult(Result("optional", 0));
+ } else {
+ CodeCompletionString *Pattern = 0;
+
+ // @class name ;
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("class");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddTextChunk(";"); // add ';' chunk
+ Results.MaybeAddResult(Result(Pattern, 0));
+
+ // @interface name
+ // FIXME: Could introduce the whole pattern, including superclasses and
+ // such.
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("interface");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("class");
+ Results.MaybeAddResult(Result(Pattern, 0));
+
+ // @protocol name
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("protocol");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("protocol");
+ Results.MaybeAddResult(Result(Pattern, 0));
+
+ // @implementation name
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("implementation");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("class");
+ Results.MaybeAddResult(Result(Pattern, 0));
+
+ // @compatibility_alias name
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("compatibility_alias");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("alias");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("class");
+ Results.MaybeAddResult(Result(Pattern, 0));
+ }
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
+
+static void AddObjCExpressionResults(unsigned Rank, ResultBuilder &Results) {
+ typedef CodeCompleteConsumer::Result Result;
+ CodeCompletionString *Pattern = 0;
+
+ // @encode ( type-name )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("encode");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("type-name");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.MaybeAddResult(Result(Pattern, Rank));
+
+ // @protocol ( protocol-name )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("protocol");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("protocol-name");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.MaybeAddResult(Result(Pattern, Rank));
+
+ // @selector ( selector )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("selector");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("selector");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.MaybeAddResult(Result(Pattern, Rank));
+}
+
+void Sema::CodeCompleteObjCAtStatement(Scope *S) {
+ typedef CodeCompleteConsumer::Result Result;
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+
+ CodeCompletionString *Pattern = 0;
+
+ // @try { statements } @catch ( declaration ) { statements } @finally
+ // { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("try");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Pattern->AddTextChunk("@catch");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("parameter");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Pattern->AddTextChunk("@finally");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.MaybeAddResult(Result(Pattern, 0));
+
+ // @throw
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("throw");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddTextChunk(";");
+ Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk
+
+ // @synchronized ( expression ) { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("synchronized");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk
+
+ AddObjCExpressionResults(0, Results);
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
+
+void Sema::CodeCompleteObjCAtExpression(Scope *S) {
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ AddObjCExpressionResults(0, Results);
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
+
/// \brief Determine whether the addition of the given flag to an Objective-C
/// property's attributes will cause a conflict.
static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 520d7de..14d2377 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "SemaInit.h"
#include "Lookup.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
@@ -229,7 +230,7 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
LookupName(R, S, false);
R.suppressDiagnostics();
if (R.getResultKind() == LookupResult::Found)
- if (const TagDecl *TD = dyn_cast<TagDecl>(R.getAsSingleDecl(Context))) {
+ if (const TagDecl *TD = R.getAsSingle<TagDecl>()) {
switch (TD->getTagKind()) {
case TagDecl::TK_struct: return DeclSpec::TST_struct;
case TagDecl::TK_union: return DeclSpec::TST_union;
@@ -379,7 +380,9 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
// scope.
if ((isa<FunctionTemplateDecl>(D) &&
cast<FunctionTemplateDecl>(D)->getTemplatedDecl()->isOutOfLine()) ||
- (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isOutOfLine()) ||
+ (isa<FunctionDecl>(D) &&
+ (cast<FunctionDecl>(D)->isFunctionTemplateSpecialization() ||
+ cast<FunctionDecl>(D)->isOutOfLine())) ||
(isa<VarDecl>(D) && cast<VarDecl>(D)->isOutOfLine()))
return;
@@ -588,7 +591,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
FunctionDecl *New = FunctionDecl::Create(Context,
Context.getTranslationUnitDecl(),
- Loc, II, R, /*DInfo=*/0,
+ Loc, II, R, /*TInfo=*/0,
FunctionDecl::Extern, false,
/*hasPrototype=*/true);
New->setImplicit();
@@ -599,7 +602,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
llvm::SmallVector<ParmVarDecl*, 16> Params;
for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i)
Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0,
- FT->getArgType(i), /*DInfo=*/0,
+ FT->getArgType(i), /*TInfo=*/0,
VarDecl::None, 0));
New->setParams(Context, Params.data(), Params.size());
}
@@ -762,6 +765,24 @@ struct GNUCompatibleParamWarning {
QualType PromotedType;
};
+
+/// getSpecialMember - get the special member enum for a method.
+static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx,
+ const CXXMethodDecl *MD) {
+ if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
+ if (Ctor->isDefaultConstructor())
+ return Sema::CXXDefaultConstructor;
+ if (Ctor->isCopyConstructor(Ctx))
+ return Sema::CXXCopyConstructor;
+ }
+
+ if (isa<CXXDestructorDecl>(MD))
+ return Sema::CXXDestructor;
+
+ assert(MD->isCopyAssignment() && "Must have copy assignment operator");
+ return Sema::CXXCopyAssignment;
+}
+
/// MergeFunctionDecl - We just parsed a function 'New' from
/// declarator D which has the same name and scope as a previous
/// declaration 'Old'. Figure out how to resolve this situation,
@@ -782,6 +803,15 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
else
Old = dyn_cast<FunctionDecl>(OldD);
if (!Old) {
+ if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(OldD)) {
+ Diag(New->getLocation(), diag::err_using_decl_conflict_reverse);
+ Diag(Shadow->getTargetDecl()->getLocation(),
+ diag::note_using_decl_target);
+ Diag(Shadow->getUsingDecl()->getLocation(),
+ diag::note_using_decl) << 0;
+ return true;
+ }
+
Diag(New->getLocation(), diag::err_redefinition_different_kind)
<< New->getDeclName();
Diag(OldD->getLocation(), diag::note_previous_definition);
@@ -827,33 +857,45 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
- if (OldMethod && NewMethod && !NewMethod->getFriendObjectKind() &&
- 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.
- if (OldMethod->isStatic() || NewMethod->isStatic()) {
- Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member);
+ if (OldMethod && NewMethod) {
+ if (!NewMethod->getFriendObjectKind() &&
+ 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.
+ if (OldMethod->isStatic() || NewMethod->isStatic()) {
+ Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member);
+ Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
+ return true;
+ }
+
+ // C++ [class.mem]p1:
+ // [...] A member shall not be declared twice in the
+ // member-specification, except that a nested class or member
+ // class template can be declared and then later defined.
+ unsigned NewDiag;
+ if (isa<CXXConstructorDecl>(OldMethod))
+ NewDiag = diag::err_constructor_redeclared;
+ else if (isa<CXXDestructorDecl>(NewMethod))
+ NewDiag = diag::err_destructor_redeclared;
+ else if (isa<CXXConversionDecl>(NewMethod))
+ NewDiag = diag::err_conv_function_redeclared;
+ else
+ NewDiag = diag::err_member_redeclared;
+
+ Diag(New->getLocation(), NewDiag);
Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
- return true;
+ } else {
+ if (OldMethod->isImplicit()) {
+ Diag(NewMethod->getLocation(),
+ diag::err_definition_of_implicitly_declared_member)
+ << New << getSpecialMember(Context, OldMethod);
+
+ Diag(OldMethod->getLocation(),
+ diag::note_previous_implicit_declaration);
+ return true;
+ }
}
-
- // C++ [class.mem]p1:
- // [...] A member shall not be declared twice in the
- // member-specification, except that a nested class or member
- // class template can be declared and then later defined.
- unsigned NewDiag;
- if (isa<CXXConstructorDecl>(OldMethod))
- NewDiag = diag::err_constructor_redeclared;
- else if (isa<CXXDestructorDecl>(NewMethod))
- NewDiag = diag::err_destructor_redeclared;
- else if (isa<CXXConversionDecl>(NewMethod))
- NewDiag = diag::err_conv_function_redeclared;
- else
- NewDiag = diag::err_member_redeclared;
-
- Diag(New->getLocation(), NewDiag);
- Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
}
// (C++98 8.3.5p3):
@@ -894,7 +936,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
ParamType != ParamEnd; ++ParamType) {
ParmVarDecl *Param = ParmVarDecl::Create(Context, New,
SourceLocation(), 0,
- *ParamType, /*DInfo=*/0,
+ *ParamType, /*TInfo=*/0,
VarDecl::None, 0);
Param->setImplicit();
Params.push_back(Param);
@@ -1057,10 +1099,11 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
if (getLangOptions().CPlusPlus) {
if (Context.hasSameType(New->getType(), Old->getType()))
MergedT = New->getType();
- // C++ [basic.types]p7:
- // [...] The declared type of an array object might be an array of
- // unknown size and therefore be incomplete at one point in a
- // translation unit and complete later on; [...]
+ // C++ [basic.link]p10:
+ // [...] the types specified by all declarations referring to a given
+ // object or function shall be identical, except that declarations for an
+ // array object can specify array types that differ by the presence or
+ // absence of a major array bound (8.3.4).
else if (Old->getType()->isIncompleteArrayType() &&
New->getType()->isArrayType()) {
CanQual<ArrayType> OldArray
@@ -1069,6 +1112,14 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
= Context.getCanonicalType(New->getType())->getAs<ArrayType>();
if (OldArray->getElementType() == NewArray->getElementType())
MergedT = New->getType();
+ } else if (Old->getType()->isArrayType() &&
+ New->getType()->isIncompleteArrayType()) {
+ CanQual<ArrayType> OldArray
+ = Context.getCanonicalType(Old->getType())->getAs<ArrayType>();
+ CanQual<ArrayType> NewArray
+ = Context.getCanonicalType(New->getType())->getAs<ArrayType>();
+ if (OldArray->getElementType() == NewArray->getElementType())
+ MergedT = Old->getType();
}
} else {
MergedT = Context.mergeTypes(New->getType(), Old->getType());
@@ -1202,6 +1253,11 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
HasFakeEdge = true;
continue;
}
+ if (isa<AsmStmt>(S)) {
+ HasFakeEdge = true;
+ HasLiveReturn = true;
+ continue;
+ }
bool NoReturnEdge = false;
if (CallExpr *C = dyn_cast<CallExpr>(S)) {
Expr *CEE = C->getCallee()->IgnoreParenCasts();
@@ -1209,11 +1265,10 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
NoReturnEdge = true;
HasFakeEdge = true;
} else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
- if (FD->hasAttr<NoReturnAttr>()) {
- NoReturnEdge = true;
- HasFakeEdge = true;
- }
+ ValueDecl *VD = DRE->getDecl();
+ if (VD->hasAttr<NoReturnAttr>()) {
+ NoReturnEdge = true;
+ HasFakeEdge = true;
}
}
}
@@ -1648,9 +1703,9 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// Mock up a declarator.
Declarator Dc(DS, Declarator::TypeNameContext);
- DeclaratorInfo *DInfo = 0;
- GetTypeForDeclarator(Dc, S, &DInfo);
- assert(DInfo && "couldn't build declarator info for anonymous struct/union");
+ TypeSourceInfo *TInfo = 0;
+ GetTypeForDeclarator(Dc, S, &TInfo);
+ assert(TInfo && "couldn't build declarator info for anonymous struct/union");
// Create a declaration for this anonymous struct/union.
NamedDecl *Anon = 0;
@@ -1658,7 +1713,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Anon = FieldDecl::Create(Context, OwningClass, Record->getLocation(),
/*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
- DInfo,
+ TInfo,
/*BitWidth=*/0, /*Mutable=*/false);
Anon->setAccess(AS_public);
if (getLangOptions().CPlusPlus)
@@ -1685,7 +1740,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Anon = VarDecl::Create(Context, Owner, Record->getLocation(),
/*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
- DInfo,
+ TInfo,
SC);
}
Anon->setImplicit();
@@ -1765,13 +1820,8 @@ DeclarationName Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) {
case UnqualifiedId::IK_TemplateId: {
TemplateName TName
- = TemplateName::getFromVoidPointer(Name.TemplateId->Template);
- if (TemplateDecl *Template = TName.getAsTemplateDecl())
- return Template->getDeclName();
- if (OverloadedFunctionDecl *Ovl = TName.getAsOverloadedFunctionDecl())
- return Ovl->getDeclName();
-
- return DeclarationName();
+ = TemplateName::getFromVoidPointer(Name.TemplateId->Template);
+ return Context.getNameForTemplate(TName);
}
}
@@ -1851,8 +1901,8 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
DeclContext *DC;
NamedDecl *New;
- DeclaratorInfo *DInfo = 0;
- QualType R = GetTypeForDeclarator(D, S, &DInfo);
+ TypeSourceInfo *TInfo = 0;
+ QualType R = GetTypeForDeclarator(D, S, &TInfo);
LookupResult Previous(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName,
ForRedeclaration);
@@ -1982,13 +2032,13 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
return DeclPtrTy();
}
- New = ActOnTypedefDeclarator(S, D, DC, R, DInfo, Previous, Redeclaration);
+ New = ActOnTypedefDeclarator(S, D, DC, R, TInfo, Previous, Redeclaration);
} else if (R->isFunctionType()) {
- New = ActOnFunctionDeclarator(S, D, DC, R, DInfo, Previous,
+ New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous,
move(TemplateParamLists),
IsFunctionDefinition, Redeclaration);
} else {
- New = ActOnVariableDeclarator(S, D, DC, R, DInfo, Previous,
+ New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous,
move(TemplateParamLists),
Redeclaration);
}
@@ -1998,9 +2048,7 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
// If this has an identifier and is not an invalid redeclaration or
// function template specialization, add it to the scope stack.
- if (Name && !(Redeclaration && New->isInvalidDecl()) &&
- !(isa<FunctionDecl>(New) &&
- cast<FunctionDecl>(New)->isFunctionTemplateSpecialization()))
+ if (Name && !(Redeclaration && New->isInvalidDecl()))
PushOnScopeChains(New, S);
return DeclPtrTy::make(New);
@@ -2104,7 +2152,7 @@ void Sema::DiagnoseFunctionSpecifiers(Declarator& D) {
NamedDecl*
Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, DeclaratorInfo *DInfo,
+ QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous, bool &Redeclaration) {
// Typedef declarators cannot be qualified (C++ [dcl.meaning]p1).
if (D.getCXXScopeSpec().isSet()) {
@@ -2125,7 +2173,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
- TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, DInfo);
+ TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, TInfo);
if (!NewTD) return 0;
// Handle attributes prior to checking for duplicates in MergeVarDecl
@@ -2151,7 +2199,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative);
if (!FixedTy.isNull()) {
Diag(D.getIdentifierLoc(), diag::warn_illegal_constant_array_size);
- NewTD->setTypeDeclaratorInfo(Context.getTrivialDeclaratorInfo(FixedTy));
+ NewTD->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(FixedTy));
} else {
if (SizeIsNegative)
Diag(D.getIdentifierLoc(), diag::err_typecheck_negative_array_size);
@@ -2244,7 +2292,7 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
NamedDecl*
Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, DeclaratorInfo *DInfo,
+ QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous,
MultiTemplateParamsArg TemplateParamLists,
bool &Redeclaration) {
@@ -2302,7 +2350,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_static_out_of_line)
<< CodeModificationHint::CreateRemoval(
- SourceRange(D.getDeclSpec().getStorageClassSpecLoc()));
+ D.getDeclSpec().getStorageClassSpecLoc());
} else if (SC == VarDecl::None)
SC = VarDecl::Static;
}
@@ -2346,7 +2394,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
- II, R, DInfo, SC);
+ II, R, TInfo, SC);
if (D.isInvalidType())
NewVD->setInvalidDecl();
@@ -2449,12 +2497,6 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD,
return NewVD->setInvalidDecl();
}
- // The variable can not have an abstract class type.
- if (RequireNonAbstractType(NewVD->getLocation(), T,
- diag::err_abstract_type_in_decl,
- AbstractVariableType))
- return NewVD->setInvalidDecl();
-
// Emit an error if an address space was applied to decl with local storage.
// This includes arrays of objects with address space qualifiers, but not
// automatic variables that point to other address spaces.
@@ -2596,7 +2638,7 @@ void Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
if (!CheckOverridingFunctionReturnType(MD, OldMD) &&
!CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
!CheckOverridingFunctionAttributes(MD, OldMD))
- MD->addOverriddenMethod(OldMD);
+ MD->addOverriddenMethod(OldMD->getCanonicalDecl());
}
}
}
@@ -2604,7 +2646,7 @@ void Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
NamedDecl*
Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, DeclaratorInfo *DInfo,
+ QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous,
MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition, bool &Redeclaration) {
@@ -2686,7 +2728,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Create the new declaration
NewFD = CXXConstructorDecl::Create(Context,
cast<CXXRecordDecl>(DC),
- D.getIdentifierLoc(), Name, R, DInfo,
+ D.getIdentifierLoc(), Name, R, TInfo,
isExplicit, isInline,
/*isImplicitlyDeclared=*/false);
} else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
@@ -2707,7 +2749,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, DInfo, SC, isInline,
+ Name, R, TInfo, SC, isInline,
/*hasPrototype=*/true);
D.setInvalidType();
}
@@ -2720,7 +2762,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
CheckConversionDeclarator(D, R, SC);
NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC),
- D.getIdentifierLoc(), Name, R, DInfo,
+ D.getIdentifierLoc(), Name, R, TInfo,
isInline, isExplicit);
isVirtualOkay = true;
@@ -2754,7 +2796,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, DInfo,
+ D.getIdentifierLoc(), Name, R, TInfo,
isStatic, isInline);
isVirtualOkay = !isStatic;
@@ -2772,7 +2814,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
NewFD = FunctionDecl::Create(Context, DC,
D.getIdentifierLoc(),
- Name, R, DInfo, SC, isInline, HasPrototype);
+ Name, R, TInfo, SC, isInline, HasPrototype);
}
if (D.isInvalidType())
@@ -2830,18 +2872,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// 'virtual' was specified outside of the class.
Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class)
<< CodeModificationHint::CreateRemoval(
- SourceRange(D.getDeclSpec().getVirtualSpecLoc()));
+ D.getDeclSpec().getVirtualSpecLoc());
} else {
// Okay: Add virtual to the method.
- cast<CXXMethodDecl>(NewFD)->setVirtualAsWritten(true);
CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC);
- CurClass->setAggregate(false);
- CurClass->setPOD(false);
- CurClass->setEmpty(false);
- CurClass->setPolymorphic(true);
- CurClass->setHasTrivialConstructor(false);
- CurClass->setHasTrivialCopyConstructor(false);
- CurClass->setHasTrivialCopyAssignment(false);
+ CurClass->setMethodAsVirtual(NewFD);
}
}
@@ -2865,9 +2900,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
NewFD->setAccess(AS_public);
}
- if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD))
- AddOverriddenMethods(cast<CXXRecordDecl>(DC), NewMD);
-
if (SC == FunctionDecl::Static && isa<CXXMethodDecl>(NewFD) &&
!CurContext->isRecord()) {
// C++ [class.static]p1:
@@ -2880,7 +2912,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_static_out_of_line)
<< CodeModificationHint::CreateRemoval(
- SourceRange(D.getDeclSpec().getStorageClassSpecLoc()));
+ D.getDeclSpec().getStorageClassSpecLoc());
}
// Handle GNU asm-label extension (encoded as an attribute).
@@ -2937,7 +2969,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
AE = FT->arg_type_end(); AI != AE; ++AI) {
ParmVarDecl *Param = ParmVarDecl::Create(Context, DC,
SourceLocation(), 0,
- *AI, /*DInfo=*/0,
+ *AI, /*TInfo=*/0,
VarDecl::None, 0);
Param->setImplicit();
Params.push_back(Param);
@@ -2996,7 +3028,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Perform semantic checking on the function declaration.
bool OverloadableAttrRequired = false; // FIXME: HACK!
- CheckFunctionDeclaration(NewFD, Previous, isExplicitSpecialization,
+ CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
Redeclaration, /*FIXME:*/OverloadableAttrRequired);
assert((NewFD->isInvalidDecl() || !Redeclaration ||
@@ -3118,7 +3150,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
/// an explicit specialization of the previous declaration.
///
/// This sets NewFD->isInvalidDecl() to true if there was an error.
-void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD,
+void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
LookupResult &Previous,
bool IsExplicitSpecialization,
bool &Redeclaration,
@@ -3156,34 +3188,47 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD,
// there's no more work to do here; we'll just add the new
// function to the scope.
- if (!getLangOptions().CPlusPlus &&
- AllowOverloadingOfFunction(Previous, Context)) {
- OverloadableAttrRequired = true;
-
- // Functions marked "overloadable" must have a prototype (that
- // we can't get through declaration merging).
- if (!NewFD->getType()->getAs<FunctionProtoType>()) {
- Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype)
- << NewFD;
- Redeclaration = true;
+ NamedDecl *OldDecl = 0;
+ if (!AllowOverloadingOfFunction(Previous, Context)) {
+ Redeclaration = true;
+ OldDecl = Previous.getFoundDecl();
+ } else {
+ if (!getLangOptions().CPlusPlus) {
+ OverloadableAttrRequired = true;
+
+ // Functions marked "overloadable" must have a prototype (that
+ // we can't get through declaration merging).
+ if (!NewFD->getType()->getAs<FunctionProtoType>()) {
+ Diag(NewFD->getLocation(),
+ diag::err_attribute_overloadable_no_prototype)
+ << NewFD;
+ Redeclaration = true;
- // Turn this into a variadic function with no parameters.
- QualType R = Context.getFunctionType(
- NewFD->getType()->getAs<FunctionType>()->getResultType(),
- 0, 0, true, 0);
- NewFD->setType(R);
- return NewFD->setInvalidDecl();
+ // Turn this into a variadic function with no parameters.
+ QualType R = Context.getFunctionType(
+ NewFD->getType()->getAs<FunctionType>()->getResultType(),
+ 0, 0, true, 0);
+ NewFD->setType(R);
+ return NewFD->setInvalidDecl();
+ }
}
- }
- NamedDecl *OldDecl = 0;
- if (!Previous.empty()) {
- if (!AllowOverloadingOfFunction(Previous, Context)) {
+ switch (CheckOverload(NewFD, Previous, OldDecl)) {
+ case Ovl_Match:
Redeclaration = true;
- OldDecl = Previous.getFoundDecl();
- } else if (!IsOverload(NewFD, Previous, OldDecl)) {
- if (!isUsingDecl(OldDecl))
- Redeclaration = true;
+ if (isa<UsingShadowDecl>(OldDecl) && CurContext->isRecord()) {
+ HideUsingShadowDecl(S, cast<UsingShadowDecl>(OldDecl));
+ Redeclaration = false;
+ }
+ break;
+
+ case Ovl_NonFunction:
+ Redeclaration = true;
+ break;
+
+ case Ovl_Overload:
+ Redeclaration = false;
+ break;
}
}
@@ -3243,8 +3288,6 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD,
Diag(NewFD->getLocation(), diag::err_destructor_name);
return NewFD->setInvalidDecl();
}
-
- CheckDestructor(Destructor);
}
Record->setUserDeclaredDestructor(true);
@@ -3257,8 +3300,22 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD,
// FIXME: C++0x: don't do this for "= default" destructors
Record->setHasTrivialDestructor(false);
} else if (CXXConversionDecl *Conversion
- = dyn_cast<CXXConversionDecl>(NewFD))
+ = dyn_cast<CXXConversionDecl>(NewFD)) {
ActOnConversionDeclarator(Conversion);
+ }
+
+ // Find any virtual functions that this function overrides.
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD)) {
+ if (!Method->isFunctionTemplateSpecialization() &&
+ !Method->getDescribedFunctionTemplate())
+ AddOverriddenMethods(Method->getParent(), Method);
+ }
+
+ // Additional checks for the destructor; make sure we do this after we
+ // figure out whether the destructor is virtual.
+ if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(NewFD))
+ if (!Destructor->getParent()->isDependentType())
+ CheckDestructor(Destructor);
// Extra checking for C++ overloaded operators (C++ [over.oper]).
if (NewFD->isOverloadedOperator() &&
@@ -3392,18 +3449,9 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
IntegerLiteral *IL;
Expr *Init = static_cast<Expr *>(init.get());
if ((IL = dyn_cast<IntegerLiteral>(Init)) && IL->getValue() == 0 &&
- Context.getCanonicalType(IL->getType()) == Context.IntTy) {
- if (Method->isVirtualAsWritten()) {
- Method->setPure();
-
- // A class is abstract if at least one function is pure virtual.
- cast<CXXRecordDecl>(CurContext)->setAbstract(true);
- } else if (!Method->isInvalidDecl()) {
- Diag(Method->getLocation(), diag::err_non_virtual_pure)
- << Method->getDeclName() << Init->getSourceRange();
- Method->setInvalidDecl();
- }
- } else {
+ Context.getCanonicalType(IL->getType()) == Context.IntTy)
+ CheckPureMethod(Method, Init->getSourceRange());
+ else {
Diag(Method->getLocation(), diag::err_member_function_initialization)
<< Method->getDeclName() << Init->getSourceRange();
Method->setInvalidDecl();
@@ -3436,6 +3484,12 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
return;
}
+ // The variable can not have an abstract class type.
+ if (RequireNonAbstractType(VDecl->getLocation(), VDecl->getType(),
+ diag::err_abstract_type_in_decl,
+ AbstractVariableType))
+ VDecl->setInvalidDecl();
+
const VarDecl *Def = 0;
if (VDecl->getDefinition(Def)) {
Diag(VDecl->getLocation(), diag::err_redefinition)
@@ -3458,8 +3512,36 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
Diag(VDecl->getLocation(), diag::err_block_extern_cant_init);
VDecl->setInvalidDecl();
} else if (!VDecl->isInvalidDecl()) {
- if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
- VDecl->getDeclName(), DirectInit))
+ if (VDecl->getType()->isReferenceType()
+ || isa<InitListExpr>(Init)) {
+ InitializedEntity Entity
+ = InitializedEntity::InitializeVariable(VDecl);
+
+ // FIXME: Poor source location information.
+ InitializationKind Kind
+ = DirectInit? InitializationKind::CreateDirect(VDecl->getLocation(),
+ SourceLocation(),
+ SourceLocation())
+ : InitializationKind::CreateCopy(VDecl->getLocation(),
+ SourceLocation());
+ InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1);
+ if (InitSeq) {
+ OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind,
+ MultiExprArg(*this, (void**)&Init, 1),
+ &DclT);
+ if (Result.isInvalid()) {
+ VDecl->setInvalidDecl();
+ return;
+ }
+
+ Init = Result.takeAs<Expr>();
+ } else {
+ InitSeq.Diagnose(*this, Entity, Kind, &Init, 1);
+ VDecl->setInvalidDecl();
+ return;
+ }
+ } else if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
+ VDecl->getDeclName(), DirectInit))
VDecl->setInvalidDecl();
// C++ 3.6.2p2, allow dynamic initialization of static initializers.
@@ -3649,7 +3731,7 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
SourceRange(Var->getLocation(),
Var->getLocation()),
Var->getDeclName(),
- IK_Default,
+ InitializationKind::CreateDefault(Var->getLocation()),
ConstructorArgs);
// FIXME: Location info for the variable initialization?
@@ -3668,6 +3750,12 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
Var->setInvalidDecl();
}
}
+
+ // The variable can not have an abstract class type.
+ if (RequireNonAbstractType(Var->getLocation(), Type,
+ diag::err_abstract_type_in_decl,
+ AbstractVariableType))
+ Var->setInvalidDecl();
}
#if 0
@@ -3817,9 +3905,9 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
if (getLangOptions().CPlusPlus)
CheckExtraCXXDefaultArguments(D);
- DeclaratorInfo *DInfo = 0;
+ TypeSourceInfo *TInfo = 0;
TagDecl *OwnedDecl = 0;
- QualType parmDeclType = GetTypeForDeclarator(D, S, &DInfo, &OwnedDecl);
+ QualType parmDeclType = GetTypeForDeclarator(D, S, &TInfo, &OwnedDecl);
if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) {
// C++ [dcl.fct]p6:
@@ -3862,7 +3950,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
ParmVarDecl *New
= ParmVarDecl::Create(Context, CurContext, D.getIdentifierLoc(), II,
- T, DInfo, StorageClass, 0);
+ T, TInfo, StorageClass, 0);
if (D.isInvalidType())
New->setInvalidDecl();
@@ -3960,6 +4048,50 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope,
return ActOnStartOfFunctionDef(FnBodyScope, DP);
}
+static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) {
+ // Don't warn about invalid declarations.
+ if (FD->isInvalidDecl())
+ return false;
+
+ // Or declarations that aren't global.
+ if (!FD->isGlobal())
+ return false;
+
+ // Don't warn about C++ member functions.
+ if (isa<CXXMethodDecl>(FD))
+ return false;
+
+ // Don't warn about 'main'.
+ if (FD->isMain())
+ return false;
+
+ // Don't warn about inline functions.
+ if (FD->isInlineSpecified())
+ return false;
+
+ // Don't warn about function templates.
+ if (FD->getDescribedFunctionTemplate())
+ return false;
+
+ // Don't warn about function template specializations.
+ if (FD->isFunctionTemplateSpecialization())
+ return false;
+
+ bool MissingPrototype = true;
+ for (const FunctionDecl *Prev = FD->getPreviousDeclaration();
+ Prev; Prev = Prev->getPreviousDeclaration()) {
+ // Ignore any declarations that occur in function or method
+ // scope, because they aren't visible from the header.
+ if (Prev->getDeclContext()->isFunctionOrMethod())
+ continue;
+
+ MissingPrototype = !Prev->getType()->isFunctionProtoType();
+ break;
+ }
+
+ return MissingPrototype;
+}
+
Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
// Clear the last template instantiation error context.
LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation();
@@ -4005,23 +4137,8 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
// prototype declaration. This warning is issued even if the
// definition itself provides a prototype. The aim is to detect
// global functions that fail to be declared in header files.
- if (!FD->isInvalidDecl() && FD->isGlobal() && !isa<CXXMethodDecl>(FD) &&
- !FD->isMain()) {
- bool MissingPrototype = true;
- for (const FunctionDecl *Prev = FD->getPreviousDeclaration();
- Prev; Prev = Prev->getPreviousDeclaration()) {
- // Ignore any declarations that occur in function or method
- // scope, because they aren't visible from the header.
- if (Prev->getDeclContext()->isFunctionOrMethod())
- continue;
-
- MissingPrototype = !Prev->getType()->isFunctionProtoType();
- break;
- }
-
- if (MissingPrototype)
- Diag(FD->getLocation(), diag::warn_missing_prototype) << FD;
- }
+ if (ShouldWarnAboutMissingPrototype(FD))
+ Diag(FD->getLocation(), diag::warn_missing_prototype) << FD;
if (FnBodyScope)
PushDeclContext(FnBodyScope, FD);
@@ -4090,11 +4207,8 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
if (!FD->isInvalidDecl())
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
- // C++ [basic.def.odr]p2:
- // [...] A virtual member function is used if it is not pure. [...]
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
- if (Method->isVirtual() && !Method->isPure())
- MarkDeclarationReferenced(Method->getLocation(), Method);
+ MaybeMarkVirtualMembersReferenced(Method->getLocation(), Method);
assert(FD == getCurFunctionDecl() && "Function parsing confused");
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
@@ -4301,20 +4415,20 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
}
TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
- DeclaratorInfo *DInfo) {
+ TypeSourceInfo *TInfo) {
assert(D.getIdentifier() && "Wrong callback for declspec without declarator");
assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
- if (!DInfo) {
+ if (!TInfo) {
assert(D.isInvalidType() && "no declarator info for valid type");
- DInfo = Context.getTrivialDeclaratorInfo(T);
+ TInfo = Context.getTrivialTypeSourceInfo(T);
}
// Scope manipulation handled by caller.
TypedefDecl *NewTD = TypedefDecl::Create(Context, CurContext,
D.getIdentifierLoc(),
D.getIdentifier(),
- DInfo);
+ TInfo);
if (const TagType *TT = T->getAs<TagType>()) {
TagDecl *TD = TT->getDecl();
@@ -4621,8 +4735,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
Previous.clear();
}
}
- } else if (TUK == TUK_Reference && SS.isEmpty() && Name &&
- (Kind != TagDecl::TK_enum || !getLangOptions().CPlusPlus)) {
+ } else if (TUK == TUK_Reference && SS.isEmpty() && Name) {
// C++ [basic.scope.pdecl]p5:
// -- for an elaborated-type-specifier of the form
//
@@ -4640,6 +4753,11 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// C99 6.7.2.3p8 has a similar (but not identical!) provision for
// C structs and unions.
//
+ // It is an error in C++ to declare (rather than define) an enum
+ // type, including via an elaborated type specifier. We'll
+ // diagnose that later; for now, declare the enum in the same
+ // scope as we would have picked for any other tag type.
+ //
// GNU C also supports this behavior as part of its incomplete
// enum types extension, while GNU C++ does not.
//
@@ -4739,10 +4857,7 @@ CreateNewDecl:
LookupResult Lookup(*this, Name, NameLoc, LookupOrdinaryName,
ForRedeclaration);
LookupName(Lookup, S);
- TypedefDecl *PrevTypedef = 0;
- if (NamedDecl *Prev = Lookup.getAsSingleDecl(Context))
- PrevTypedef = dyn_cast<TypedefDecl>(Prev);
-
+ TypedefDecl *PrevTypedef = Lookup.getAsSingle<TypedefDecl>();
NamedDecl *PrevTypedefNamed = PrevTypedef;
if (PrevTypedef && isDeclInScope(PrevTypedefNamed, SearchDC, S) &&
Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) !=
@@ -4947,8 +5062,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
SourceLocation Loc = DeclStart;
if (II) Loc = D.getIdentifierLoc();
- DeclaratorInfo *DInfo = 0;
- QualType T = GetTypeForDeclarator(D, S, &DInfo);
+ TypeSourceInfo *TInfo = 0;
+ QualType T = GetTypeForDeclarator(D, S, &TInfo);
if (getLangOptions().CPlusPlus)
CheckExtraCXXDefaultArguments(D);
@@ -4974,7 +5089,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
= (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable);
SourceLocation TSSL = D.getSourceRange().getBegin();
FieldDecl *NewFD
- = CheckFieldDecl(II, T, DInfo, Record, Loc, Mutable, BitWidth, TSSL,
+ = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, TSSL,
AS, PrevDecl, &D);
if (NewFD->isInvalidDecl() && PrevDecl) {
// Don't introduce NewFD into scope; there's already something
@@ -4998,7 +5113,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
///
/// \todo The Declarator argument is a hack. It will be removed once
FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
- DeclaratorInfo *DInfo,
+ TypeSourceInfo *TInfo,
RecordDecl *Record, SourceLocation Loc,
bool Mutable, Expr *BitWidth,
SourceLocation TSSL,
@@ -5015,9 +5130,14 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
T = Context.IntTy;
}
+ QualType EltTy = Context.getBaseElementType(T);
+ if (!EltTy->isDependentType() &&
+ RequireCompleteType(Loc, EltTy, diag::err_field_incomplete))
+ InvalidDecl = true;
+
// 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()) {
+ if (!InvalidDecl && T->isVariablyModifiedType()) {
bool SizeIsNegative;
QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context,
SizeIsNegative);
@@ -5034,20 +5154,22 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
}
// Fields can not have abstract class types
- if (RequireNonAbstractType(Loc, T, diag::err_abstract_type_in_decl,
- AbstractFieldType))
+ if (!InvalidDecl && RequireNonAbstractType(Loc, T,
+ diag::err_abstract_type_in_decl,
+ AbstractFieldType))
InvalidDecl = true;
bool ZeroWidth = false;
// If this is declared as a bit-field, check the bit-field.
- if (BitWidth && VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth)) {
+ if (!InvalidDecl && BitWidth &&
+ VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth)) {
InvalidDecl = true;
DeleteExpr(BitWidth);
BitWidth = 0;
ZeroWidth = false;
}
- FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, DInfo,
+ FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, TInfo,
BitWidth, Mutable);
if (InvalidDecl)
NewFD->setInvalidDecl();
@@ -5059,8 +5181,6 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
}
if (getLangOptions().CPlusPlus) {
- QualType EltTy = Context.getBaseElementType(T);
-
CXXRecordDecl* CXXRecord = cast<CXXRecordDecl>(Record);
if (!T->isPODType())
@@ -5296,8 +5416,8 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S,
// FIXME: Unnamed fields can be handled in various different ways, for
// example, unnamed unions inject all members into the struct namespace!
- DeclaratorInfo *DInfo = 0;
- QualType T = GetTypeForDeclarator(D, S, &DInfo);
+ TypeSourceInfo *TInfo = 0;
+ QualType T = GetTypeForDeclarator(D, S, &TInfo);
if (BitWidth) {
// 6.7.2.1p3, 6.7.2.1p4
@@ -5340,7 +5460,7 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S,
// Construct the decl.
ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context,
EnclosingContext, Loc, II, T,
- DInfo, ac, (Expr *)BitfieldWidth);
+ TInfo, ac, (Expr *)BitfieldWidth);
if (II) {
NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName,
@@ -5403,8 +5523,10 @@ void Sema::ActOnFields(Scope* S,
// If the field is already invalid for some reason, don't emit more
// diagnostics about it.
- if (FD->isInvalidDecl())
+ if (FD->isInvalidDecl()) {
+ EnclosingDecl->setInvalidDecl();
continue;
+ }
// C99 6.7.2.1p2:
// A structure or union shall not contain a member with
@@ -5540,7 +5662,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
llvm::APSInt EnumVal(32);
QualType EltTy;
if (Val) {
- if (Val->isTypeDependent())
+ if (Enum->isDependentType())
EltTy = Context.DependentTy;
else {
// Make sure to promote the operand type to int.
@@ -5552,8 +5674,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// C99 6.7.2.2p2: Make sure we have an integer constant expression.
SourceLocation ExpLoc;
- if (!Val->isValueDependent() &&
- VerifyIntegerConstantExpression(Val, &EnumVal)) {
+ if (VerifyIntegerConstantExpression(Val, &EnumVal)) {
Val = 0;
} else {
EltTy = Val->getType();
@@ -5562,7 +5683,9 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
}
if (!Val) {
- if (LastEnumConst) {
+ if (Enum->isDependentType())
+ EltTy = Context.DependentTy;
+ else if (LastEnumConst) {
// Assign the last value + 1.
EnumVal = LastEnumConst->getInitVal();
++EnumVal;
@@ -5576,6 +5699,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// First value, set to zero.
EltTy = Context.IntTy;
EnumVal.zextOrTrunc(static_cast<uint32_t>(Context.getTypeSize(EltTy)));
+ EnumVal.setIsSigned(true);
}
}
@@ -5647,6 +5771,19 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
if (Attr)
ProcessDeclAttributeList(S, Enum, Attr);
+ if (Enum->isDependentType()) {
+ for (unsigned i = 0; i != NumElements; ++i) {
+ EnumConstantDecl *ECD =
+ cast_or_null<EnumConstantDecl>(Elements[i].getAs<Decl>());
+ if (!ECD) continue;
+
+ ECD->setType(EnumType);
+ }
+
+ Enum->completeDefinition(Context, Context.DependentTy, Context.DependentTy);
+ return;
+ }
+
// TODO: If the result value doesn't fit in an int, it must be a long or long
// long value. ISO C does not support this, but GCC does as an extension,
// emit a warning.
@@ -5698,6 +5835,17 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
QualType BestType;
unsigned BestWidth;
+ // C++0x N3000 [conv.prom]p3:
+ // An rvalue of an unscoped enumeration type whose underlying
+ // type is not fixed can be converted to an rvalue of the first
+ // of the following types that can represent all the values of
+ // the enumeration: int, unsigned int, long int, unsigned long
+ // int, long long int, or unsigned long long int.
+ // C99 6.4.4.3p2:
+ // An identifier declared as an enumeration constant has type int.
+ // The C99 rule is modified by a gcc extension
+ QualType BestPromotionType;
+
bool Packed = Enum->getAttr<PackedAttr>() ? true : false;
if (NumNegativeBits) {
@@ -5705,22 +5853,21 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// int/long/longlong) that fits.
// If it's packed, check also if it fits a char or a short.
if (Packed && NumNegativeBits <= CharWidth && NumPositiveBits < CharWidth) {
- BestType = Context.SignedCharTy;
- BestWidth = CharWidth;
+ BestType = Context.SignedCharTy;
+ BestWidth = CharWidth;
} else if (Packed && NumNegativeBits <= ShortWidth &&
NumPositiveBits < ShortWidth) {
- BestType = Context.ShortTy;
- BestWidth = ShortWidth;
- }
- else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
+ BestType = Context.ShortTy;
+ BestWidth = ShortWidth;
+ } else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
BestType = Context.IntTy;
BestWidth = IntWidth;
} else {
BestWidth = Context.Target.getLongWidth();
- if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth)
+ if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) {
BestType = Context.LongTy;
- else {
+ } else {
BestWidth = Context.Target.getLongLongWidth();
if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth)
@@ -5728,31 +5875,46 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
BestType = Context.LongLongTy;
}
}
+ BestPromotionType = (BestWidth <= IntWidth ? Context.IntTy : BestType);
} else {
// If there is no negative value, figure out which of uint, ulong, ulonglong
// fits.
// If it's packed, check also if it fits a char or a short.
if (Packed && NumPositiveBits <= CharWidth) {
- BestType = Context.UnsignedCharTy;
- BestWidth = CharWidth;
+ BestType = Context.UnsignedCharTy;
+ BestPromotionType = Context.IntTy;
+ BestWidth = CharWidth;
} else if (Packed && NumPositiveBits <= ShortWidth) {
- BestType = Context.UnsignedShortTy;
- BestWidth = ShortWidth;
- }
- else if (NumPositiveBits <= IntWidth) {
+ BestType = Context.UnsignedShortTy;
+ BestPromotionType = Context.IntTy;
+ BestWidth = ShortWidth;
+ } else if (NumPositiveBits <= IntWidth) {
BestType = Context.UnsignedIntTy;
BestWidth = IntWidth;
+ BestPromotionType = (NumPositiveBits == BestWidth
+ ? Context.UnsignedIntTy : Context.IntTy);
} else if (NumPositiveBits <=
(BestWidth = Context.Target.getLongWidth())) {
BestType = Context.UnsignedLongTy;
+ BestPromotionType = (NumPositiveBits == BestWidth
+ ? Context.UnsignedLongTy : Context.LongTy);
} else {
BestWidth = Context.Target.getLongLongWidth();
assert(NumPositiveBits <= BestWidth &&
"How could an initializer get larger than ULL?");
BestType = Context.UnsignedLongLongTy;
+ BestPromotionType = (NumPositiveBits == BestWidth
+ ? Context.UnsignedLongLongTy : Context.LongLongTy);
}
}
+ // If we're in C and the promotion type is larger than an int, just
+ // use the underlying type, which is generally the unsigned integer
+ // type of the same rank as the promotion type. This is how the gcc
+ // extension works.
+ if (!getLangOptions().CPlusPlus && BestPromotionType != Context.IntTy)
+ BestPromotionType = BestType;
+
// Loop over all of the enumerator constants, changing their types to match
// the type of the enum if needed.
for (unsigned i = 0; i != NumElements; ++i) {
@@ -5765,19 +5927,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// enumerator value fits in an int, type it as an int, otherwise type it the
// same as the enumerator decl itself. This means that in "enum { X = 1U }"
// that X has type 'int', not 'unsigned'.
- if (ECD->getType() == Context.IntTy) {
- // Make sure the init value is signed.
- llvm::APSInt IV = ECD->getInitVal();
- IV.setIsSigned(true);
- ECD->setInitVal(IV);
-
- if (getLangOptions().CPlusPlus)
- // C++ [dcl.enum]p4: Following the closing brace of an
- // enum-specifier, each enumerator has the type of its
- // enumeration.
- ECD->setType(EnumType);
- continue; // Already int type.
- }
+ if (!getLangOptions().CPlusPlus && ECD->getType() == Context.IntTy)
+ continue;
// Determine whether the value fits into an int.
llvm::APSInt InitVal = ECD->getInitVal();
@@ -5792,7 +5943,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
QualType NewTy;
unsigned NewWidth;
bool NewSign;
- if (FitsInInt) {
+ if (FitsInInt && !getLangOptions().CPlusPlus) {
NewTy = Context.IntTy;
NewWidth = IntWidth;
NewSign = true;
@@ -5830,7 +5981,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
ECD->setType(NewTy);
}
- Enum->completeDefinition(Context, BestType);
+ Enum->completeDefinition(Context, BestType, BestPromotionType);
}
Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc,
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index b2124fe..84ee207 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -195,98 +195,13 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
QualType T = S.BuildExtVectorType(curType, S.Owned(sizeExpr), Attr.getLoc());
if (!T.isNull()) {
// FIXME: preserve the old source info.
- tDecl->setTypeDeclaratorInfo(S.Context.getTrivialDeclaratorInfo(T));
+ tDecl->setTypeSourceInfo(S.Context.getTrivialTypeSourceInfo(T));
// Remember this typedef decl, we will need it later for diagnostics.
S.ExtVectorDecls.push_back(tDecl);
}
}
-
-/// HandleVectorSizeAttribute - this attribute is only applicable to integral
-/// and float scalars, although arrays, pointers, and function return values are
-/// allowed in conjunction with this construct. Aggregates with this attribute
-/// are invalid, even if they are of the same size as a corresponding scalar.
-/// The raw attribute should contain precisely 1 argument, the vector size for
-/// the variable, measured in bytes. If curType and rawAttr are well formed,
-/// this routine will return a new vector type.
-static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
- QualType CurType;
- if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
- CurType = VD->getType();
- else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D))
- CurType = TD->getUnderlyingType();
- else {
- S.Diag(D->getLocation(), diag::err_attr_wrong_decl)
- << "vector_size" << SourceRange(Attr.getLoc(), Attr.getLoc());
- return;
- }
-
- // Check the attribute arugments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
- return;
- }
- Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0));
- llvm::APSInt vecSize(32);
- if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
- << "vector_size" << sizeExpr->getSourceRange();
- return;
- }
- // navigate to the base type - we need to provide for vector pointers, vector
- // arrays, and functions returning vectors.
- if (CurType->isPointerType() || CurType->isArrayType() ||
- CurType->isFunctionType()) {
- S.Diag(Attr.getLoc(), diag::err_unsupported_vector_size) << CurType;
- return;
- /* FIXME: rebuild the type from the inside out, vectorizing the inner type.
- do {
- if (PointerType *PT = dyn_cast<PointerType>(canonType))
- canonType = PT->getPointeeType().getTypePtr();
- else if (ArrayType *AT = dyn_cast<ArrayType>(canonType))
- canonType = AT->getElementType().getTypePtr();
- else if (FunctionType *FT = dyn_cast<FunctionType>(canonType))
- canonType = FT->getResultType().getTypePtr();
- } while (canonType->isPointerType() || canonType->isArrayType() ||
- canonType->isFunctionType());
- */
- }
- // 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;
- return;
- }
- unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType));
- // vecSize is specified in bytes - convert to bits.
- unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8);
-
- // the vector size needs to be an integral multiple of the type size.
- if (vectorSize % typeSize) {
- S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size)
- << sizeExpr->getSourceRange();
- return;
- }
- if (vectorSize == 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_zero_size)
- << sizeExpr->getSourceRange();
- return;
- }
-
- // Success! Instantiate the vector type, the number of elements is > 0, and
- // not required to be a power of 2, unlike GCC.
- CurType = S.Context.getVectorType(CurType, vectorSize/typeSize);
-
- if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
- VD->setType(CurType);
- else {
- // FIXME: preserve existing source info.
- DeclaratorInfo *DInfo = S.Context.getTrivialDeclaratorInfo(CurType);
- cast<TypedefDecl>(D)->setTypeDeclaratorInfo(DInfo);
- }
-}
-
static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() > 0) {
@@ -461,7 +376,8 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
if (!isFunctionOrMethod(d) && !isa<BlockDecl>(d)) {
ValueDecl *VD = dyn_cast<ValueDecl>(d);
- if (VD == 0 || !VD->getType()->isBlockPointerType()) {
+ if (VD == 0 || (!VD->getType()->isBlockPointerType()
+ && !VD->getType()->isFunctionPointerType())) {
S.Diag(Attr.getLoc(),
Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
: diag::warn_attribute_wrong_decl_type)
@@ -1143,10 +1059,6 @@ static void HandlePureAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // Match gcc which ignores cleanup attrs when compiling C++.
- if (S.getLangOptions().CPlusPlus)
- return;
-
if (!Attr.getParameterName()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
@@ -1709,7 +1621,7 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// Install the new type.
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
// FIXME: preserve existing source info.
- TD->setTypeDeclaratorInfo(S.Context.getTrivialDeclaratorInfo(NewTy));
+ TD->setTypeSourceInfo(S.Context.getTrivialTypeSourceInfo(NewTy));
} else
cast<ValueDecl>(D)->setType(NewTy);
}
@@ -1964,6 +1876,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_IBOutlet: HandleIBOutletAttr (D, Attr, S); break;
case AttributeList::AT_address_space:
case AttributeList::AT_objc_gc:
+ case AttributeList::AT_vector_size:
// Ignore these, these are type attributes, handled by
// ProcessTypeAttributes.
break;
@@ -2013,7 +1926,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break;
case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break;
case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break;
- case AttributeList::AT_vector_size: HandleVectorSizeAttr (D, Attr, S); break;
case AttributeList::AT_visibility: HandleVisibilityAttr (D, Attr, S); break;
case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S);
break;
@@ -2062,11 +1974,11 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(),
FD->getLocation(), DeclarationName(II),
- FD->getType(), FD->getDeclaratorInfo());
+ FD->getType(), FD->getTypeSourceInfo());
} else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) {
NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
VD->getLocation(), II,
- VD->getType(), VD->getDeclaratorInfo(),
+ VD->getType(), VD->getTypeSourceInfo(),
VD->getStorageClass());
}
return NewD;
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index f161cb5..228a716 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -12,11 +12,14 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "SemaInit.h"
#include "Lookup.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Parse/DeclSpec.h"
@@ -482,24 +485,47 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
assert(BaseDecl && "Base type is not incomplete, but has no definition");
CXXRecordDecl * CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl);
assert(CXXBaseDecl && "Base type is not a C++ type");
- if (!CXXBaseDecl->isEmpty())
- Class->setEmpty(false);
- if (CXXBaseDecl->isPolymorphic())
- Class->setPolymorphic(true);
+
// C++0x CWG Issue #817 indicates that [[final]] classes shouldn't be bases.
if (CXXBaseDecl->hasAttr<FinalAttr>()) {
Diag(BaseLoc, diag::err_final_base) << BaseType.getAsString();
- Diag(CXXBaseDecl->getLocation(), diag::note_previous_class_decl)
- << BaseType.getAsString();
+ Diag(CXXBaseDecl->getLocation(), diag::note_previous_decl)
+ << BaseType;
return 0;
}
+ SetClassDeclAttributesFromBase(Class, CXXBaseDecl, Virtual);
+
+ // Create the base specifier.
+ // FIXME: Allocate via ASTContext?
+ return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
+ Class->getTagKind() == RecordDecl::TK_class,
+ Access, BaseType);
+}
+
+void Sema::SetClassDeclAttributesFromBase(CXXRecordDecl *Class,
+ const CXXRecordDecl *BaseClass,
+ bool BaseIsVirtual) {
+ // A class with a non-empty base class is not empty.
+ // FIXME: Standard ref?
+ if (!BaseClass->isEmpty())
+ Class->setEmpty(false);
+
+ // C++ [class.virtual]p1:
+ // A class that [...] inherits a virtual function is called a polymorphic
+ // class.
+ if (BaseClass->isPolymorphic())
+ Class->setPolymorphic(true);
+
// C++ [dcl.init.aggr]p1:
// An aggregate is [...] a class with [...] no base classes [...].
Class->setAggregate(false);
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class...
Class->setPOD(false);
- if (Virtual) {
+ if (BaseIsVirtual) {
// C++ [class.ctor]p5:
// A constructor is trivial if its class has no virtual base classes.
Class->setHasTrivialConstructor(false);
@@ -521,33 +547,27 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
// C++ [class.ctor]p5:
// A constructor is trivial if all the direct base classes of its
// class have trivial constructors.
- if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialConstructor())
+ if (!BaseClass->hasTrivialConstructor())
Class->setHasTrivialConstructor(false);
// C++ [class.copy]p6:
// A copy constructor is trivial if all the direct base classes of its
// class have trivial copy constructors.
- if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyConstructor())
+ if (!BaseClass->hasTrivialCopyConstructor())
Class->setHasTrivialCopyConstructor(false);
// C++ [class.copy]p11:
// A copy assignment operator is trivial if all the direct base classes
// of its class have trivial copy assignment operators.
- if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyAssignment())
+ if (!BaseClass->hasTrivialCopyAssignment())
Class->setHasTrivialCopyAssignment(false);
}
// C++ [class.ctor]p3:
// A destructor is trivial if all the direct base classes of its class
// have trivial destructors.
- if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialDestructor())
+ if (!BaseClass->hasTrivialDestructor())
Class->setHasTrivialDestructor(false);
-
- // Create the base specifier.
- // FIXME: Allocate via ASTContext?
- return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
- Class->getTagKind() == RecordDecl::TK_class,
- Access, BaseType);
}
/// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is
@@ -976,19 +996,26 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
if (Member)
return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
- RParenLoc);
+ LParenLoc, RParenLoc);
}
// It didn't name a member, so see if it names a class.
- TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy
- : getTypeName(*MemberOrBase, IdLoc, S, &SS);
- if (!BaseTy)
+ QualType BaseType;
+
+ TypeSourceInfo *TInfo = 0;
+ if (TemplateTypeTy)
+ BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo);
+ else
+ BaseType = QualType::getFromOpaquePtr(getTypeName(*MemberOrBase, IdLoc,
+ S, &SS));
+ if (BaseType.isNull())
return Diag(IdLoc, diag::err_mem_init_not_member_or_class)
<< MemberOrBase << SourceRange(IdLoc, RParenLoc);
- QualType BaseType = GetTypeFromParser(BaseTy);
+ if (!TInfo)
+ TInfo = Context.getTrivialTypeSourceInfo(BaseType, IdLoc);
- return BuildBaseInitializer(BaseType, (Expr **)Args, NumArgs, IdLoc,
- RParenLoc, ClassDecl);
+ return BuildBaseInitializer(BaseType, TInfo, (Expr **)Args, NumArgs,
+ LParenLoc, RParenLoc, ClassDecl);
}
/// Checks an initializer expression for use of uninitialized fields, such as
@@ -1037,6 +1064,7 @@ static bool InitExprContainsUninitializedFields(const Stmt* S,
Sema::MemInitResult
Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
unsigned NumArgs, SourceLocation IdLoc,
+ SourceLocation LParenLoc,
SourceLocation RParenLoc) {
// FIXME: CXXBaseOrMemberInitializer should only contain a single
// subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
@@ -1081,7 +1109,8 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
NumArgs),
IdLoc,
SourceRange(IdLoc, RParenLoc),
- Member->getDeclName(), IK_Direct,
+ Member->getDeclName(),
+ InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc),
ConstructorArgs);
if (C) {
@@ -1118,22 +1147,25 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
ExprTemporaries.clear();
// FIXME: Perform direct initialization of the member.
- return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args,
- NumArgs, C, IdLoc, RParenLoc);
+ return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc,
+ C, LParenLoc, (Expr **)Args,
+ NumArgs, RParenLoc);
}
Sema::MemInitResult
-Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
- unsigned NumArgs, SourceLocation IdLoc,
- SourceLocation RParenLoc, CXXRecordDecl *ClassDecl) {
+Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation LParenLoc, SourceLocation RParenLoc,
+ CXXRecordDecl *ClassDecl) {
bool HasDependentArg = false;
for (unsigned i = 0; i < NumArgs; i++)
HasDependentArg |= Args[i]->isTypeDependent();
+ SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getSourceRange().getBegin();
if (!BaseType->isDependentType()) {
if (!BaseType->isRecordType())
- return Diag(IdLoc, diag::err_base_init_does_not_name_class)
- << BaseType << SourceRange(IdLoc, RParenLoc);
+ return Diag(BaseLoc, diag::err_base_init_does_not_name_class)
+ << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
// C++ [class.base.init]p2:
// [...] Unless the mem-initializer-id names a nonstatic data
@@ -1179,16 +1211,16 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
// a direct non-virtual base class and an inherited virtual base
// class, the mem-initializer is ill-formed.
if (DirectBaseSpec && VirtualBaseSpec)
- return Diag(IdLoc, diag::err_base_init_direct_and_virtual)
- << BaseType << SourceRange(IdLoc, RParenLoc);
+ return Diag(BaseLoc, diag::err_base_init_direct_and_virtual)
+ << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
// C++ [base.class.init]p2:
// Unless the mem-initializer-id names a nonstatic data membeer of the
// constructor's class ot a direst or virtual base of that class, the
// mem-initializer is ill-formed.
if (!DirectBaseSpec && !VirtualBaseSpec)
- return Diag(IdLoc, diag::err_not_direct_base_or_virtual)
- << BaseType << ClassDecl->getNameAsCString()
- << SourceRange(IdLoc, RParenLoc);
+ return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
+ << BaseType << ClassDecl->getNameAsCString()
+ << BaseTInfo->getTypeLoc().getSourceRange();
}
CXXConstructorDecl *C = 0;
@@ -1200,8 +1232,10 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
C = PerformInitializationByConstructor(BaseType,
MultiExprArg(*this,
(void**)Args, NumArgs),
- IdLoc, SourceRange(IdLoc, RParenLoc),
- Name, IK_Direct,
+ BaseLoc,
+ SourceRange(BaseLoc, RParenLoc),
+ Name,
+ InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc),
ConstructorArgs);
if (C) {
// Take over the constructor arguments as our own.
@@ -1214,8 +1248,9 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
// subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
ExprTemporaries.clear();
- return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args,
- NumArgs, C, IdLoc, RParenLoc);
+ return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, C,
+ LParenLoc, (Expr **)Args,
+ NumArgs, RParenLoc);
}
bool
@@ -1277,14 +1312,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
}
else {
CXXRecordDecl *VBaseDecl =
- cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
assert(VBaseDecl && "SetBaseOrMemberInitializers - VBaseDecl null");
CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context);
if (!Ctor) {
Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
<< 0 << VBase->getType();
- Diag(VBaseDecl->getLocation(), diag::note_previous_class_decl)
+ Diag(VBaseDecl->getLocation(), diag::note_previous_decl)
<< Context.getTagDeclType(VBaseDecl);
HadError = true;
continue;
@@ -1298,13 +1333,18 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
// FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
+ // subexpression so we can wrap it in a CXXExprWithTemporaries if
+ // necessary.
+ // FIXME: Is there any better source-location information we can give?
ExprTemporaries.clear();
CXXBaseOrMemberInitializer *Member =
- new (Context) CXXBaseOrMemberInitializer(VBase->getType(),
- CtorArgs.takeAs<Expr>(),
- CtorArgs.size(), Ctor,
+ new (Context) CXXBaseOrMemberInitializer(Context,
+ Context.getTrivialTypeSourceInfo(VBase->getType(),
+ SourceLocation()),
+ Ctor,
SourceLocation(),
+ CtorArgs.takeAs<Expr>(),
+ CtorArgs.size(),
SourceLocation());
AllToInit.push_back(Member);
}
@@ -1332,7 +1372,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
<< 0 << Base->getType();
- Diag(BaseDecl->getLocation(), diag::note_previous_class_decl)
+ Diag(BaseDecl->getLocation(), diag::note_previous_decl)
<< Context.getTagDeclType(BaseDecl);
HadError = true;
continue;
@@ -1346,13 +1386,18 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
// FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
+ // subexpression so we can wrap it in a CXXExprWithTemporaries if
+ // necessary.
+ // FIXME: Is there any better source-location information we can give?
ExprTemporaries.clear();
CXXBaseOrMemberInitializer *Member =
- new (Context) CXXBaseOrMemberInitializer(Base->getType(),
- CtorArgs.takeAs<Expr>(),
- CtorArgs.size(), Ctor,
+ new (Context) CXXBaseOrMemberInitializer(Context,
+ Context.getTrivialTypeSourceInfo(Base->getType(),
+ SourceLocation()),
+ Ctor,
SourceLocation(),
+ CtorArgs.takeAs<Expr>(),
+ CtorArgs.size(),
SourceLocation());
AllToInit.push_back(Member);
}
@@ -1399,7 +1444,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
<< 1 << (*Field)->getDeclName();
Diag(Field->getLocation(), diag::note_field_decl);
- Diag(RT->getDecl()->getLocation(), diag::note_previous_class_decl)
+ Diag(RT->getDecl()->getLocation(), diag::note_previous_decl)
<< Context.getTagDeclType(RT->getDecl());
HadError = true;
continue;
@@ -1427,9 +1472,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
// subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
ExprTemporaries.clear();
CXXBaseOrMemberInitializer *Member =
- new (Context) CXXBaseOrMemberInitializer(*Field,CtorArgs.takeAs<Expr>(),
- CtorArgs.size(), Ctor,
+ new (Context) CXXBaseOrMemberInitializer(Context,
+ *Field, SourceLocation(),
+ Ctor,
SourceLocation(),
+ CtorArgs.takeAs<Expr>(),
+ CtorArgs.size(),
SourceLocation());
AllToInit.push_back(Member);
@@ -1537,13 +1585,15 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
if (FieldDecl *Field = Member->getMember())
Diag(Member->getSourceLocation(),
diag::error_multiple_mem_initialization)
- << Field->getNameAsString();
+ << 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);
+ << QualType(BaseClass, 0)
+ << Member->getSourceRange();
}
Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
<< 0;
@@ -1920,6 +1970,28 @@ 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) {
+ if (!Record || Record->isInvalidDecl())
+ return;
+
+ if (!Record->isAbstract()) {
+ // Collect all the pure virtual methods and see if this is an abstract
+ // class after all.
+ PureVirtualMethodCollector Collector(Context, Record);
+ if (!Collector.empty())
+ Record->setAbstract(true);
+ }
+
+ if (Record->isAbstract())
+ (void)AbstractClassUsageDiagnoser(*this, Record);
+
+ if (!Record->isDependentType() && !Record->isInvalidDecl())
+ AddImplicitlyDeclaredMembersToClass(Record);
+}
+
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclPtrTy TagDecl,
SourceLocation LBrac,
@@ -1928,24 +2000,13 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
return;
AdjustDeclIfTemplate(TagDecl);
+
ActOnFields(S, RLoc, TagDecl,
(DeclPtrTy*)FieldCollector->getCurFields(),
FieldCollector->getCurNumFields(), LBrac, RBrac, 0);
- CXXRecordDecl *RD = cast<CXXRecordDecl>(TagDecl.getAs<Decl>());
- if (!RD->isAbstract()) {
- // Collect all the pure virtual methods and see if this is an abstract
- // class after all.
- PureVirtualMethodCollector Collector(Context, RD);
- if (!Collector.empty())
- RD->setAbstract(true);
- }
-
- if (RD->isAbstract())
- (void)AbstractClassUsageDiagnoser(*this, RD);
-
- if (!RD->isDependentType() && !RD->isInvalidDecl())
- AddImplicitlyDeclaredMembersToClass(RD);
+ CheckCompletedCXXClass(
+ dyn_cast_or_null<CXXRecordDecl>(TagDecl.getAs<Decl>()));
}
/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
@@ -1974,7 +2035,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
ClassDecl->getLocation(), Name,
Context.getFunctionType(Context.VoidTy,
0, 0, false, 0),
- /*DInfo=*/0,
+ /*TInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
@@ -2046,7 +2107,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
Context.getFunctionType(Context.VoidTy,
&ArgType, 1,
false, 0),
- /*DInfo=*/0,
+ /*TInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
@@ -2058,7 +2119,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
ClassDecl->getLocation(),
/*IdentifierInfo=*/0,
- ArgType, /*DInfo=*/0,
+ ArgType, /*TInfo=*/0,
VarDecl::None, 0);
CopyConstructor->setParams(Context, &FromParam, 1);
ClassDecl->addDecl(CopyConstructor);
@@ -2132,7 +2193,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name,
Context.getFunctionType(RetType, &ArgType, 1,
false, 0),
- /*DInfo=*/0, /*isStatic=*/false, /*isInline=*/true);
+ /*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true);
CopyAssignment->setAccess(AS_public);
CopyAssignment->setImplicit();
CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
@@ -2142,13 +2203,14 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
ClassDecl->getLocation(),
/*IdentifierInfo=*/0,
- ArgType, /*DInfo=*/0,
+ ArgType, /*TInfo=*/0,
VarDecl::None, 0);
CopyAssignment->setParams(Context, &FromParam, 1);
// Don't call addedAssignmentOperator. There is no way to distinguish an
// implicit from an explicit assignment operator.
ClassDecl->addDecl(CopyAssignment);
+ AddOverriddenMethods(ClassDecl, CopyAssignment);
}
if (!ClassDecl->hasUserDeclaredDestructor()) {
@@ -2814,6 +2876,7 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) {
Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
AccessSpecifier AS,
+ bool HasUsingKeyword,
SourceLocation UsingLoc,
const CXXScopeSpec &SS,
UnqualifiedId &Name,
@@ -2830,6 +2893,9 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
break;
case UnqualifiedId::IK_ConstructorName:
+ // C++0x inherited constructors.
+ if (getLangOptions().CPlusPlus0x) break;
+
Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_constructor)
<< SS.getRange();
return DeclPtrTy();
@@ -2846,45 +2912,237 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
}
DeclarationName TargetName = GetNameFromUnqualifiedId(Name);
+ if (!TargetName)
+ return DeclPtrTy();
+
+ // Warn about using declarations.
+ // TODO: store that the declaration was written without 'using' and
+ // talk about access decls instead of using decls in the
+ // diagnostics.
+ if (!HasUsingKeyword) {
+ UsingLoc = Name.getSourceRange().getBegin();
+
+ Diag(UsingLoc, diag::warn_access_decl_deprecated)
+ << CodeModificationHint::CreateInsertion(SS.getRange().getBegin(),
+ "using ");
+ }
+
NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS,
Name.getSourceRange().getBegin(),
TargetName, AttrList,
/* IsInstantiation */ false,
IsTypeName, TypenameLoc);
- if (UD) {
- PushOnScopeChains(UD, S);
- UD->setAccess(AS);
- }
+ if (UD)
+ PushOnScopeChains(UD, S, /*AddToContext*/ false);
return DeclPtrTy::make(UD);
}
+/// Determines whether to create a using shadow decl for a particular
+/// decl, given the set of decls existing prior to this using lookup.
+bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
+ const LookupResult &Previous) {
+ // Diagnose finding a decl which is not from a base class of the
+ // current class. We do this now because there are cases where this
+ // function will silently decide not to build a shadow decl, which
+ // will pre-empt further diagnostics.
+ //
+ // We don't need to do this in C++0x because we do the check once on
+ // the qualifier.
+ //
+ // FIXME: diagnose the following if we care enough:
+ // struct A { int foo; };
+ // struct B : A { using A::foo; };
+ // template <class T> struct C : A {};
+ // template <class T> struct D : C<T> { using B::foo; } // <---
+ // This is invalid (during instantiation) in C++03 because B::foo
+ // resolves to the using decl in B, which is not a base class of D<T>.
+ // We can't diagnose it immediately because C<T> is an unknown
+ // specialization. The UsingShadowDecl in D<T> then points directly
+ // to A::foo, which will look well-formed when we instantiate.
+ // The right solution is to not collapse the shadow-decl chain.
+ if (!getLangOptions().CPlusPlus0x && CurContext->isRecord()) {
+ DeclContext *OrigDC = Orig->getDeclContext();
+
+ // Handle enums and anonymous structs.
+ if (isa<EnumDecl>(OrigDC)) OrigDC = OrigDC->getParent();
+ CXXRecordDecl *OrigRec = cast<CXXRecordDecl>(OrigDC);
+ while (OrigRec->isAnonymousStructOrUnion())
+ OrigRec = cast<CXXRecordDecl>(OrigRec->getDeclContext());
+
+ if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(OrigRec)) {
+ if (OrigDC == CurContext) {
+ Diag(Using->getLocation(),
+ diag::err_using_decl_nested_name_specifier_is_current_class)
+ << Using->getNestedNameRange();
+ Diag(Orig->getLocation(), diag::note_using_decl_target);
+ return true;
+ }
+
+ Diag(Using->getNestedNameRange().getBegin(),
+ diag::err_using_decl_nested_name_specifier_is_not_base_class)
+ << Using->getTargetNestedNameDecl()
+ << cast<CXXRecordDecl>(CurContext)
+ << Using->getNestedNameRange();
+ Diag(Orig->getLocation(), diag::note_using_decl_target);
+ return true;
+ }
+ }
+
+ if (Previous.empty()) return false;
+
+ NamedDecl *Target = Orig;
+ if (isa<UsingShadowDecl>(Target))
+ Target = cast<UsingShadowDecl>(Target)->getTargetDecl();
+
+ // If the target happens to be one of the previous declarations, we
+ // don't have a conflict.
+ //
+ // FIXME: but we might be increasing its access, in which case we
+ // should redeclare it.
+ NamedDecl *NonTag = 0, *Tag = 0;
+ for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
+ I != E; ++I) {
+ NamedDecl *D = (*I)->getUnderlyingDecl();
+ if (D->getCanonicalDecl() == Target->getCanonicalDecl())
+ return false;
+
+ (isa<TagDecl>(D) ? Tag : NonTag) = D;
+ }
+
+ if (Target->isFunctionOrFunctionTemplate()) {
+ FunctionDecl *FD;
+ if (isa<FunctionTemplateDecl>(Target))
+ FD = cast<FunctionTemplateDecl>(Target)->getTemplatedDecl();
+ else
+ FD = cast<FunctionDecl>(Target);
+
+ NamedDecl *OldDecl = 0;
+ switch (CheckOverload(FD, Previous, OldDecl)) {
+ case Ovl_Overload:
+ return false;
+
+ case Ovl_NonFunction:
+ Diag(Using->getLocation(), diag::err_using_decl_conflict);
+ break;
+
+ // We found a decl with the exact signature.
+ case Ovl_Match:
+ if (isa<UsingShadowDecl>(OldDecl)) {
+ // Silently ignore the possible conflict.
+ return false;
+ }
+
+ // If we're in a record, we want to hide the target, so we
+ // return true (without a diagnostic) to tell the caller not to
+ // build a shadow decl.
+ if (CurContext->isRecord())
+ return true;
+
+ // If we're not in a record, this is an error.
+ Diag(Using->getLocation(), diag::err_using_decl_conflict);
+ break;
+ }
+
+ Diag(Target->getLocation(), diag::note_using_decl_target);
+ Diag(OldDecl->getLocation(), diag::note_using_decl_conflict);
+ return true;
+ }
+
+ // Target is not a function.
+
+ if (isa<TagDecl>(Target)) {
+ // No conflict between a tag and a non-tag.
+ if (!Tag) return false;
+
+ Diag(Using->getLocation(), diag::err_using_decl_conflict);
+ Diag(Target->getLocation(), diag::note_using_decl_target);
+ Diag(Tag->getLocation(), diag::note_using_decl_conflict);
+ return true;
+ }
+
+ // No conflict between a tag and a non-tag.
+ if (!NonTag) return false;
+
+ Diag(Using->getLocation(), diag::err_using_decl_conflict);
+ Diag(Target->getLocation(), diag::note_using_decl_target);
+ Diag(NonTag->getLocation(), diag::note_using_decl_conflict);
+ return true;
+}
+
/// Builds a shadow declaration corresponding to a 'using' declaration.
-static UsingShadowDecl *BuildUsingShadowDecl(Sema &SemaRef, Scope *S,
- AccessSpecifier AS,
- UsingDecl *UD, NamedDecl *Orig) {
- // FIXME: diagnose hiding, collisions
+UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
+ UsingDecl *UD,
+ NamedDecl *Orig) {
// If we resolved to another shadow declaration, just coalesce them.
- if (isa<UsingShadowDecl>(Orig)) {
- Orig = cast<UsingShadowDecl>(Orig)->getTargetDecl();
- assert(!isa<UsingShadowDecl>(Orig) && "nested shadow declaration");
+ NamedDecl *Target = Orig;
+ if (isa<UsingShadowDecl>(Target)) {
+ Target = cast<UsingShadowDecl>(Target)->getTargetDecl();
+ assert(!isa<UsingShadowDecl>(Target) && "nested shadow declaration");
}
UsingShadowDecl *Shadow
- = UsingShadowDecl::Create(SemaRef.Context, SemaRef.CurContext,
- UD->getLocation(), UD, Orig);
+ = UsingShadowDecl::Create(Context, CurContext,
+ UD->getLocation(), UD, Target);
UD->addShadowDecl(Shadow);
if (S)
- SemaRef.PushOnScopeChains(Shadow, S);
+ PushOnScopeChains(Shadow, S);
else
- SemaRef.CurContext->addDecl(Shadow);
- Shadow->setAccess(AS);
+ CurContext->addDecl(Shadow);
+ Shadow->setAccess(UD->getAccess());
+
+ if (Orig->isInvalidDecl() || UD->isInvalidDecl())
+ Shadow->setInvalidDecl();
return Shadow;
}
+/// Hides a using shadow declaration. This is required by the current
+/// using-decl implementation when a resolvable using declaration in a
+/// class is followed by a declaration which would hide or override
+/// one or more of the using decl's targets; for example:
+///
+/// struct Base { void foo(int); };
+/// struct Derived : Base {
+/// using Base::foo;
+/// void foo(int);
+/// };
+///
+/// The governing language is C++03 [namespace.udecl]p12:
+///
+/// When a using-declaration brings names from a base class into a
+/// derived class scope, member functions in the derived class
+/// override and/or hide member functions with the same name and
+/// parameter types in a base class (rather than conflicting).
+///
+/// There are two ways to implement this:
+/// (1) optimistically create shadow decls when they're not hidden
+/// by existing declarations, or
+/// (2) don't create any shadow decls (or at least don't make them
+/// visible) until we've fully parsed/instantiated the class.
+/// The problem with (1) is that we might have to retroactively remove
+/// a shadow decl, which requires several O(n) operations because the
+/// decl structures are (very reasonably) not designed for removal.
+/// (2) avoids this but is very fiddly and phase-dependent.
+void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {
+ // Remove it from the DeclContext...
+ Shadow->getDeclContext()->removeDecl(Shadow);
+
+ // ...and the scope, if applicable...
+ if (S) {
+ S->RemoveDecl(DeclPtrTy::make(static_cast<Decl*>(Shadow)));
+ IdResolver.RemoveDecl(Shadow);
+ }
+
+ // ...and the using decl.
+ Shadow->getUsingDecl()->removeShadowDecl(Shadow);
+
+ // TODO: complain somehow if Shadow was used. It shouldn't
+ // be possible for this to happen, because
+}
+
/// Builds a using declaration.
///
/// \param IsInstantiation - Whether this call arises from an
@@ -2910,56 +3168,76 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
return 0;
}
+ // Do the redeclaration lookup in the current scope.
+ LookupResult Previous(*this, Name, IdentLoc, LookupUsingDeclName,
+ ForRedeclaration);
+ Previous.setHideTags(false);
+ if (S) {
+ LookupName(Previous, S);
+
+ // It is really dumb that we have to do this.
+ LookupResult::Filter F = Previous.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (!isDeclInScope(D, CurContext, S))
+ F.erase();
+ }
+ F.done();
+ } else {
+ assert(IsInstantiation && "no scope in non-instantiation");
+ assert(CurContext->isRecord() && "scope not record in instantiation");
+ LookupQualifiedName(Previous, CurContext);
+ }
+
NestedNameSpecifier *NNS =
static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ // Check for invalid redeclarations.
+ if (CheckUsingDeclRedeclaration(UsingLoc, IsTypeName, SS, IdentLoc, Previous))
+ return 0;
+
+ // Check for bad qualifiers.
+ if (CheckUsingDeclQualifier(UsingLoc, SS, IdentLoc))
+ return 0;
+
DeclContext *LookupContext = computeDeclContext(SS);
+ NamedDecl *D;
if (!LookupContext) {
if (IsTypeName) {
- return UnresolvedUsingTypenameDecl::Create(Context, CurContext,
- UsingLoc, TypenameLoc,
- SS.getRange(), NNS,
- IdentLoc, Name);
- } else {
- return UnresolvedUsingValueDecl::Create(Context, CurContext,
- UsingLoc, SS.getRange(), NNS,
+ // FIXME: not all declaration name kinds are legal here
+ D = UnresolvedUsingTypenameDecl::Create(Context, CurContext,
+ UsingLoc, TypenameLoc,
+ SS.getRange(), NNS,
IdentLoc, Name);
+ } else {
+ D = UnresolvedUsingValueDecl::Create(Context, CurContext,
+ UsingLoc, SS.getRange(), NNS,
+ IdentLoc, Name);
}
+ } else {
+ D = UsingDecl::Create(Context, CurContext, IdentLoc,
+ SS.getRange(), UsingLoc, NNS, Name,
+ IsTypeName);
}
+ D->setAccess(AS);
+ CurContext->addDecl(D);
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(CurContext)) {
- // C++0x N2914 [namespace.udecl]p3:
- // A using-declaration used as a member-declaration shall refer to a member
- // of a base class of the class being defined, shall refer to a member of an
- // anonymous union that is a member of a base class of the class being
- // defined, or shall refer to an enumerator for an enumeration type that is
- // a member of a base class of the class being defined.
-
- CXXRecordDecl *LookupRD = dyn_cast<CXXRecordDecl>(LookupContext);
- if (!LookupRD || !RD->isDerivedFrom(LookupRD)) {
- Diag(SS.getRange().getBegin(),
- diag::err_using_decl_nested_name_specifier_is_not_a_base_class)
- << NNS << RD->getDeclName();
- return 0;
- }
- } else {
- // C++0x N2914 [namespace.udecl]p8:
- // A using-declaration for a class member shall be a member-declaration.
- if (isa<CXXRecordDecl>(LookupContext)) {
- Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_class_member)
- << SS.getRange();
- return 0;
- }
+ if (!LookupContext) return D;
+ UsingDecl *UD = cast<UsingDecl>(D);
+
+ if (RequireCompleteDeclContext(SS)) {
+ UD->setInvalidDecl();
+ return UD;
}
- // Look up the target name. Unlike most lookups, we do not want to
- // hide tag declarations: tag names are visible through the using
- // declaration even if hidden by ordinary names.
+ // Look up the target name.
+
LookupResult R(*this, Name, IdentLoc, LookupOrdinaryName);
- // We don't hide tags behind ordinary decls if we're in a
- // non-dependent context, but in a dependent context, this is
- // important for the stability of two-phase lookup.
+ // Unlike most lookups, we don't always want to hide tag
+ // declarations: tag names are visible through the using declaration
+ // even if hidden by ordinary names, *except* in a dependent context
+ // where it's important for the sanity of two-phase lookup.
if (!IsInstantiation)
R.setHideTags(false);
@@ -2968,54 +3246,243 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
if (R.empty()) {
Diag(IdentLoc, diag::err_no_member)
<< Name << LookupContext << SS.getRange();
- return 0;
+ UD->setInvalidDecl();
+ return UD;
}
- if (R.isAmbiguous())
- return 0;
+ if (R.isAmbiguous()) {
+ UD->setInvalidDecl();
+ return UD;
+ }
if (IsTypeName) {
// If we asked for a typename and got a non-type decl, error out.
- if (R.getResultKind() != LookupResult::Found
- || !isa<TypeDecl>(R.getFoundDecl())) {
+ if (!R.getAsSingle<TypeDecl>()) {
Diag(IdentLoc, diag::err_using_typename_non_type);
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
Diag((*I)->getUnderlyingDecl()->getLocation(),
diag::note_using_decl_target);
- return 0;
+ UD->setInvalidDecl();
+ return UD;
}
} else {
// If we asked for a non-typename and we got a type, error out,
// but only if this is an instantiation of an unresolved using
// decl. Otherwise just silently find the type name.
- if (IsInstantiation &&
- R.getResultKind() == LookupResult::Found &&
- isa<TypeDecl>(R.getFoundDecl())) {
+ if (IsInstantiation && R.getAsSingle<TypeDecl>()) {
Diag(IdentLoc, diag::err_using_dependent_value_is_type);
Diag(R.getFoundDecl()->getLocation(), diag::note_using_decl_target);
- return 0;
+ UD->setInvalidDecl();
+ return UD;
}
}
// C++0x N2914 [namespace.udecl]p6:
// A using-declaration shall not name a namespace.
- if (R.getResultKind() == LookupResult::Found
- && isa<NamespaceDecl>(R.getFoundDecl())) {
+ if (R.getAsSingle<NamespaceDecl>()) {
Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace)
<< SS.getRange();
- return 0;
+ UD->setInvalidDecl();
+ return UD;
}
- UsingDecl *UD = UsingDecl::Create(Context, CurContext, IdentLoc,
- SS.getRange(), UsingLoc, NNS, Name,
- IsTypeName);
-
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- BuildUsingShadowDecl(*this, S, AS, UD, *I);
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ if (!CheckUsingShadowDecl(UD, *I, Previous))
+ BuildUsingShadowDecl(S, UD, *I);
+ }
return UD;
}
+/// Checks that the given using declaration is not an invalid
+/// redeclaration. Note that this is checking only for the using decl
+/// itself, not for any ill-formedness among the UsingShadowDecls.
+bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
+ bool isTypeName,
+ const CXXScopeSpec &SS,
+ SourceLocation NameLoc,
+ const LookupResult &Prev) {
+ // C++03 [namespace.udecl]p8:
+ // C++0x [namespace.udecl]p10:
+ // A using-declaration is a declaration and can therefore be used
+ // repeatedly where (and only where) multiple declarations are
+ // allowed.
+ // That's only in file contexts.
+ if (CurContext->getLookupContext()->isFileContext())
+ return false;
+
+ NestedNameSpecifier *Qual
+ = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+
+ for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) {
+ NamedDecl *D = *I;
+
+ bool DTypename;
+ NestedNameSpecifier *DQual;
+ if (UsingDecl *UD = dyn_cast<UsingDecl>(D)) {
+ DTypename = UD->isTypeName();
+ DQual = UD->getTargetNestedNameDecl();
+ } else if (UnresolvedUsingValueDecl *UD
+ = dyn_cast<UnresolvedUsingValueDecl>(D)) {
+ DTypename = false;
+ DQual = UD->getTargetNestedNameSpecifier();
+ } else if (UnresolvedUsingTypenameDecl *UD
+ = dyn_cast<UnresolvedUsingTypenameDecl>(D)) {
+ DTypename = true;
+ DQual = UD->getTargetNestedNameSpecifier();
+ } else continue;
+
+ // using decls differ if one says 'typename' and the other doesn't.
+ // FIXME: non-dependent using decls?
+ if (isTypeName != DTypename) continue;
+
+ // using decls differ if they name different scopes (but note that
+ // template instantiation can cause this check to trigger when it
+ // didn't before instantiation).
+ if (Context.getCanonicalNestedNameSpecifier(Qual) !=
+ Context.getCanonicalNestedNameSpecifier(DQual))
+ continue;
+
+ Diag(NameLoc, diag::err_using_decl_redeclaration) << SS.getRange();
+ Diag(D->getLocation(), diag::note_using_decl) << 1;
+ return true;
+ }
+
+ return false;
+}
+
+
+/// Checks that the given nested-name qualifier used in a using decl
+/// in the current context is appropriately related to the current
+/// scope. If an error is found, diagnoses it and returns true.
+bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation NameLoc) {
+ DeclContext *NamedContext = computeDeclContext(SS);
+
+ if (!CurContext->isRecord()) {
+ // C++03 [namespace.udecl]p3:
+ // C++0x [namespace.udecl]p8:
+ // A using-declaration for a class member shall be a member-declaration.
+
+ // If we weren't able to compute a valid scope, it must be a
+ // dependent class scope.
+ if (!NamedContext || NamedContext->isRecord()) {
+ Diag(NameLoc, diag::err_using_decl_can_not_refer_to_class_member)
+ << SS.getRange();
+ return true;
+ }
+
+ // Otherwise, everything is known to be fine.
+ return false;
+ }
+
+ // The current scope is a record.
+
+ // If the named context is dependent, we can't decide much.
+ if (!NamedContext) {
+ // FIXME: in C++0x, we can diagnose if we can prove that the
+ // nested-name-specifier does not refer to a base class, which is
+ // still possible in some cases.
+
+ // Otherwise we have to conservatively report that things might be
+ // okay.
+ return false;
+ }
+
+ if (!NamedContext->isRecord()) {
+ // Ideally this would point at the last name in the specifier,
+ // but we don't have that level of source info.
+ Diag(SS.getRange().getBegin(),
+ diag::err_using_decl_nested_name_specifier_is_not_class)
+ << (NestedNameSpecifier*) SS.getScopeRep() << SS.getRange();
+ return true;
+ }
+
+ if (getLangOptions().CPlusPlus0x) {
+ // C++0x [namespace.udecl]p3:
+ // In a using-declaration used as a member-declaration, the
+ // nested-name-specifier shall name a base class of the class
+ // being defined.
+
+ if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(
+ cast<CXXRecordDecl>(NamedContext))) {
+ if (CurContext == NamedContext) {
+ Diag(NameLoc,
+ diag::err_using_decl_nested_name_specifier_is_current_class)
+ << SS.getRange();
+ return true;
+ }
+
+ Diag(SS.getRange().getBegin(),
+ diag::err_using_decl_nested_name_specifier_is_not_base_class)
+ << (NestedNameSpecifier*) SS.getScopeRep()
+ << cast<CXXRecordDecl>(CurContext)
+ << SS.getRange();
+ return true;
+ }
+
+ return false;
+ }
+
+ // C++03 [namespace.udecl]p4:
+ // A using-declaration used as a member-declaration shall refer
+ // to a member of a base class of the class being defined [etc.].
+
+ // Salient point: SS doesn't have to name a base class as long as
+ // lookup only finds members from base classes. Therefore we can
+ // diagnose here only if we can prove that that can't happen,
+ // i.e. if the class hierarchies provably don't intersect.
+
+ // TODO: it would be nice if "definitely valid" results were cached
+ // in the UsingDecl and UsingShadowDecl so that these checks didn't
+ // need to be repeated.
+
+ struct UserData {
+ llvm::DenseSet<const CXXRecordDecl*> Bases;
+
+ static bool collect(const CXXRecordDecl *Base, void *OpaqueData) {
+ UserData *Data = reinterpret_cast<UserData*>(OpaqueData);
+ Data->Bases.insert(Base);
+ return true;
+ }
+
+ bool hasDependentBases(const CXXRecordDecl *Class) {
+ return !Class->forallBases(collect, this);
+ }
+
+ /// Returns true if the base is dependent or is one of the
+ /// accumulated base classes.
+ static bool doesNotContain(const CXXRecordDecl *Base, void *OpaqueData) {
+ UserData *Data = reinterpret_cast<UserData*>(OpaqueData);
+ return !Data->Bases.count(Base);
+ }
+
+ bool mightShareBases(const CXXRecordDecl *Class) {
+ return Bases.count(Class) || !Class->forallBases(doesNotContain, this);
+ }
+ };
+
+ UserData Data;
+
+ // Returns false if we find a dependent base.
+ if (Data.hasDependentBases(cast<CXXRecordDecl>(CurContext)))
+ return false;
+
+ // Returns false if the class has a dependent base or if it or one
+ // of its bases is present in the base set of the current context.
+ if (Data.mightShareBases(cast<CXXRecordDecl>(NamedContext)))
+ return false;
+
+ Diag(SS.getRange().getBegin(),
+ diag::err_using_decl_nested_name_specifier_is_not_base_class)
+ << (NestedNameSpecifier*) SS.getScopeRep()
+ << cast<CXXRecordDecl>(CurContext)
+ << SS.getRange();
+
+ return true;
+}
+
Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
SourceLocation NamespaceLoc,
SourceLocation AliasLoc,
@@ -3081,7 +3548,6 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
} else {
Constructor->setUsed();
}
- return;
}
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
@@ -3163,7 +3629,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (CXXMethodDecl *BaseAssignOpMethod =
- getAssignOperatorMethod(MethodDecl->getParamDecl(0), BaseClassDecl))
+ getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0),
+ BaseClassDecl))
MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod);
}
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
@@ -3175,7 +3642,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
if (CXXMethodDecl *FieldAssignOpMethod =
- getAssignOperatorMethod(MethodDecl->getParamDecl(0), FieldClassDecl))
+ getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0),
+ FieldClassDecl))
MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod);
} else if (FieldType->isReferenceType()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
@@ -3196,7 +3664,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
}
CXXMethodDecl *
-Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl,
+Sema::getAssignOperatorMethod(SourceLocation CurrentLocation,
+ ParmVarDecl *ParmDecl,
CXXRecordDecl *ClassDecl) {
QualType LHSType = Context.getTypeDeclType(ClassDecl);
QualType RHSType(LHSType);
@@ -3206,18 +3675,17 @@ Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl,
RHSType = Context.getCVRQualifiedType(RHSType,
ParmDecl->getType().getCVRQualifiers());
ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl,
- LHSType,
- SourceLocation()));
+ LHSType,
+ SourceLocation()));
ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl,
- RHSType,
- SourceLocation()));
+ RHSType,
+ CurrentLocation));
Expr *Args[2] = { &*LHS, &*RHS };
OverloadCandidateSet CandidateSet;
AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2,
CandidateSet);
OverloadCandidateSet::iterator Best;
- if (BestViableFunction(CandidateSet,
- ClassDecl->getLocation(), Best) == OR_Success)
+ if (BestViableFunction(CandidateSet, CurrentLocation, Best) == OR_Success)
return cast<CXXMethodDecl>(Best->Function);
assert(false &&
"getAssignOperatorMethod - copy assignment operator method not found");
@@ -3286,8 +3754,10 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
if (ICE->getCastKind() == CastExpr::CK_NoOp)
E = ICE->getSubExpr();
-
- if (isa<CallExpr>(E) || isa<CXXTemporaryObjectExpr>(E))
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(E))
+ Elidable = !CE->getCallReturnType()->isReferenceType();
+ else if (isa<CXXTemporaryObjectExpr>(E))
Elidable = true;
}
@@ -3428,7 +3898,9 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
SourceRange(VDecl->getLocation(),
RParenLoc),
VDecl->getDeclName(),
- IK_Direct,
+ InitializationKind::CreateDirect(VDecl->getLocation(),
+ LParenLoc,
+ RParenLoc),
ConstructorArgs);
if (!Constructor)
RealDecl->setInvalidDecl();
@@ -3464,7 +3936,7 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef,
QualType ClassType,
Expr **Args,
unsigned NumArgs,
- Sema::InitializationKind Kind,
+ InitializationKind Kind,
OverloadCandidateSet &CandidateSet) {
// C++ [dcl.init]p14:
// If the initialization is direct-initialization, or if it is
@@ -3499,10 +3971,12 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef,
else
Constructor = cast<CXXConstructorDecl>(*Con);
- if ((Kind == Sema::IK_Direct) ||
- (Kind == Sema::IK_Copy &&
+ if ((Kind.getKind() == InitializationKind::IK_Direct) ||
+ (Kind.getKind() == InitializationKind::IK_Value) ||
+ (Kind.getKind() == InitializationKind::IK_Copy &&
Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) ||
- (Kind == Sema::IK_Default && Constructor->isDefaultConstructor())) {
+ ((Kind.getKind() == InitializationKind::IK_Default) &&
+ Constructor->isDefaultConstructor())) {
if (ConstructorTmpl)
SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl,
/*ExplicitArgs*/ 0,
@@ -3774,7 +4248,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// real, update the initializer with the resulting function.
if (!ICS) {
if (DiagnoseUseOfDecl(Fn, DeclLoc))
- return true;
+ return true;
Init = FixOverloadedFunctionReference(Init, Fn);
}
@@ -3874,23 +4348,28 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
= T2RecordDecl->getVisibleConversionFunctions();
for (UnresolvedSet::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
+ NamedDecl *D = *I;
+ CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
FunctionTemplateDecl *ConvTemplate
- = dyn_cast<FunctionTemplateDecl>(*I);
+ = dyn_cast<FunctionTemplateDecl>(D);
CXXConversionDecl *Conv;
if (ConvTemplate)
Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
- Conv = cast<CXXConversionDecl>(*I);
+ 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, Init, DeclType,
- CandidateSet);
+ AddTemplateConversionCandidate(ConvTemplate, ActingDC,
+ Init, DeclType, CandidateSet);
else
- AddConversionCandidate(Conv, Init, DeclType, CandidateSet);
+ AddConversionCandidate(Conv, ActingDC, Init, DeclType, CandidateSet);
}
}
@@ -4125,6 +4604,138 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
}
}
+static inline bool
+CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef,
+ const FunctionDecl *FnDecl) {
+ const DeclContext *DC = FnDecl->getDeclContext()->getLookupContext();
+ if (isa<NamespaceDecl>(DC)) {
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_new_delete_declared_in_namespace)
+ << FnDecl->getDeclName();
+ }
+
+ if (isa<TranslationUnitDecl>(DC) &&
+ FnDecl->getStorageClass() == FunctionDecl::Static) {
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_new_delete_declared_static)
+ << FnDecl->getDeclName();
+ }
+
+ return false;
+}
+
+static inline bool
+CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
+ CanQualType ExpectedResultType,
+ CanQualType ExpectedFirstParamType,
+ unsigned DependentParamTypeDiag,
+ unsigned InvalidParamTypeDiag) {
+ QualType ResultType =
+ FnDecl->getType()->getAs<FunctionType>()->getResultType();
+
+ // Check that the result type is not dependent.
+ if (ResultType->isDependentType())
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_new_delete_dependent_result_type)
+ << FnDecl->getDeclName() << ExpectedResultType;
+
+ // Check that the result type is what we expect.
+ if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType)
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_new_delete_invalid_result_type)
+ << FnDecl->getDeclName() << ExpectedResultType;
+
+ // A function template must have at least 2 parameters.
+ if (FnDecl->getDescribedFunctionTemplate() && FnDecl->getNumParams() < 2)
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_new_delete_template_too_few_parameters)
+ << FnDecl->getDeclName();
+
+ // The function decl must have at least 1 parameter.
+ if (FnDecl->getNumParams() == 0)
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_new_delete_too_few_parameters)
+ << FnDecl->getDeclName();
+
+ // Check the the first parameter type is not dependent.
+ QualType FirstParamType = FnDecl->getParamDecl(0)->getType();
+ if (FirstParamType->isDependentType())
+ return SemaRef.Diag(FnDecl->getLocation(), DependentParamTypeDiag)
+ << FnDecl->getDeclName() << ExpectedFirstParamType;
+
+ // Check that the first parameter type is what we expect.
+ if (SemaRef.Context.getCanonicalType(FirstParamType) !=
+ ExpectedFirstParamType)
+ return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag)
+ << FnDecl->getDeclName() << ExpectedFirstParamType;
+
+ return false;
+}
+
+static bool
+CheckOperatorNewDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) {
+ // C++ [basic.stc.dynamic.allocation]p1:
+ // A program is ill-formed if an allocation function is declared in a
+ // namespace scope other than global scope or declared static in global
+ // scope.
+ if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl))
+ return true;
+
+ CanQualType SizeTy =
+ SemaRef.Context.getCanonicalType(SemaRef.Context.getSizeType());
+
+ // C++ [basic.stc.dynamic.allocation]p1:
+ // The return type shall be void*. The first parameter shall have type
+ // std::size_t.
+ if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidPtrTy,
+ SizeTy,
+ diag::err_operator_new_dependent_param_type,
+ diag::err_operator_new_param_type))
+ return true;
+
+ // C++ [basic.stc.dynamic.allocation]p1:
+ // The first parameter shall not have an associated default argument.
+ if (FnDecl->getParamDecl(0)->hasDefaultArg())
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_new_default_arg)
+ << FnDecl->getDeclName() << FnDecl->getParamDecl(0)->getDefaultArgRange();
+
+ return false;
+}
+
+static bool
+CheckOperatorDeleteDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) {
+ // C++ [basic.stc.dynamic.deallocation]p1:
+ // A program is ill-formed if deallocation functions are declared in a
+ // namespace scope other than global scope or declared static in global
+ // scope.
+ if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl))
+ return true;
+
+ // C++ [basic.stc.dynamic.deallocation]p2:
+ // Each deallocation function shall return void and its first parameter
+ // shall be void*.
+ if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidTy,
+ SemaRef.Context.VoidPtrTy,
+ diag::err_operator_delete_dependent_param_type,
+ diag::err_operator_delete_param_type))
+ return true;
+
+ QualType FirstParamType = FnDecl->getParamDecl(0)->getType();
+ if (FirstParamType->isDependentType())
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_delete_dependent_param_type)
+ << FnDecl->getDeclName() << SemaRef.Context.VoidPtrTy;
+
+ if (SemaRef.Context.getCanonicalType(FirstParamType) !=
+ SemaRef.Context.VoidPtrTy)
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_delete_param_type)
+ << FnDecl->getDeclName() << SemaRef.Context.VoidPtrTy;
+
+ return false;
+}
+
/// CheckOverloadedOperatorDeclaration - Check whether the declaration
/// of this overloaded operator is well-formed. If so, returns false;
/// otherwise, emits appropriate diagnostics and returns true.
@@ -4140,29 +4751,11 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// described completely in 3.7.3. The attributes and restrictions
// found in the rest of this subclause do not apply to them unless
// explicitly stated in 3.7.3.
- // FIXME: Write a separate routine for checking this. For now, just allow it.
if (Op == OO_Delete || Op == OO_Array_Delete)
- return false;
+ return CheckOperatorDeleteDeclaration(*this, FnDecl);
- if (Op == OO_New || Op == OO_Array_New) {
- bool ret = false;
- if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) {
- QualType SizeTy = Context.getCanonicalType(Context.getSizeType());
- QualType T = Context.getCanonicalType((*Param)->getType());
- if (!T->isDependentType() && SizeTy != T) {
- Diag(FnDecl->getLocation(),
- diag::err_operator_new_param_type) << FnDecl->getDeclName()
- << SizeTy;
- ret = true;
- }
- }
- QualType ResultTy = Context.getCanonicalType(FnDecl->getResultType());
- if (!ResultTy->isDependentType() && ResultTy != Context.VoidPtrTy)
- return Diag(FnDecl->getLocation(),
- diag::err_operator_new_result_type) << FnDecl->getDeclName()
- << static_cast<QualType>(Context.VoidPtrTy);
- return ret;
- }
+ if (Op == OO_New || Op == OO_Array_New)
+ return CheckOperatorNewDeclaration(*this, FnDecl);
// C++ [over.oper]p6:
// An operator function shall either be a non-static member
@@ -4201,14 +4794,10 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
if (Op != OO_Call) {
for (FunctionDecl::param_iterator Param = FnDecl->param_begin();
Param != FnDecl->param_end(); ++Param) {
- if ((*Param)->hasUnparsedDefaultArg())
+ if ((*Param)->hasDefaultArg())
return Diag((*Param)->getLocation(),
diag::err_operator_overload_default_arg)
- << FnDecl->getDeclName();
- else if (Expr *DefArg = (*Param)->getDefaultArg())
- return Diag((*Param)->getLocation(),
- diag::err_operator_overload_default_arg)
- << FnDecl->getDeclName() << DefArg->getSourceRange();
+ << FnDecl->getDeclName() << (*Param)->getDefaultArgRange();
}
}
@@ -4346,7 +4935,7 @@ Sema::DeclPtrTy Sema::ActOnFinishLinkageSpecification(Scope *S,
/// occurs within a C++ catch clause, returning the newly-created
/// variable.
VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
- DeclaratorInfo *DInfo,
+ TypeSourceInfo *TInfo,
IdentifierInfo *Name,
SourceLocation Loc,
SourceRange Range) {
@@ -4396,7 +4985,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
// FIXME: Need to check for abstract classes.
VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc,
- Name, ExDeclType, DInfo, VarDecl::None);
+ Name, ExDeclType, TInfo, VarDecl::None);
if (Invalid)
ExDecl->setInvalidDecl();
@@ -4407,8 +4996,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
/// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch
/// handler.
Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
- DeclaratorInfo *DInfo = 0;
- QualType ExDeclType = GetTypeForDeclarator(D, S, &DInfo);
+ TypeSourceInfo *TInfo = 0;
+ QualType ExDeclType = GetTypeForDeclarator(D, S, &TInfo);
bool Invalid = D.isInvalidType();
IdentifierInfo *II = D.getIdentifier();
@@ -4428,7 +5017,7 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
Invalid = true;
}
- VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType, DInfo,
+ VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType, TInfo,
D.getIdentifier(),
D.getIdentifierLoc(),
D.getDeclSpec().getSourceRange());
@@ -4462,10 +5051,8 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
}
if (Value == 0) {
- std::string str(AssertMessage->getStrData(),
- AssertMessage->getByteLength());
Diag(AssertLoc, diag::err_static_assert_failed)
- << str << AssertExpr->getSourceRange();
+ << AssertMessage->getString() << AssertExpr->getSourceRange();
}
}
@@ -4602,8 +5189,8 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
SourceLocation Loc = D.getIdentifierLoc();
- DeclaratorInfo *DInfo = 0;
- QualType T = GetTypeForDeclarator(D, S, &DInfo);
+ TypeSourceInfo *TInfo = 0;
+ QualType T = GetTypeForDeclarator(D, S, &TInfo);
// C++ [class.friend]p1
// A friend of a class is a function or class....
@@ -4726,7 +5313,7 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
}
bool Redeclaration = false;
- NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, DInfo, Previous,
+ NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, TInfo, Previous,
move(TemplateParams),
IsDefinition,
Redeclaration);
@@ -4890,6 +5477,26 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
return false;
}
+/// \brief Mark the given method pure.
+///
+/// \param Method the method to be marked pure.
+///
+/// \param InitRange the source range that covers the "0" initializer.
+bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) {
+ if (Method->isVirtual() || Method->getParent()->isDependentContext()) {
+ Method->setPure();
+
+ // A class is abstract if at least one function is pure virtual.
+ Method->getParent()->setAbstract(true);
+ return false;
+ }
+
+ if (!Method->isInvalidDecl())
+ Diag(Method->getLocation(), diag::err_non_virtual_pure)
+ << Method->getDeclName() << InitRange;
+ return true;
+}
+
/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an
/// initializer for the declaration 'Dcl'.
/// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a
@@ -4949,9 +5556,9 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
"Parser allowed 'typedef' as storage class of condition decl.");
- DeclaratorInfo *DInfo = 0;
+ TypeSourceInfo *TInfo = 0;
TagDecl *OwnedTag = 0;
- QualType Ty = GetTypeForDeclarator(D, S, &DInfo, &OwnedTag);
+ QualType Ty = GetTypeForDeclarator(D, S, &TInfo, &OwnedTag);
if (Ty->isFunctionType()) { // The declarator shall not specify a function...
// We exit without creating a CXXConditionDeclExpr because a FunctionDecl
@@ -4972,3 +5579,80 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
VD->setDeclaredInCondition(true);
return Dcl;
}
+
+void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc,
+ CXXMethodDecl *MD) {
+ // Ignore dependent types.
+ if (MD->isDependentContext())
+ return;
+
+ CXXRecordDecl *RD = MD->getParent();
+
+ // Ignore classes without a vtable.
+ if (!RD->isDynamicClass())
+ return;
+
+ if (!MD->isOutOfLine()) {
+ // The only inline functions we care about are constructors. We also defer
+ // marking the virtual members as referenced until we've reached the end
+ // of the translation unit. We do this because we need to know the key
+ // function of the class in order to determine the key function.
+ if (isa<CXXConstructorDecl>(MD))
+ ClassesWithUnmarkedVirtualMembers.insert(std::make_pair(RD, Loc));
+ return;
+ }
+
+ const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
+
+ if (!KeyFunction) {
+ // This record does not have a key function, so we assume that the vtable
+ // will be emitted when it's used by the constructor.
+ if (!isa<CXXConstructorDecl>(MD))
+ return;
+ } else if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) {
+ // We don't have the right key function.
+ return;
+ }
+
+ // Mark the members as referenced.
+ MarkVirtualMembersReferenced(Loc, RD);
+ ClassesWithUnmarkedVirtualMembers.erase(RD);
+}
+
+bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() {
+ if (ClassesWithUnmarkedVirtualMembers.empty())
+ return false;
+
+ for (std::map<CXXRecordDecl *, SourceLocation>::iterator i =
+ ClassesWithUnmarkedVirtualMembers.begin(),
+ e = ClassesWithUnmarkedVirtualMembers.end(); i != e; ++i) {
+ CXXRecordDecl *RD = i->first;
+
+ const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
+ if (KeyFunction) {
+ // We know that the class has a key function. If the key function was
+ // declared in this translation unit, then it the class decl would not
+ // have been in the ClassesWithUnmarkedVirtualMembers map.
+ continue;
+ }
+
+ SourceLocation Loc = i->second;
+ MarkVirtualMembersReferenced(Loc, RD);
+ }
+
+ ClassesWithUnmarkedVirtualMembers.clear();
+ return true;
+}
+
+void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) {
+ for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+ e = RD->method_end(); i != e; ++i) {
+ CXXMethodDecl *MD = *i;
+
+ // C++ [basic.def.odr]p2:
+ // [...] A virtual member function is used if it is not pure. [...]
+ if (MD->isVirtual() && !MD->isPure())
+ MarkDeclarationReferenced(Loc, MD);
+ }
+}
+
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 7da37af..a768e1b 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -1349,10 +1349,10 @@ ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel,
}
if (issueWarning && (MethList.Method && MethList.Next)) {
Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
- Diag(MethList.Method->getLocStart(), diag::note_using_decl)
+ Diag(MethList.Method->getLocStart(), diag::note_using)
<< MethList.Method->getSourceRange();
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
- Diag(Next->Method->getLocStart(), diag::note_also_found_decl)
+ Diag(Next->Method->getLocStart(), diag::note_also_found)
<< Next->Method->getSourceRange();
}
return MethList.Method;
@@ -1413,10 +1413,10 @@ ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel,
}
if (issueWarning && (MethList.Method && MethList.Next)) {
Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
- Diag(MethList.Method->getLocStart(), diag::note_using_decl)
+ Diag(MethList.Method->getLocStart(), diag::note_using)
<< MethList.Method->getSourceRange();
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
- Diag(Next->Method->getLocStart(), diag::note_also_found_decl)
+ Diag(Next->Method->getLocStart(), diag::note_also_found)
<< Next->Method->getSourceRange();
}
return MethList.Method;
@@ -1495,7 +1495,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
property->getLocation(),
property->getIdentifier(),
property->getType(),
- /*DInfo=*/0,
+ /*TInfo=*/0,
VarDecl::None,
0);
SetterMethod->setMethodParams(Context, &Argument, 1);
@@ -1765,7 +1765,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
for (unsigned i = 0, e = Sel.getNumArgs(); i != e; ++i) {
QualType ArgType;
- DeclaratorInfo *DI;
+ TypeSourceInfo *DI;
if (ArgInfo[i].Type == 0) {
ArgType = Context.getObjCIdType();
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 25af052..7e2a98d 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -35,10 +35,15 @@ static const FunctionProtoType *GetUnderlyingFunction(QualType T)
/// exception specification. Incomplete types, or pointers to incomplete types
/// other than void are not allowed.
bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
- // FIXME: This may not correctly work with the fix for core issue 437,
- // where a class's own type is considered complete within its body. But
- // perhaps RequireCompleteType itself should contain this logic?
+ // This check (and the similar one below) deals with issue 437, that changes
+ // C++ 9.2p2 this way:
+ // Within the class member-specification, the class is regarded as complete
+ // within function bodies, default arguments, exception-specifications, and
+ // constructor ctor-initializers (including such things in nested classes).
+ if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined())
+ return false;
+
// C++ 15.4p2: A type denoted in an exception-specification shall not denote
// an incomplete type.
if (RequireCompleteType(Range.getBegin(), T,
@@ -58,8 +63,12 @@ bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
} else
return false;
+ // Again as before
+ if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined())
+ return false;
+
if (!T->isVoidType() && RequireCompleteType(Range.getBegin(), T,
- PDiag(diag::err_incomplete_in_exception_spec) << /*direct*/kind << Range))
+ PDiag(diag::err_incomplete_in_exception_spec) << kind << Range))
return true;
return false;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index f653cf6..358f445 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -259,15 +259,43 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) {
DefaultArgumentPromotion(Expr);
if (Expr->getType()->isObjCInterfaceType()) {
- Diag(Expr->getLocStart(),
- diag::err_cannot_pass_objc_interface_to_vararg)
- << Expr->getType() << CT;
- return true;
+ switch (ExprEvalContexts.back().Context ) {
+ case Unevaluated:
+ // The argument will never be evaluated, so don't complain.
+ break;
+
+ case PotentiallyEvaluated:
+ Diag(Expr->getLocStart(),
+ diag::err_cannot_pass_objc_interface_to_vararg)
+ << Expr->getType() << CT;
+ return true;
+
+ case PotentiallyPotentiallyEvaluated:
+ ExprEvalContexts.back().addDiagnostic(Expr->getLocStart(),
+ PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
+ << Expr->getType() << CT);
+ break;
+ }
}
- if (!Expr->getType()->isPODType())
- Diag(Expr->getLocStart(), diag::warn_cannot_pass_non_pod_arg_to_vararg)
- << Expr->getType() << CT;
+ if (!Expr->getType()->isPODType()) {
+ switch (ExprEvalContexts.back().Context ) {
+ case Unevaluated:
+ // The argument will never be evaluated, so don't complain.
+ break;
+
+ case PotentiallyEvaluated:
+ Diag(Expr->getLocStart(), diag::warn_cannot_pass_non_pod_arg_to_vararg)
+ << Expr->getType() << CT;
+ break;
+
+ case PotentiallyPotentiallyEvaluated:
+ ExprEvalContexts.back().addDiagnostic(Expr->getLocStart(),
+ PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
+ << Expr->getType() << CT);
+ break;
+ }
+ }
return false;
}
@@ -415,7 +443,7 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
/// BuildDeclRefExpr - Build a DeclRefExpr.
Sema::OwningExprResult
-Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
+Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc,
const CXXScopeSpec *SS) {
if (Context.getCanonicalType(Ty) == Context.UndeducedAutoTy) {
Diag(Loc,
@@ -605,6 +633,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
MemberType = Context.getQualifiedType(MemberType, NewQuals);
MarkDeclarationReferenced(Loc, *FI);
+ PerformObjectMemberConversion(Result, *FI);
// FIXME: Might this end up being a qualified name?
Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI,
OpLoc, MemberType);
@@ -665,9 +694,9 @@ static void DecomposeTemplateName(LookupResult &R, const UnqualifiedId &Id) {
if (TemplateDecl *TD = TName.getAsTemplateDecl())
R.addDecl(TD);
- else if (OverloadedFunctionDecl *OD
- = TName.getAsOverloadedFunctionDecl())
- for (OverloadIterator I(OD), E; I != E; ++I)
+ else if (OverloadedTemplateStorage *OT = TName.getAsOverloadedTemplate())
+ for (OverloadedTemplateStorage::iterator I = OT->begin(), E = OT->end();
+ I != E; ++I)
R.addDecl(*I);
R.resolveKind();
@@ -703,18 +732,188 @@ static bool IsDependentIdExpression(Sema &SemaRef, const CXXScopeSpec &SS) {
// We can't look into record types unless they're fully-formed.
if (!IsFullyFormedScope(SemaRef, cast<CXXRecordDecl>(DC))) return true;
- // We can always look into fully-formed record types, but if we're
- // in a dependent but not fully-formed context, we can't decide
- // whether the qualifier names a base class. We shouldn't be trying
- // to decide that yet anyway, but we are, so we need to delay that
- // decision.
- CXXRecordDecl *CurRecord;
- if (CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(SemaRef.CurContext))
- CurRecord = cast<CXXRecordDecl>(CurMethod->getParent());
- else
- CurRecord = dyn_cast<CXXRecordDecl>(SemaRef.CurContext);
+ return false;
+}
+
+/// Determines if the given class is provably not derived from all of
+/// the prospective base classes.
+static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
+ CXXRecordDecl *Record,
+ const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) {
+ if (Bases.count(Record->getCanonicalDecl()))
+ return false;
+
+ RecordDecl *RD = Record->getDefinition(SemaRef.Context);
+ if (!RD) return false;
+ Record = cast<CXXRecordDecl>(RD);
+
+ for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
+ E = Record->bases_end(); I != E; ++I) {
+ CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType());
+ CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>();
+ if (!BaseRT) return false;
+
+ CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
+ if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases))
+ return false;
+ }
+
+ return true;
+}
+
+/// Determines if this a C++ class member.
+static bool IsClassMember(NamedDecl *D) {
+ DeclContext *DC = D->getDeclContext();
+
+ // C++0x [class.mem]p1:
+ // The enumerators of an unscoped enumeration defined in
+ // the class are members of the class.
+ // FIXME: support C++0x scoped enumerations.
+ if (isa<EnumDecl>(DC))
+ DC = DC->getParent();
+
+ return DC->isRecord();
+}
+
+/// Determines if this is an instance member of a class.
+static bool IsInstanceMember(NamedDecl *D) {
+ assert(IsClassMember(D) &&
+ "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,
+
+ /// The reference may be an implicit instance member access.
+ IMA_Mixed,
+
+ /// The reference may be to an instance member, but it is invalid if
+ /// so, because the context is not an instance method.
+ IMA_Mixed_StaticContext,
+
+ /// The reference may be to an instance member, but it is invalid if
+ /// so, because the context is from an unrelated class.
+ IMA_Mixed_Unrelated,
+
+ /// The reference is definitely an implicit instance member access.
+ IMA_Instance,
+
+ /// The reference may be to an unresolved using declaration.
+ IMA_Unresolved,
+
+ /// The reference may be to an unresolved using declaration and the
+ /// context is not an instance method.
+ IMA_Unresolved_StaticContext,
+
+ /// The reference is to a member of an anonymous structure in a
+ /// non-class context.
+ IMA_AnonymousMember,
- return CurRecord && !IsFullyFormedScope(SemaRef, CurRecord);
+ /// All possible referrents are instance members and the current
+ /// context is not an instance method.
+ IMA_Error_StaticContext,
+
+ /// All possible referrents are instance members of an unrelated
+ /// class.
+ IMA_Error_Unrelated
+};
+
+/// The given lookup names class member(s) and is not being used for
+/// an address-of-member expression. Classify the type of access
+/// according to whether it's possible that this reference names an
+/// instance member. This is best-effort; it is okay to
+/// conservatively answer "yes", in which case some errors will simply
+/// not be caught until template-instantiation.
+static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
+ const LookupResult &R) {
+ assert(!R.empty() && IsClassMember(*R.begin()));
+
+ bool isStaticContext =
+ (!isa<CXXMethodDecl>(SemaRef.CurContext) ||
+ cast<CXXMethodDecl>(SemaRef.CurContext)->isStatic());
+
+ if (R.isUnresolvableResult())
+ return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
+
+ // Collect all the declaring classes of instance members we find.
+ 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)) {
+ CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
+
+ // If this is a member of an anonymous record, move out to the
+ // innermost non-anonymous struct or union. If there isn't one,
+ // that's a special case.
+ while (R->isAnonymousStructOrUnion()) {
+ R = dyn_cast<CXXRecordDecl>(R->getParent());
+ if (!R) return IMA_AnonymousMember;
+ }
+ Classes.insert(R->getCanonicalDecl());
+ }
+ else
+ hasNonInstance = true;
+ }
+
+ // If we didn't find any instance members, it can't be an implicit
+ // member reference.
+ if (Classes.empty())
+ return IMA_Static;
+
+ // If the current context is not an instance method, it can't be
+ // an implicit member reference.
+ if (isStaticContext)
+ return (hasNonInstance ? IMA_Mixed_StaticContext : IMA_Error_StaticContext);
+
+ // If we can prove that the current context is unrelated to all the
+ // declaring classes, it can't be an implicit member reference (in
+ // which case it's an error if any of those members are selected).
+ if (IsProvablyNotDerivedFrom(SemaRef,
+ cast<CXXMethodDecl>(SemaRef.CurContext)->getParent(),
+ Classes))
+ return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
+
+ return (hasNonInstance ? IMA_Mixed : IMA_Instance);
+}
+
+/// Diagnose a reference to a field with no object available.
+static void DiagnoseInstanceReference(Sema &SemaRef,
+ const CXXScopeSpec &SS,
+ const LookupResult &R) {
+ SourceLocation Loc = R.getNameLoc();
+ SourceRange Range(Loc);
+ if (SS.isSet()) Range.setBegin(SS.getRange().getBegin());
+
+ if (R.getAsSingle<FieldDecl>()) {
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) {
+ if (MD->isStatic()) {
+ // "invalid use of member 'x' in static member function"
+ SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method)
+ << Range << R.getLookupName();
+ return;
+ }
+ }
+
+ SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use)
+ << R.getLookupName() << Range;
+ return;
+ }
+
+ SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range;
}
Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
@@ -746,10 +945,8 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
// Determine whether this is a member of an unknown specialization;
// we need to handle these differently.
if (SS.isSet() && IsDependentIdExpression(*this, SS)) {
- bool CheckForImplicitMember = !isAddressOfOperand;
-
return ActOnDependentIdExpression(SS, Name, NameLoc,
- CheckForImplicitMember,
+ isAddressOfOperand,
TemplateArgs);
}
@@ -847,23 +1044,41 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
}
}
- // &SomeClass::foo is an abstract member reference, regardless of
- // the nature of foo, but &SomeClass::foo(...) is not. If this is
- // *not* an abstract member reference, and any of the results is a
- // class member (which necessarily means they're all class members),
- // then we make an implicit member reference instead.
- //
- // This check considers all the same information as the "needs ADL"
- // check, but there's no simple logical relationship other than the
- // fact that they can never be simultaneously true. We could
- // calculate them both in one pass if that proves important for
- // performance.
- if (!ADL) {
+ // Check whether this might be a C++ implicit instance member access.
+ // C++ [expr.prim.general]p6:
+ // Within the definition of a non-static member function, an
+ // identifier that names a non-static member is transformed to a
+ // class member access expression.
+ // But note that &SomeClass::foo is grammatically distinct, even
+ // though we don't parse it that way.
+ if (!R.empty() && IsClassMember(*R.begin())) {
bool isAbstractMemberPointer = (isAddressOfOperand && !SS.isEmpty());
- if (!isAbstractMemberPointer && !R.empty() &&
- isa<CXXRecordDecl>((*R.begin())->getDeclContext())) {
- return BuildImplicitMemberReferenceExpr(SS, R, TemplateArgs);
+ if (!isAbstractMemberPointer) {
+ switch (ClassifyImplicitMemberAccess(*this, R)) {
+ case IMA_Instance:
+ return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
+
+ case IMA_AnonymousMember:
+ assert(R.isSingleResult());
+ return BuildAnonymousStructUnionMemberReference(R.getNameLoc(),
+ R.getAsSingle<FieldDecl>());
+
+ case IMA_Mixed:
+ case IMA_Mixed_Unrelated:
+ case IMA_Unresolved:
+ return BuildImplicitMemberExpr(SS, R, TemplateArgs, false);
+
+ case IMA_Static:
+ case IMA_Mixed_StaticContext:
+ case IMA_Unresolved_StaticContext:
+ break;
+
+ case IMA_Error_StaticContext:
+ case IMA_Error_Unrelated:
+ DiagnoseInstanceReference(*this, SS, R);
+ return ExprError();
+ }
}
}
@@ -1027,7 +1242,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, NamedDecl *Member) {
/// \brief Build a MemberExpr AST node.
static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
- const CXXScopeSpec &SS, NamedDecl *Member,
+ const CXXScopeSpec &SS, ValueDecl *Member,
SourceLocation Loc, QualType Ty,
const TemplateArgumentListInfo *TemplateArgs = 0) {
NestedNameSpecifier *Qualifier = 0;
@@ -1041,35 +1256,15 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
Member, Loc, TemplateArgs, Ty);
}
-/// Return true if all the decls in the given result are instance
-/// methods.
-static bool IsOnlyInstanceMethods(const LookupResult &R) {
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- NamedDecl *D = (*I)->getUnderlyingDecl();
-
- CXXMethodDecl *Method;
- if (isa<FunctionTemplateDecl>(D))
- Method = cast<CXXMethodDecl>(cast<FunctionTemplateDecl>(D)
- ->getTemplatedDecl());
- else if (isa<CXXMethodDecl>(D))
- Method = cast<CXXMethodDecl>(D);
- else
- return false;
-
- if (Method->isStatic())
- return false;
- }
-
- return true;
-}
-
-/// Builds an implicit member access expression from the given
-/// unqualified lookup set, which is known to contain only class
-/// members.
+/// Builds an implicit member access expression. The current context
+/// is known to be an instance method, and the given unqualified lookup
+/// set is known to contain only instance members, at least one of which
+/// is from an appropriate type.
Sema::OwningExprResult
-Sema::BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs) {
+Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool IsKnownInstance) {
assert(!R.empty() && !R.isAmbiguous());
SourceLocation Loc = R.getNameLoc();
@@ -1082,44 +1277,18 @@ Sema::BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS,
if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion())
return BuildAnonymousStructUnionMemberReference(Loc, FD);
- QualType ThisType;
- if (isImplicitMemberReference(R, ThisType)) {
- Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType);
- return BuildMemberReferenceExpr(ExprArg(*this, This),
- /*OpLoc*/ SourceLocation(),
- /*IsArrow*/ true,
- SS, R, TemplateArgs);
- }
-
- // Diagnose now if none of the available methods are static.
- if (IsOnlyInstanceMethods(R))
- return ExprError(Diag(Loc, diag::err_member_call_without_object));
-
- if (R.getAsSingle<FieldDecl>()) {
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
- if (MD->isStatic()) {
- // "invalid use of member 'x' in static member function"
- Diag(Loc, diag::err_invalid_member_use_in_static_method)
- << R.getLookupName();
- return ExprError();
- }
- }
-
- // Any other ways we could have found the field in a well-formed
- // program would have been turned into implicit member expressions
- // above.
- Diag(Loc, diag::err_invalid_non_static_member_use)
- << R.getLookupName();
- return ExprError();
+ // If this is known to be an instance access, go ahead and build a
+ // 'this' expression now.
+ QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context);
+ Expr *This = 0; // null signifies implicit access
+ if (IsKnownInstance) {
+ This = new (Context) CXXThisExpr(SourceLocation(), ThisType);
}
- // We're not in an implicit member-reference context, but the lookup
- // results might not require an instance. Try to build a non-member
- // decl reference.
- if (TemplateArgs)
- return BuildTemplateIdExpr(SS, R, /* ADL */ false, *TemplateArgs);
-
- return BuildDeclarationNameExpr(SS, R, /*ADL*/ false);
+ return BuildMemberReferenceExpr(ExprArg(*this, This), ThisType,
+ /*OpLoc*/ SourceLocation(),
+ /*IsArrow*/ true,
+ SS, R, TemplateArgs);
}
bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
@@ -1146,7 +1315,7 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
// -- a declaration of a class member
// Since using decls preserve this property, we check this on the
// original decl.
- if (D->getDeclContext()->isRecord())
+ if (IsClassMember(D))
return false;
// C++0x [basic.lookup.argdep]p3:
@@ -1205,11 +1374,9 @@ Sema::OwningExprResult
Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
LookupResult &R,
bool NeedsADL) {
- assert(R.getResultKind() != LookupResult::FoundUnresolvedValue);
-
- // If this isn't an overloaded result and we don't need ADL, just
- // build an ordinary singleton decl ref.
- if (!NeedsADL && !R.isOverloadedResult())
+ // If this is a single, fully-resolved result and we don't need ADL,
+ // just build an ordinary singleton decl ref.
+ if (!NeedsADL && R.isSingleResult())
return BuildDeclarationNameExpr(SS, R.getNameLoc(), R.getFoundDecl());
// We only need to check the declaration if there's exactly one
@@ -1246,7 +1413,23 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
if (CheckDeclInExpr(*this, Loc, D))
return ExprError();
- ValueDecl *VD = cast<ValueDecl>(D);
+ if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
+ // Specifically diagnose references to class templates that are missing
+ // a template argument list.
+ Diag(Loc, diag::err_template_decl_ref)
+ << Template << SS.getRange();
+ Diag(Template->getLocation(), diag::note_template_decl_here);
+ return ExprError();
+ }
+
+ // Make sure that we're referring to a value.
+ ValueDecl *VD = dyn_cast<ValueDecl>(D);
+ if (!VD) {
+ Diag(Loc, diag::err_ref_non_value)
+ << D << SS.getRange();
+ Diag(D->getLocation(), diag::note_previous_declaration);
+ return ExprError();
+ }
// Check whether this declaration can be used. Note that we suppress
// this check when we're going to perform argument-dependent lookup
@@ -1558,20 +1741,20 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc,
/// \brief Build a sizeof or alignof expression given a type operand.
Action::OwningExprResult
-Sema::CreateSizeOfAlignOfExpr(DeclaratorInfo *DInfo,
+Sema::CreateSizeOfAlignOfExpr(TypeSourceInfo *TInfo,
SourceLocation OpLoc,
bool isSizeOf, SourceRange R) {
- if (!DInfo)
+ if (!TInfo)
return ExprError();
- QualType T = DInfo->getType();
+ QualType T = TInfo->getType();
if (!T->isDependentType() &&
CheckSizeOfAlignOfOperand(T, OpLoc, R, isSizeOf))
return ExprError();
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
- return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, DInfo,
+ return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, TInfo,
Context.getSizeType(), OpLoc,
R.getEnd()));
}
@@ -1613,9 +1796,9 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
if (TyOrEx == 0) return ExprError();
if (isType) {
- DeclaratorInfo *DInfo;
- (void) GetTypeFromParser(TyOrEx, &DInfo);
- return CreateSizeOfAlignOfExpr(DInfo, OpLoc, isSizeof, ArgRange);
+ TypeSourceInfo *TInfo;
+ (void) GetTypeFromParser(TyOrEx, &TInfo);
+ return CreateSizeOfAlignOfExpr(TInfo, OpLoc, isSizeof, ArgRange);
}
Expr *ArgEx = (Expr *)TyOrEx;
@@ -1952,7 +2135,8 @@ static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy,
}
Sema::OwningExprResult
-Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc,
+Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType,
+ bool IsArrow, SourceLocation OpLoc,
const CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
DeclarationName Name, SourceLocation NameLoc,
@@ -1969,20 +2153,21 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc,
// accessing the 'f' property if T is an Obj-C interface. The extra check
// allows this, while still reporting an error if T is a struct pointer.
if (!IsArrow) {
- const PointerType *PT = BaseExpr->getType()->getAs<PointerType>();
+ const PointerType *PT = BaseType->getAs<PointerType>();
if (PT && (!getLangOptions().ObjC1 ||
PT->getPointeeType()->isRecordType())) {
+ assert(BaseExpr && "cannot happen with implicit member accesses");
Diag(NameLoc, diag::err_typecheck_member_reference_struct_union)
- << BaseExpr->getType() << BaseExpr->getSourceRange();
+ << BaseType << BaseExpr->getSourceRange();
return ExprError();
}
}
- assert(BaseExpr->getType()->isDependentType());
+ assert(BaseType->isDependentType());
// 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.
- return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr,
+ return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType,
IsArrow, OpLoc,
static_cast<NestedNameSpecifier*>(SS.getScopeRep()),
SS.getRange(),
@@ -1997,15 +2182,18 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc,
static void DiagnoseQualifiedMemberReference(Sema &SemaRef,
Expr *BaseExpr,
QualType BaseType,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ const CXXScopeSpec &SS,
const LookupResult &R) {
- DeclContext *DC = R.getRepresentativeDecl()->getDeclContext();
+ // If this is an implicit member access, use a different set of
+ // diagnostics.
+ 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)
- << QualifierRange << DC << BaseType;
+ << SS.getRange() << DC << BaseType;
}
// Check whether the declarations we found through a nested-name
@@ -2022,37 +2210,78 @@ static void DiagnoseQualifiedMemberReference(Sema &SemaRef,
// we actually pick through overload resolution is from a superclass.
bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
QualType BaseType,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ const CXXScopeSpec &SS,
const LookupResult &R) {
- QualType BaseTypeCanon
- = Context.getCanonicalType(BaseType).getUnqualifiedType();
-
- bool FoundValid = false;
+ const RecordType *BaseRT = BaseType->getAs<RecordType>();
+ if (!BaseRT) {
+ // We can't check this yet because the base type is still
+ // dependent.
+ assert(BaseType->isDependentType());
+ return false;
+ }
+ CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- TypeDecl* TyD = cast<TypeDecl>((*I)->getUnderlyingDecl()->getDeclContext());
- CanQualType MemberTypeCanon
- = Context.getCanonicalType(Context.getTypeDeclType(TyD));
+ // If this is an implicit member reference and we find a
+ // non-instance member, it's not an error.
+ if (!BaseExpr && !IsInstanceMember((*I)->getUnderlyingDecl()))
+ return false;
- if (BaseTypeCanon == MemberTypeCanon ||
- IsDerivedFrom(BaseTypeCanon, MemberTypeCanon)) {
- FoundValid = true;
- break;
- }
+ // Note that we use the DC of the decl, not the underlying decl.
+ CXXRecordDecl *RecordD = cast<CXXRecordDecl>((*I)->getDeclContext());
+ while (RecordD->isAnonymousStructOrUnion())
+ RecordD = cast<CXXRecordDecl>(RecordD->getParent());
+
+ llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord;
+ MemberRecord.insert(RecordD->getCanonicalDecl());
+
+ if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord))
+ return false;
}
- if (!FoundValid) {
- DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType,
- Qualifier, QualifierRange, R);
+ DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS, R);
+ return true;
+}
+
+static bool
+LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
+ SourceRange BaseRange, const RecordType *RTy,
+ SourceLocation OpLoc, const CXXScopeSpec &SS) {
+ RecordDecl *RDecl = RTy->getDecl();
+ if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
+ PDiag(diag::err_typecheck_incomplete_tag)
+ << BaseRange))
return true;
+
+ DeclContext *DC = RDecl;
+ if (SS.isSet()) {
+ // If the member name was a qualified-id, look into the
+ // nested-name-specifier.
+ DC = SemaRef.computeDeclContext(SS, false);
+
+ if (SemaRef.RequireCompleteDeclContext(SS)) {
+ SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
+ << SS.getRange() << DC;
+ return true;
+ }
+
+ assert(DC && "Cannot handle non-computable dependent contexts in lookup");
+
+ if (!isa<TypeDecl>(DC)) {
+ SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass)
+ << DC << SS.getRange();
+ return true;
+ }
}
+ // The record definition is complete, now look up the member.
+ SemaRef.LookupQualifiedName(R, DC);
+
return false;
}
Sema::OwningExprResult
-Sema::BuildMemberReferenceExpr(ExprArg BaseArg,
+Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
const CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
@@ -2060,38 +2289,53 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg,
const TemplateArgumentListInfo *TemplateArgs) {
Expr *Base = BaseArg.takeAs<Expr>();
- if (Base->getType()->isDependentType())
- return ActOnDependentMemberExpr(ExprArg(*this, Base),
+ if (BaseType->isDependentType() ||
+ (SS.isSet() && isDependentScopeSpecifier(SS)))
+ return ActOnDependentMemberExpr(ExprArg(*this, Base), BaseType,
IsArrow, OpLoc,
SS, FirstQualifierInScope,
Name, NameLoc,
TemplateArgs);
LookupResult R(*this, Name, NameLoc, LookupMemberName);
- OwningExprResult Result =
- LookupMemberExpr(R, Base, IsArrow, OpLoc,
- SS, FirstQualifierInScope,
- /*ObjCImpDecl*/ DeclPtrTy());
- if (Result.isInvalid()) {
- Owned(Base);
- return ExprError();
- }
+ // Implicit member accesses.
+ if (!Base) {
+ QualType RecordTy = BaseType;
+ if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
+ if (LookupMemberExprInRecord(*this, R, SourceRange(),
+ RecordTy->getAs<RecordType>(),
+ OpLoc, SS))
+ return ExprError();
+
+ // Explicit member accesses.
+ } else {
+ OwningExprResult Result =
+ LookupMemberExpr(R, Base, IsArrow, OpLoc,
+ SS, FirstQualifierInScope,
+ /*ObjCImpDecl*/ DeclPtrTy());
- if (Result.get())
- return move(Result);
+ if (Result.isInvalid()) {
+ Owned(Base);
+ return ExprError();
+ }
+
+ if (Result.get())
+ return move(Result);
+ }
- return BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc,
- IsArrow, SS, R, TemplateArgs);
+ return BuildMemberReferenceExpr(ExprArg(*this, Base), BaseType,
+ OpLoc, IsArrow, SS, R, TemplateArgs);
}
Sema::OwningExprResult
-Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc,
- bool IsArrow, const CXXScopeSpec &SS,
+Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
+ SourceLocation OpLoc, bool IsArrow,
+ const CXXScopeSpec &SS,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
Expr *BaseExpr = Base.takeAs<Expr>();
- QualType BaseType = BaseExpr->getType();
+ QualType BaseType = BaseExprType;
if (IsArrow) {
assert(BaseType->isPointerType());
BaseType = BaseType->getAs<PointerType>()->getPointeeType();
@@ -2112,29 +2356,30 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc,
: BaseType->getAs<RecordType>()->getDecl());
Diag(R.getNameLoc(), diag::err_no_member)
- << MemberName << DC << BaseExpr->getSourceRange();
+ << MemberName << DC
+ << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
return ExprError();
}
- // We can't always diagnose the problem yet: it's permitted for
- // lookup to find things from an invalid context as long as they
- // don't get picked by overload resolution.
- if (SS.isSet() && CheckQualifiedMemberReference(BaseExpr, BaseType,
- Qualifier, SS.getRange(), R))
+ // Diagnose qualified lookups that find only declarations from a
+ // non-base type. Note that it's okay for lookup to find
+ // declarations from a non-base type as long as those aren't the
+ // ones picked by overload resolution.
+ if (SS.isSet() && CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
return ExprError();
// Construct an unresolved result if we in fact got an unresolved
// result.
if (R.isOverloadedResult() || R.isUnresolvableResult()) {
- bool Dependent = R.isUnresolvableResult();
- Dependent = Dependent ||
- UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(),
- TemplateArgs);
+ bool Dependent =
+ R.isUnresolvableResult() ||
+ UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs);
UnresolvedMemberExpr *MemExpr
= UnresolvedMemberExpr::Create(Context, Dependent,
R.isUnresolvableResult(),
- BaseExpr, IsArrow, OpLoc,
+ BaseExpr, BaseExprType,
+ IsArrow, OpLoc,
Qualifier, SS.getRange(),
MemberName, MemberLoc,
TemplateArgs);
@@ -2155,6 +2400,15 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc,
if (MemberDecl->isInvalidDecl())
return ExprError();
+ // Handle the implicit-member-access case.
+ if (!BaseExpr) {
+ // If this is not an instance member, convert to a non-member access.
+ if (!IsInstanceMember(MemberDecl))
+ return BuildDeclarationNameExpr(SS, R.getNameLoc(), MemberDecl);
+
+ BaseExpr = new (Context) CXXThisExpr(SourceLocation(), BaseExprType);
+ }
+
bool ShouldCheckUse = true;
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) {
// Don't diagnose the use of a virtual member function unless it's
@@ -2172,7 +2426,8 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc,
if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) {
// We may have found a field within an anonymous union or struct
// (C++ [class.union]).
- if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion())
+ if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion() &&
+ !BaseType->getAs<RecordType>()->getDecl()->isAnonymousStructOrUnion())
return BuildAnonymousStructUnionMemberReference(MemberLoc, FD,
BaseExpr, OpLoc);
@@ -2246,7 +2501,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc,
/// fixed for ObjC++.
Sema::OwningExprResult
Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
- bool IsArrow, SourceLocation OpLoc,
+ bool &IsArrow, SourceLocation OpLoc,
const CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
DeclPtrTy ObjCImpDecl) {
@@ -2295,6 +2550,16 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// If this is an Objective-C pseudo-builtin and a definition is provided then
// use that.
if (BaseType->isObjCIdType()) {
+ if (IsArrow) {
+ // Handle the following exceptional case PObj->isa.
+ if (const ObjCObjectPointerType *OPT =
+ BaseType->getAs<ObjCObjectPointerType>()) {
+ if (OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) &&
+ MemberName.getAsIdentifierInfo()->isStr("isa"))
+ return Owned(new (Context) ObjCIsaExpr(BaseExpr, true, MemberLoc,
+ Context.getObjCClassType()));
+ }
+ }
// We have an 'id' type. Rather than fall through, we check if this
// is a reference to 'isa'.
if (BaseType != Context.ObjCIdRedefinitionType) {
@@ -2377,41 +2642,48 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
BaseType = PT->getPointeeType();
else if (BaseType->isObjCObjectPointerType())
;
- else {
+ else if (BaseType->isRecordType()) {
+ // Recover from arrow accesses to records, e.g.:
+ // struct MyRecord foo;
+ // foo->bar
+ // This is actually well-formed in C++ if MyRecord has an
+ // overloaded operator->, but that should have been dealt with
+ // by now.
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << BaseType << int(IsArrow) << BaseExpr->getSourceRange()
+ << CodeModificationHint::CreateReplacement(OpLoc, ".");
+ IsArrow = false;
+ } else {
Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
<< BaseType << BaseExpr->getSourceRange();
return ExprError();
}
+ } else {
+ // Recover from dot accesses to pointers, e.g.:
+ // type *foo;
+ // foo.bar
+ // This is actually well-formed in two cases:
+ // - 'type' is an Objective C type
+ // - 'bar' is a pseudo-destructor name which happens to refer to
+ // the appropriate pointer type
+ if (MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
+ const PointerType *PT = BaseType->getAs<PointerType>();
+ if (PT && PT->getPointeeType()->isRecordType()) {
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << BaseType << int(IsArrow) << BaseExpr->getSourceRange()
+ << CodeModificationHint::CreateReplacement(OpLoc, "->");
+ BaseType = PT->getPointeeType();
+ IsArrow = true;
+ }
+ }
}
-
+
// Handle field access to simple records. This also handles access
// to fields of the ObjC 'id' struct.
if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
- RecordDecl *RDecl = RTy->getDecl();
- if (RequireCompleteType(OpLoc, BaseType,
- PDiag(diag::err_typecheck_incomplete_tag)
- << BaseExpr->getSourceRange()))
+ if (LookupMemberExprInRecord(*this, R, BaseExpr->getSourceRange(),
+ RTy, OpLoc, SS))
return ExprError();
-
- DeclContext *DC = RDecl;
- if (SS.isSet()) {
- // If the member name was a qualified-id, look into the
- // nested-name-specifier.
- DC = computeDeclContext(SS, false);
-
- if (!isa<TypeDecl>(DC)) {
- Diag(MemberLoc, diag::err_qualified_member_nonclass)
- << DC << SS.getRange();
- return ExprError();
- }
-
- // FIXME: If DC is not computable, we should build a
- // CXXDependentScopeMemberExpr.
- assert(DC && "Cannot handle non-computable dependent contexts in lookup");
- }
-
- // The record definition is complete, now make sure the member is valid.
- LookupQualifiedName(R, DC);
return Owned((Expr*) 0);
}
@@ -2644,7 +2916,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) &&
MemberName.getAsIdentifierInfo()->isStr("isa"))
return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc,
- Context.getObjCIdType()));
+ Context.getObjCClassType()));
// Handle 'field access' to vectors, such as 'V.xx'.
if (BaseType->isExtVectorType()) {
@@ -2723,7 +2995,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
Expr *Base = BaseArg.takeAs<Expr>();
OwningExprResult Result(*this);
if (Base->getType()->isDependentType()) {
- Result = ActOnDependentMemberExpr(ExprArg(*this, Base),
+ Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(),
IsArrow, OpLoc,
SS, FirstQualifierInScope,
Name, NameLoc,
@@ -2756,8 +3028,8 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
}
}
- Result = BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc,
- IsArrow, SS, R, TemplateArgs);
+ Result = BuildMemberReferenceExpr(ExprArg(*this, Base), Base->getType(),
+ OpLoc, IsArrow, SS, R, TemplateArgs);
}
return move(Result);
@@ -3054,16 +3326,16 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
isa<FunctionTemplateDecl>(*MemE->decls_begin()));
(void)MemE;
- return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
- CommaLocs, RParenLoc));
+ return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
+ CommaLocs, RParenLoc);
}
// Determine whether this is a call to a member function.
if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(NakedFn)) {
NamedDecl *MemDecl = MemExpr->getMemberDecl();
if (isa<CXXMethodDecl>(MemDecl))
- return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
- CommaLocs, RParenLoc));
+ return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
+ CommaLocs, RParenLoc);
}
// Determine whether this is a call to a pointer-to-member function.
@@ -3155,13 +3427,28 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
} else {
assert(Fns.size() <= 1 && "overloaded without Overloaded flag");
if (Fns.empty())
- NDecl = FDecl = 0;
+ NDecl = 0;
else {
NDecl = Fns[0];
- FDecl = dyn_cast<FunctionDecl>(NDecl);
}
}
+ return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc);
+}
+
+/// BuildCallExpr - Build a call to a resolved expression, i.e. an
+/// expression not of \p OverloadTy. The expression should
+/// unary-convert to an expression of function-pointer or
+/// block-pointer type.
+///
+/// \param NDecl the declaration being called, if available
+Sema::OwningExprResult
+Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
+ SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RParenLoc) {
+ FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
+
// Promote the function operand.
UsualUnaryConversions(Fn);
@@ -3661,41 +3948,14 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
ImpCastExprToType(LHS, RHSTy, CastExpr::CK_Unknown);
return RHSTy;
}
- // Handle things like Class and struct objc_class*. Here we case the result
- // to the pseudo-builtin, because that will be implicitly cast back to the
- // redefinition type if an attempt is made to access its fields.
- if (LHSTy->isObjCClassType() &&
- (RHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) {
- ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast);
- return LHSTy;
- }
- if (RHSTy->isObjCClassType() &&
- (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) {
- ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast);
- return RHSTy;
- }
- // And the same for struct objc_object* / id
- if (LHSTy->isObjCIdType() &&
- (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
- ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast);
- return LHSTy;
- }
- if (RHSTy->isObjCIdType() &&
- (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
- ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast);
- return RHSTy;
- }
- // And the same for struct objc_selector* / SEL
- if (Context.isObjCSelType(LHSTy) &&
- (RHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) {
- ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast);
- return LHSTy;
- }
- if (Context.isObjCSelType(RHSTy) &&
- (LHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) {
- ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast);
- return RHSTy;
- }
+
+ // All objective-c pointer type analysis is done here.
+ QualType compositeType = FindCompositeObjCPointerType(LHS, RHS,
+ QuestionLoc);
+ if (!compositeType.isNull())
+ return compositeType;
+
+
// Handle block pointer types.
if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) {
if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) {
@@ -3706,7 +3966,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
return destType;
}
Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
- << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
+ << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
return QualType();
}
// We have 2 block pointer types.
@@ -3717,11 +3977,11 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// The block pointer types aren't identical, continue checking.
QualType lhptee = LHSTy->getAs<BlockPointerType>()->getPointeeType();
QualType rhptee = RHSTy->getAs<BlockPointerType>()->getPointeeType();
-
+
if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
rhptee.getUnqualifiedType())) {
Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers)
- << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
+ << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
// In this situation, we assume void* type. No especially good
// reason, but this is what gcc does, and we do have to pick
// to get a consistent AST.
@@ -3735,86 +3995,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast);
return LHSTy;
}
- // Check constraints for Objective-C object pointers types.
- if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) {
-
- if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
- // Two identical object pointer types are always compatible.
- return LHSTy;
- }
- const ObjCObjectPointerType *LHSOPT = LHSTy->getAs<ObjCObjectPointerType>();
- const ObjCObjectPointerType *RHSOPT = RHSTy->getAs<ObjCObjectPointerType>();
- QualType compositeType = LHSTy;
-
- // If both operands are interfaces and either operand can be
- // assigned to the other, use that type as the composite
- // type. This allows
- // xxx ? (A*) a : (B*) b
- // where B is a subclass of A.
- //
- // Additionally, as for assignment, if either type is 'id'
- // allow silent coercion. Finally, if the types are
- // incompatible then make sure to use 'id' as the composite
- // type so the result is acceptable for sending messages to.
-
- // FIXME: Consider unifying with 'areComparableObjCPointerTypes'.
- // It could return the composite type.
- if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) {
- compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy;
- } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) {
- compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy;
- } else if ((LHSTy->isObjCQualifiedIdType() ||
- RHSTy->isObjCQualifiedIdType()) &&
- Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) {
- // Need to handle "id<xx>" explicitly.
- // GCC allows qualified id and any Objective-C type to devolve to
- // id. Currently localizing to here until clear this should be
- // part of ObjCQualifiedIdTypesAreCompatible.
- compositeType = Context.getObjCIdType();
- } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) {
- compositeType = Context.getObjCIdType();
- } else if (!(compositeType =
- Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull())
- ;
- else {
- Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands)
- << LHSTy << RHSTy
- << LHS->getSourceRange() << RHS->getSourceRange();
- QualType incompatTy = Context.getObjCIdType();
- ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast);
- ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast);
- return incompatTy;
- }
- // The object pointer types are compatible.
- ImpCastExprToType(LHS, compositeType, CastExpr::CK_BitCast);
- ImpCastExprToType(RHS, compositeType, CastExpr::CK_BitCast);
- return compositeType;
- }
- // Check Objective-C object pointer types and 'void *'
- if (LHSTy->isVoidPointerType() && RHSTy->isObjCObjectPointerType()) {
- QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
- QualType rhptee = RHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
- QualType destPointee
- = Context.getQualifiedType(lhptee, rhptee.getQualifiers());
- QualType destType = Context.getPointerType(destPointee);
- // Add qualifiers if necessary.
- ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp);
- // Promote to void*.
- ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast);
- return destType;
- }
- if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) {
- QualType lhptee = LHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
- QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
- QualType destPointee
- = Context.getQualifiedType(rhptee, lhptee.getQualifiers());
- QualType destType = Context.getPointerType(destPointee);
- // Add qualifiers if necessary.
- ImpCastExprToType(RHS, destType, CastExpr::CK_NoOp);
- // Promote to void*.
- ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast);
- return destType;
- }
+
// Check constraints for C object pointers types (C99 6.5.15p3,6).
if (LHSTy->isPointerType() && RHSTy->isPointerType()) {
// get the "pointed to" types
@@ -3892,6 +4073,131 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
return QualType();
}
+/// FindCompositeObjCPointerType - Helper method to find composite type of
+/// two objective-c pointer types of the two input expressions.
+QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
+ SourceLocation QuestionLoc) {
+ QualType LHSTy = LHS->getType();
+ QualType RHSTy = RHS->getType();
+
+ // Handle things like Class and struct objc_class*. Here we case the result
+ // to the pseudo-builtin, because that will be implicitly cast back to the
+ // redefinition type if an attempt is made to access its fields.
+ if (LHSTy->isObjCClassType() &&
+ (RHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) {
+ ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast);
+ return LHSTy;
+ }
+ if (RHSTy->isObjCClassType() &&
+ (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) {
+ ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast);
+ return RHSTy;
+ }
+ // And the same for struct objc_object* / id
+ if (LHSTy->isObjCIdType() &&
+ (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
+ ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast);
+ return LHSTy;
+ }
+ if (RHSTy->isObjCIdType() &&
+ (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
+ ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast);
+ return RHSTy;
+ }
+ // And the same for struct objc_selector* / SEL
+ if (Context.isObjCSelType(LHSTy) &&
+ (RHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) {
+ ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast);
+ return LHSTy;
+ }
+ if (Context.isObjCSelType(RHSTy) &&
+ (LHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) {
+ ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast);
+ return RHSTy;
+ }
+ // Check constraints for Objective-C object pointers types.
+ if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) {
+
+ if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
+ // Two identical object pointer types are always compatible.
+ return LHSTy;
+ }
+ const ObjCObjectPointerType *LHSOPT = LHSTy->getAs<ObjCObjectPointerType>();
+ const ObjCObjectPointerType *RHSOPT = RHSTy->getAs<ObjCObjectPointerType>();
+ QualType compositeType = LHSTy;
+
+ // If both operands are interfaces and either operand can be
+ // assigned to the other, use that type as the composite
+ // type. This allows
+ // xxx ? (A*) a : (B*) b
+ // where B is a subclass of A.
+ //
+ // Additionally, as for assignment, if either type is 'id'
+ // allow silent coercion. Finally, if the types are
+ // incompatible then make sure to use 'id' as the composite
+ // type so the result is acceptable for sending messages to.
+
+ // FIXME: Consider unifying with 'areComparableObjCPointerTypes'.
+ // It could return the composite type.
+ if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) {
+ compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy;
+ } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) {
+ compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy;
+ } else if ((LHSTy->isObjCQualifiedIdType() ||
+ RHSTy->isObjCQualifiedIdType()) &&
+ Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) {
+ // Need to handle "id<xx>" explicitly.
+ // GCC allows qualified id and any Objective-C type to devolve to
+ // id. Currently localizing to here until clear this should be
+ // part of ObjCQualifiedIdTypesAreCompatible.
+ compositeType = Context.getObjCIdType();
+ } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) {
+ compositeType = Context.getObjCIdType();
+ } else if (!(compositeType =
+ Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull())
+ ;
+ else {
+ Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands)
+ << LHSTy << RHSTy
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ QualType incompatTy = Context.getObjCIdType();
+ ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast);
+ ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast);
+ return incompatTy;
+ }
+ // The object pointer types are compatible.
+ ImpCastExprToType(LHS, compositeType, CastExpr::CK_BitCast);
+ ImpCastExprToType(RHS, compositeType, CastExpr::CK_BitCast);
+ return compositeType;
+ }
+ // Check Objective-C object pointer types and 'void *'
+ if (LHSTy->isVoidPointerType() && RHSTy->isObjCObjectPointerType()) {
+ QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType destPointee
+ = Context.getQualifiedType(lhptee, rhptee.getQualifiers());
+ QualType destType = Context.getPointerType(destPointee);
+ // Add qualifiers if necessary.
+ ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp);
+ // Promote to void*.
+ ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast);
+ return destType;
+ }
+ if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) {
+ QualType lhptee = LHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
+ QualType destPointee
+ = Context.getQualifiedType(rhptee, lhptee.getQualifiers());
+ QualType destType = Context.getPointerType(destPointee);
+ // Add qualifiers if necessary.
+ ImpCastExprToType(RHS, destType, CastExpr::CK_NoOp);
+ // Promote to void*.
+ ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast);
+ return destType;
+ }
+ return QualType();
+}
+
/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
/// in the case of a the GNU conditional expr extension.
Action::OwningExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
@@ -4051,6 +4357,29 @@ Sema::CheckBlockPointerTypesForAssignment(QualType lhsType,
return ConvTy;
}
+/// CheckObjCPointerTypesForAssignment - Compares two objective-c pointer types
+/// for assignment compatibility.
+Sema::AssignConvertType
+Sema::CheckObjCPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
+ if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType())
+ return Compatible;
+ QualType lhptee =
+ lhsType->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType rhptee =
+ rhsType->getAs<ObjCObjectPointerType>()->getPointeeType();
+ // make sure we operate on the canonical type
+ lhptee = Context.getCanonicalType(lhptee);
+ rhptee = Context.getCanonicalType(rhptee);
+ if (!lhptee.isAtLeastAsQualifiedAs(rhptee))
+ return CompatiblePointerDiscardsQualifiers;
+
+ if (Context.typesAreCompatible(lhsType, rhsType))
+ return Compatible;
+ if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType())
+ return IncompatibleObjCQualifiedId;
+ return IncompatiblePointer;
+}
+
/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
/// has code to accommodate several GCC extensions when type checking
/// pointers. Here are some objectionable examples that GCC considers warnings:
@@ -4173,13 +4502,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
return IncompatiblePointer;
}
if (rhsType->isObjCObjectPointerType()) {
- if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType())
- return Compatible;
- if (Context.typesAreCompatible(lhsType, rhsType))
- return Compatible;
- if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType())
- return IncompatibleObjCQualifiedId;
- return IncompatiblePointer;
+ return CheckObjCPointerTypesForAssignment(lhsType, rhsType);
}
if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) {
if (RHSPT->getPointeeType()->isVoidType())
@@ -4794,6 +5117,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
unsigned OpaqueOpc, bool isRelational) {
BinaryOperator::Opcode Opc = (BinaryOperator::Opcode)OpaqueOpc;
+ // Handle vector comparisons separately.
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
return CheckVectorCompareOperands(lex, rex, Loc, isRelational);
@@ -4871,17 +5195,15 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
}
// The result of comparisons is 'bool' in C++, 'int' in C.
- QualType ResultTy = getLangOptions().CPlusPlus? Context.BoolTy :Context.IntTy;
+ QualType ResultTy = getLangOptions().CPlusPlus ? Context.BoolTy:Context.IntTy;
if (isRelational) {
if (lType->isRealType() && rType->isRealType())
return ResultTy;
} else {
// Check for comparisons of floating point operands using != and ==.
- if (lType->isFloatingType()) {
- assert(rType->isFloatingType());
+ if (lType->isFloatingType() && rType->isFloatingType())
CheckFloatComparison(Loc,lex,rex);
- }
if (lType->isArithmeticType() && rType->isArithmeticType())
return ResultTy;
@@ -6157,18 +6479,33 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
RecordDecl *RD = RC->getDecl();
if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
if (!CRD->isPOD() && !DidWarnAboutNonPOD) {
- ExprError(Diag(BuiltinLoc, diag::warn_offsetof_non_pod_type)
- << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
- << Res->getType());
- DidWarnAboutNonPOD = true;
+ switch (ExprEvalContexts.back().Context ) {
+ case Unevaluated:
+ // The argument will never be evaluated, so don't complain.
+ break;
+
+ case PotentiallyEvaluated:
+ ExprError(Diag(BuiltinLoc, diag::warn_offsetof_non_pod_type)
+ << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
+ << Res->getType());
+ DidWarnAboutNonPOD = true;
+ break;
+
+ case PotentiallyPotentiallyEvaluated:
+ ExprEvalContexts.back().addDiagnostic(BuiltinLoc,
+ PDiag(diag::warn_offsetof_non_pod_type)
+ << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
+ << Res->getType());
+ DidWarnAboutNonPOD = true;
+ break;
+ }
}
}
LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName);
LookupQualifiedName(R, RD);
- FieldDecl *MemberDecl
- = dyn_cast_or_null<FieldDecl>(R.getAsSingleDecl(Context));
+ FieldDecl *MemberDecl = R.getAsSingle<FieldDecl>();
// FIXME: Leaks Res
if (!MemberDecl)
return ExprError(Diag(BuiltinLoc, diag::err_no_member)
@@ -6180,6 +6517,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
Res = BuildAnonymousStructUnionMemberReference(
OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>();
} else {
+ PerformObjectMemberConversion(Res, MemberDecl);
// MemberDecl->getType() doesn't get the right qualifiers, but it
// doesn't matter here.
Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd,
@@ -6270,6 +6608,7 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) {
CurFunctionNeedsScopeChecking = false;
BSI->TheDecl = BlockDecl::Create(Context, CurContext, CaretLoc);
+ CurContext->addDecl(BSI->TheDecl);
PushDeclContext(BlockScope, BSI->TheDecl);
}
@@ -6625,16 +6964,26 @@ Sema::PopExpressionEvaluationContext() {
ExpressionEvaluationContextRecord Rec = ExprEvalContexts.back();
ExprEvalContexts.pop_back();
- if (Rec.Context == PotentiallyPotentiallyEvaluated &&
- Rec.PotentiallyReferenced) {
- // Mark any remaining declarations in the current position of the stack
- // as "referenced". If they were not meant to be referenced, semantic
- // analysis would have eliminated them (e.g., in ActOnCXXTypeId).
- for (PotentiallyReferencedDecls::iterator
- I = Rec.PotentiallyReferenced->begin(),
- IEnd = Rec.PotentiallyReferenced->end();
- I != IEnd; ++I)
- MarkDeclarationReferenced(I->first, I->second);
+ if (Rec.Context == PotentiallyPotentiallyEvaluated) {
+ if (Rec.PotentiallyReferenced) {
+ // Mark any remaining declarations in the current position of the stack
+ // as "referenced". If they were not meant to be referenced, semantic
+ // analysis would have eliminated them (e.g., in ActOnCXXTypeId).
+ for (PotentiallyReferencedDecls::iterator
+ I = Rec.PotentiallyReferenced->begin(),
+ IEnd = Rec.PotentiallyReferenced->end();
+ I != IEnd; ++I)
+ MarkDeclarationReferenced(I->first, I->second);
+ }
+
+ if (Rec.PotentiallyDiagnosed) {
+ // Emit any pending diagnostics.
+ for (PotentiallyEmittedDiagnostics::iterator
+ I = Rec.PotentiallyDiagnosed->begin(),
+ IEnd = Rec.PotentiallyDiagnosed->end();
+ I != IEnd; ++I)
+ Diag(I->first, I->second);
+ }
}
// When are coming out of an unevaluated context, clear out any
@@ -6708,6 +7057,8 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
if (!Constructor->isUsed())
DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals);
}
+
+ MaybeMarkVirtualMembersReferenced(Loc, Constructor);
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
if (Destructor->isImplicit() && !Destructor->isUsed())
DefineImplicitDestructor(Loc, Destructor);
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 00fb65d..6d991b6 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "SemaInit.h"
#include "Lookup.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
@@ -37,8 +38,7 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info");
LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName);
LookupQualifiedName(R, StdNamespace);
- Decl *TypeInfoDecl = R.getAsSingleDecl(Context);
- RecordDecl *TypeInfoRecordDecl = dyn_cast_or_null<RecordDecl>(TypeInfoDecl);
+ RecordDecl *TypeInfoRecordDecl = R.getAsSingle<RecordDecl>();
if (!TypeInfoRecordDecl)
return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
@@ -226,7 +226,9 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
SourceRange(TypeRange.getBegin(),
RParenLoc),
DeclarationName(),
- IK_Direct,
+ InitializationKind::CreateDirect(TypeRange.getBegin(),
+ LParenLoc,
+ RParenLoc),
ConstructorArgs);
if (!Constructor)
@@ -322,9 +324,9 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
- //FIXME: Store DeclaratorInfo in CXXNew expression.
- DeclaratorInfo *DInfo = 0;
- QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &DInfo);
+ //FIXME: Store TypeSourceInfo in CXXNew expression.
+ TypeSourceInfo *TInfo = 0;
+ QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &TInfo);
if (D.isInvalidType())
return ExprError();
@@ -450,12 +452,17 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
// Skip all the checks.
} else if ((RT = AllocType->getAs<RecordType>()) &&
!AllocType->isAggregateType()) {
+ InitializationKind InitKind = InitializationKind::CreateDefault(TypeLoc);
+ if (NumConsArgs > 0)
+ InitKind = InitializationKind::CreateDirect(TypeLoc,
+ PlacementLParen,
+ PlacementRParen);
Constructor = PerformInitializationByConstructor(
AllocType, move(ConstructorArgs),
TypeLoc,
SourceRange(TypeLoc, ConstructorRParen),
RT->getDecl()->getDeclName(),
- NumConsArgs != 0 ? IK_Direct : IK_Default,
+ InitKind,
ConvertedConstructorArgs);
if (!Constructor)
return ExprError();
@@ -602,7 +609,8 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
Alloc != AllocEnd; ++Alloc) {
// Even member operator new/delete are implicitly treated as
// static, so don't use AddMemberCandidate.
- if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*Alloc)) {
+ if (FunctionDecl *Fn =
+ dyn_cast<FunctionDecl>((*Alloc)->getUnderlyingDecl())) {
AddOverloadCandidate(Fn, Args, NumArgs, Candidates,
/*SuppressUserConversions=*/false);
continue;
@@ -761,10 +769,10 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
&BadAllocType);
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
- FnType, /*DInfo=*/0, FunctionDecl::None, false, true);
+ FnType, /*TInfo=*/0, FunctionDecl::None, false, true);
Alloc->setImplicit();
ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
- 0, Argument, /*DInfo=*/0,
+ 0, Argument, /*TInfo=*/0,
VarDecl::None, 0);
Alloc->setParams(Context, &Param, 1);
@@ -1270,6 +1278,16 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
// Nothing else to do.
break;
+ case ICK_NoReturn_Adjustment:
+ // If both sides are functions (or pointers/references to them), there could
+ // be incompatible exception declarations.
+ if (CheckExceptionSpecCompatibility(From, ToType))
+ return true;
+
+ ImpCastExprToType(From, Context.getNoReturnType(From->getType(), false),
+ CastExpr::CK_NoOp);
+ break;
+
case ICK_Integral_Promotion:
case ICK_Integral_Conversion:
ImpCastExprToType(From, ToType, CastExpr::CK_IntegralCast);
@@ -1574,7 +1592,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
OverloadCandidateSet::iterator Best;
switch (Self.BestViableFunction(CandidateSet, Loc, Best)) {
- case Sema::OR_Success:
+ case OR_Success:
// We found a match. Perform the conversions on the arguments and move on.
if (Self.PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0],
Best->Conversions[0], "converting") ||
@@ -1583,13 +1601,13 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
break;
return false;
- case Sema::OR_No_Viable_Function:
+ case OR_No_Viable_Function:
Self.Diag(Loc, diag::err_typecheck_cond_incompatible_operands)
<< LHS->getType() << RHS->getType()
<< LHS->getSourceRange() << RHS->getSourceRange();
return true;
- case Sema::OR_Ambiguous:
+ case OR_Ambiguous:
Self.Diag(Loc, diag::err_conditional_ambiguous_ovl)
<< LHS->getType() << RHS->getType()
<< LHS->getSourceRange() << RHS->getSourceRange();
@@ -1597,7 +1615,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
// the viable candidates.
break;
- case Sema::OR_Deleted:
+ case OR_Deleted:
assert(false && "Conditional operator has only built-in overloads");
break;
}
@@ -1788,6 +1806,11 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
QualType Composite = FindCompositePointerType(LHS, RHS);
if (!Composite.isNull())
return Composite;
+
+ // Similarly, attempt to find composite type of twp objective-c pointers.
+ Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc);
+ if (!Composite.isNull())
+ return Composite;
// Fourth bullet is same for pointers-to-member. However, the possible
// conversions are far more limited: we have null-to-pointer, upcast of
@@ -1882,8 +1905,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
assert(getLangOptions().CPlusPlus && "This function assumes C++");
QualType T1 = E1->getType(), T2 = E2->getType();
- if (!T1->isPointerType() && !T1->isMemberPointerType() &&
- !T2->isPointerType() && !T2->isMemberPointerType())
+ if (!T1->isAnyPointerType() && !T1->isMemberPointerType() &&
+ !T2->isAnyPointerType() && !T2->isMemberPointerType())
return QualType();
// C++0x 5.9p2
@@ -2070,14 +2093,17 @@ Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr,
bool ShouldDestroyTemps) {
assert(SubExpr && "sub expression can't be null!");
- if (ExprTemporaries.empty())
+ unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
+ assert(ExprTemporaries.size() >= FirstTemporary);
+ if (ExprTemporaries.size() == FirstTemporary)
return SubExpr;
Expr *E = CXXExprWithTemporaries::Create(Context, SubExpr,
- &ExprTemporaries[0],
- ExprTemporaries.size(),
+ &ExprTemporaries[FirstTemporary],
+ ExprTemporaries.size() - FirstTemporary,
ShouldDestroyTemps);
- ExprTemporaries.clear();
+ ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary,
+ ExprTemporaries.end());
return E;
}
@@ -2164,15 +2190,13 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
CXXMethodDecl *Method) {
+ if (PerformObjectArgumentInitialization(Exp, Method))
+ assert(0 && "Calling BuildCXXMemberCallExpr with invalid call?");
+
MemberExpr *ME =
new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method,
SourceLocation(), Method->getType());
- QualType ResultType;
- if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(Method))
- ResultType = Conv->getConversionType().getNonReferenceType();
- else
- ResultType = Method->getResultType().getNonReferenceType();
-
+ QualType ResultType = Method->getResultType().getNonReferenceType();
MarkDeclarationReferenced(Exp->getLocStart(), Method);
CXXMemberCallExpr *CE =
new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType,
@@ -2208,11 +2232,7 @@ Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc,
case CastExpr::CK_UserDefinedConversion: {
assert(!From->getType()->isPointerType() && "Arg can't have pointer type!");
-
- // Cast to base if needed.
- if (PerformObjectArgumentInitialization(From, Method))
- return ExprError();
-
+
// Create an implicit call expr that calls it.
CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method);
return MaybeBindToTemporary(CE);
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 2eba704..4518465 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -15,11 +15,13 @@
//
//===----------------------------------------------------------------------===//
+#include "SemaInit.h"
#include "Sema.h"
#include "clang/Parse/Designator.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "llvm/Support/ErrorHandling.h"
#include <map>
using namespace clang;
@@ -76,7 +78,7 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType,
OverloadCandidateSet CandidateSet;
if (S.IsUserDefinedConversion(Init, DeclType, ICS.UserDefined,
CandidateSet,
- true, false, false) != S.OR_Ambiguous)
+ true, false, false) != OR_Ambiguous)
return S.Diag(Init->getSourceRange().getBegin(),
diag::err_typecheck_convert_incompatible)
<< DeclType << Init->getType() << "initializing"
@@ -230,13 +232,20 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+ // FIXME: Poor location information
+ InitializationKind InitKind
+ = InitializationKind::CreateCopy(Init->getLocStart(),
+ SourceLocation());
+ if (DirectInit)
+ InitKind = InitializationKind::CreateDirect(Init->getLocStart(),
+ SourceLocation(),
+ SourceLocation());
CXXConstructorDecl *Constructor
= PerformInitializationByConstructor(DeclType,
MultiExprArg(*this,
(void **)&Init, 1),
InitLoc, Init->getSourceRange(),
- InitEntity,
- DirectInit? IK_Direct : IK_Copy,
+ InitEntity, InitKind,
ConstructorArgs);
if (!Constructor)
return true;
@@ -637,8 +646,8 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
if (T->isScalarType() && !TopLevelObject)
SemaRef.Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init)
<< IList->getSourceRange()
- << CodeModificationHint::CreateRemoval(SourceRange(IList->getLocStart()))
- << CodeModificationHint::CreateRemoval(SourceRange(IList->getLocEnd()));
+ << CodeModificationHint::CreateRemoval(IList->getLocStart())
+ << CodeModificationHint::CreateRemoval(IList->getLocEnd());
}
void InitListChecker::CheckListElementTypes(InitListExpr *IList,
@@ -1875,12 +1884,13 @@ bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) {
if (ClassDecl->hasUserDeclaredConstructor()) {
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+ // FIXME: Poor location information
CXXConstructorDecl *Constructor
= PerformInitializationByConstructor(Type,
MultiExprArg(*this, 0, 0),
Loc, SourceRange(Loc),
DeclarationName(),
- IK_Direct,
+ InitializationKind::CreateValue(Loc, Loc, Loc),
ConstructorArgs);
if (!Constructor)
return true;
@@ -1908,3 +1918,1379 @@ bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) {
return false;
}
+
+//===----------------------------------------------------------------------===//
+// Initialization entity
+//===----------------------------------------------------------------------===//
+
+void InitializedEntity::InitDeclLoc() {
+ assert((Kind == EK_Variable || Kind == EK_Parameter || Kind == EK_Member) &&
+ "InitDeclLoc cannot be used with non-declaration entities.");
+
+ if (TypeSourceInfo *DI = VariableOrMember->getTypeSourceInfo()) {
+ TL = DI->getTypeLoc();
+ return;
+ }
+
+ // FIXME: Once we've gone through the effort to create the fake
+ // TypeSourceInfo, should we cache it in the declaration?
+ // (If not, we "leak" it).
+ TypeSourceInfo *DI = VariableOrMember->getASTContext()
+ .CreateTypeSourceInfo(VariableOrMember->getType());
+ DI->getTypeLoc().initialize(VariableOrMember->getLocation());
+ TL = DI->getTypeLoc();
+}
+
+InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context,
+ CXXBaseSpecifier *Base)
+{
+ InitializedEntity Result;
+ Result.Kind = EK_Base;
+ Result.Base = Base;
+ // FIXME: CXXBaseSpecifier should store a TypeLoc.
+ TypeSourceInfo *DI = Context.CreateTypeSourceInfo(Base->getType());
+ DI->getTypeLoc().initialize(Base->getSourceRange().getBegin());
+ Result.TL = DI->getTypeLoc();
+ return Result;
+}
+
+//===----------------------------------------------------------------------===//
+// Initialization sequence
+//===----------------------------------------------------------------------===//
+
+void InitializationSequence::Step::Destroy() {
+ switch (Kind) {
+ case SK_ResolveAddressOfOverloadedFunction:
+ case SK_CastDerivedToBaseRValue:
+ case SK_CastDerivedToBaseLValue:
+ case SK_BindReference:
+ case SK_BindReferenceToTemporary:
+ case SK_UserConversion:
+ case SK_QualificationConversionRValue:
+ case SK_QualificationConversionLValue:
+ case SK_ListInitialization:
+ case SK_ConstructorInitialization:
+ case SK_ZeroInitialization:
+ break;
+
+ case SK_ConversionSequence:
+ delete ICS;
+ }
+}
+
+void InitializationSequence::AddAddressOverloadResolutionStep(
+ FunctionDecl *Function) {
+ Step S;
+ S.Kind = SK_ResolveAddressOfOverloadedFunction;
+ S.Type = Function->getType();
+ S.Function = Function;
+ Steps.push_back(S);
+}
+
+void InitializationSequence::AddDerivedToBaseCastStep(QualType BaseType,
+ bool IsLValue) {
+ Step S;
+ S.Kind = IsLValue? SK_CastDerivedToBaseLValue : SK_CastDerivedToBaseRValue;
+ S.Type = BaseType;
+ Steps.push_back(S);
+}
+
+void InitializationSequence::AddReferenceBindingStep(QualType T,
+ bool BindingTemporary) {
+ Step S;
+ S.Kind = BindingTemporary? SK_BindReferenceToTemporary : SK_BindReference;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
+void InitializationSequence::AddUserConversionStep(FunctionDecl *Function,
+ QualType T) {
+ Step S;
+ S.Kind = SK_UserConversion;
+ S.Type = T;
+ S.Function = Function;
+ Steps.push_back(S);
+}
+
+void InitializationSequence::AddQualificationConversionStep(QualType Ty,
+ bool IsLValue) {
+ Step S;
+ S.Kind = IsLValue? SK_QualificationConversionLValue
+ : SK_QualificationConversionRValue;
+ S.Type = Ty;
+ Steps.push_back(S);
+}
+
+void InitializationSequence::AddConversionSequenceStep(
+ const ImplicitConversionSequence &ICS,
+ QualType T) {
+ Step S;
+ S.Kind = SK_ConversionSequence;
+ S.Type = T;
+ S.ICS = new ImplicitConversionSequence(ICS);
+ Steps.push_back(S);
+}
+
+void InitializationSequence::AddListInitializationStep(QualType T) {
+ Step S;
+ S.Kind = SK_ListInitialization;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
+void
+InitializationSequence::AddConstructorInitializationStep(
+ CXXConstructorDecl *Constructor,
+ QualType T) {
+ Step S;
+ S.Kind = SK_ConstructorInitialization;
+ S.Type = T;
+ S.Function = Constructor;
+ Steps.push_back(S);
+}
+
+void InitializationSequence::AddZeroInitializationStep(QualType T) {
+ Step S;
+ S.Kind = SK_ZeroInitialization;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
+void InitializationSequence::SetOverloadFailure(FailureKind Failure,
+ OverloadingResult Result) {
+ SequenceKind = FailedSequence;
+ this->Failure = Failure;
+ this->FailedOverloadResult = Result;
+}
+
+//===----------------------------------------------------------------------===//
+// Attempt initialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Attempt list initialization (C++0x [dcl.init.list])
+static void TryListInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ InitListExpr *InitList,
+ InitializationSequence &Sequence) {
+ // FIXME: We only perform rudimentary checking of list
+ // initializations at this point, then assume that any list
+ // initialization of an array, aggregate, or scalar will be
+ // well-formed. We we actually "perform" list initialization, we'll
+ // do all of the necessary checking. C++0x initializer lists will
+ // force us to perform more checking here.
+ Sequence.setSequenceKind(InitializationSequence::ListInitialization);
+
+ QualType DestType = Entity.getType().getType();
+
+ // C++ [dcl.init]p13:
+ // If T is a scalar type, then a declaration of the form
+ //
+ // T x = { a };
+ //
+ // is equivalent to
+ //
+ // T x = a;
+ if (DestType->isScalarType()) {
+ if (InitList->getNumInits() > 1 && S.getLangOptions().CPlusPlus) {
+ Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar);
+ return;
+ }
+
+ // Assume scalar initialization from a single value works.
+ } else if (DestType->isAggregateType()) {
+ // Assume aggregate initialization works.
+ } else if (DestType->isVectorType()) {
+ // Assume vector initialization works.
+ } else if (DestType->isReferenceType()) {
+ // FIXME: C++0x defines behavior for this.
+ Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList);
+ return;
+ } else if (DestType->isRecordType()) {
+ // FIXME: C++0x defines behavior for this
+ Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType);
+ }
+
+ // Add a general "list initialization" step.
+ Sequence.AddListInitializationStep(DestType);
+}
+
+/// \brief Try a reference initialization that involves calling a conversion
+/// function.
+///
+/// FIXME: look intos DRs 656, 896
+static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr *Initializer,
+ bool AllowRValues,
+ InitializationSequence &Sequence) {
+ QualType DestType = Entity.getType().getType();
+ QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
+ QualType T1 = cv1T1.getUnqualifiedType();
+ QualType cv2T2 = Initializer->getType();
+ QualType T2 = cv2T2.getUnqualifiedType();
+
+ bool DerivedToBase;
+ assert(!S.CompareReferenceRelationship(Initializer->getLocStart(),
+ T1, T2, DerivedToBase) &&
+ "Must have incompatible references when binding via conversion");
+ (void)DerivedToBase;
+
+ // Build the candidate set directly in the initialization sequence
+ // structure, so that it will persist if we fail.
+ OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
+ CandidateSet.clear();
+
+ // Determine whether we are allowed to call explicit constructors or
+ // explicit conversion operators.
+ bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct;
+
+ const RecordType *T1RecordType = 0;
+ if (AllowRValues && (T1RecordType = T1->getAs<RecordType>())) {
+ // The type we're converting to is a class type. Enumerate its constructors
+ // to see if there is a suitable conversion.
+ CXXRecordDecl *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getDecl());
+
+ DeclarationName ConstructorName
+ = S.Context.DeclarationNames.getCXXConstructorName(
+ S.Context.getCanonicalType(T1).getUnqualifiedType());
+ DeclContext::lookup_iterator Con, ConEnd;
+ for (llvm::tie(Con, ConEnd) = T1RecordDecl->lookup(ConstructorName);
+ Con != ConEnd; ++Con) {
+ // 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 (!Constructor->isInvalidDecl() &&
+ Constructor->isConvertingConstructor(AllowExplicit)) {
+ if (ConstructorTmpl)
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0,
+ &Initializer, 1, CandidateSet);
+ else
+ S.AddOverloadCandidate(Constructor, &Initializer, 1, CandidateSet);
+ }
+ }
+ }
+
+ if (const RecordType *T2RecordType = T2->getAs<RecordType>()) {
+ // The type we're converting from is a class type, enumerate its conversion
+ // functions.
+ CXXRecordDecl *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getDecl());
+
+ // Determine the type we are converting to. If we are allowed to
+ // convert to an rvalue, take the type that the destination type
+ // refers to.
+ QualType ToType = AllowRValues? cv1T1 : DestType;
+
+ const UnresolvedSet *Conversions
+ = T2RecordDecl->getVisibleConversionFunctions();
+ for (UnresolvedSet::iterator I = Conversions->begin(),
+ E = Conversions->end();
+ I != E; ++I) {
+ NamedDecl *D = *I;
+ CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+ FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
+ CXXConversionDecl *Conv;
+ if (ConvTemplate)
+ Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ else
+ Conv = cast<CXXConversionDecl>(*I);
+
+ // If the conversion function doesn't return a reference type,
+ // it can't be considered for this conversion unless we're allowed to
+ // consider rvalues.
+ // FIXME: Do we need to make sure that we only consider conversion
+ // candidates with reference-compatible results? That might be needed to
+ // break recursion.
+ if ((AllowExplicit || !Conv->isExplicit()) &&
+ (AllowRValues || Conv->getConversionType()->isLValueReferenceType())){
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, Initializer,
+ ToType, CandidateSet);
+ else
+ S.AddConversionCandidate(Conv, ActingDC, Initializer, cv1T1,
+ CandidateSet);
+ }
+ }
+ }
+
+ SourceLocation DeclLoc = Initializer->getLocStart();
+
+ // Perform overload resolution. If it fails, return the failed result.
+ OverloadCandidateSet::iterator Best;
+ if (OverloadingResult Result
+ = S.BestViableFunction(CandidateSet, DeclLoc, Best))
+ return Result;
+
+ FunctionDecl *Function = Best->Function;
+
+ // Compute the returned type of the conversion.
+ if (isa<CXXConversionDecl>(Function))
+ T2 = Function->getResultType();
+ else
+ T2 = cv1T1;
+
+ // Add the user-defined conversion step.
+ Sequence.AddUserConversionStep(Function, T2.getNonReferenceType());
+
+ // Determine whether we need to perform derived-to-base or
+ // cv-qualification adjustments.
+ bool NewDerivedToBase = false;
+ Sema::ReferenceCompareResult NewRefRelationship
+ = S.CompareReferenceRelationship(DeclLoc, T1, T2.getNonReferenceType(),
+ NewDerivedToBase);
+ assert(NewRefRelationship != Sema::Ref_Incompatible &&
+ "Overload resolution picked a bad conversion function");
+ (void)NewRefRelationship;
+ if (NewDerivedToBase)
+ Sequence.AddDerivedToBaseCastStep(
+ S.Context.getQualifiedType(T1,
+ T2.getNonReferenceType().getQualifiers()),
+ /*isLValue=*/true);
+
+ if (cv1T1.getQualifiers() != T2.getNonReferenceType().getQualifiers())
+ Sequence.AddQualificationConversionStep(cv1T1, T2->isReferenceType());
+
+ Sequence.AddReferenceBindingStep(cv1T1, !T2->isReferenceType());
+ return OR_Success;
+}
+
+/// \brief Attempt reference initialization (C++0x [dcl.init.list])
+static void TryReferenceInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr *Initializer,
+ InitializationSequence &Sequence) {
+ Sequence.setSequenceKind(InitializationSequence::ReferenceBinding);
+
+ QualType DestType = Entity.getType().getType();
+ QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
+ QualType T1 = cv1T1.getUnqualifiedType();
+ QualType cv2T2 = Initializer->getType();
+ QualType T2 = cv2T2.getUnqualifiedType();
+ SourceLocation DeclLoc = Initializer->getLocStart();
+
+ // 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) {
+ FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Initializer,
+ T1,
+ false);
+ if (!Fn) {
+ Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
+ return;
+ }
+
+ Sequence.AddAddressOverloadResolutionStep(Fn);
+ cv2T2 = Fn->getType();
+ 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);
+ Sema::ReferenceCompareResult RefRelationship
+ = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase);
+
+ // C++0x [dcl.init.ref]p5:
+ // A reference to type "cv1 T1" is initialized by an expression of type
+ // "cv2 T2" as follows:
+ //
+ // - If the reference is an lvalue reference and the initializer
+ // expression
+ OverloadingResult ConvOvlResult = OR_Success;
+ if (isLValueRef) {
+ if (InitLvalue == Expr::LV_Valid &&
+ RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
+ // - is an lvalue (but is not a bit-field), and "cv1 T1" is
+ // reference-compatible with "cv2 T2," or
+ //
+ // Per C++ [over.best.ics]p2, we ignore whether the lvalue is a
+ // bit-field when we're determining whether the reference initialization
+ // can occur. This property will be checked by PerformInitialization.
+ if (DerivedToBase)
+ Sequence.AddDerivedToBaseCastStep(
+ S.Context.getQualifiedType(T1, cv2T2.getQualifiers()),
+ /*isLValue=*/true);
+ if (cv1T1.getQualifiers() != cv2T2.getQualifiers())
+ Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/true);
+ Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/false);
+ return;
+ }
+
+ // - 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" (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 (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType()) {
+ ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, Kind,
+ Initializer,
+ /*AllowRValues=*/false,
+ Sequence);
+ if (ConvOvlResult == OR_Success)
+ return;
+ }
+ }
+
+ // - Otherwise, the reference shall be an lvalue reference 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 (!((isLValueRef && cv1T1.getCVRQualifiers() == Qualifiers::Const) ||
+ (isRValueRef && InitLvalue != Expr::LV_Valid))) {
+ if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty())
+ Sequence.SetOverloadFailure(
+ InitializationSequence::FK_ReferenceInitOverloadFailed,
+ ConvOvlResult);
+ else if (isLValueRef)
+ Sequence.SetFailed(InitLvalue == Expr::LV_Valid
+ ? (RefRelationship == Sema::Ref_Related
+ ? InitializationSequence::FK_ReferenceInitDropsQualifiers
+ : InitializationSequence::FK_NonConstLValueReferenceBindingToUnrelated)
+ : InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary);
+ else
+ Sequence.SetFailed(
+ InitializationSequence::FK_RValueReferenceBindingToLValue);
+
+ return;
+ }
+
+ // - If T1 and T2 are class types and
+ if (T1->isRecordType() && T2->isRecordType()) {
+ // - the initializer expression is an rvalue and "cv1 T1" is
+ // reference-compatible with "cv2 T2", or
+ if (InitLvalue != Expr::LV_Valid &&
+ RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
+ if (DerivedToBase)
+ Sequence.AddDerivedToBaseCastStep(
+ S.Context.getQualifiedType(T1, cv2T2.getQualifiers()),
+ /*isLValue=*/false);
+ if (cv1T1.getQualifiers() != cv2T2.getQualifiers())
+ Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/false);
+ Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true);
+ return;
+ }
+
+ // - 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)),
+ if (RefRelationship == Sema::Ref_Incompatible) {
+ ConvOvlResult = TryRefInitWithConversionFunction(S, Entity,
+ Kind, Initializer,
+ /*AllowRValues=*/true,
+ Sequence);
+ if (ConvOvlResult)
+ Sequence.SetOverloadFailure(
+ InitializationSequence::FK_ReferenceInitOverloadFailed,
+ ConvOvlResult);
+
+ return;
+ }
+
+ Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers);
+ return;
+ }
+
+ // - If the initializer expression is an rvalue, with T2 an array type,
+ // and "cv1 T1" is reference-compatible with "cv2 T2," the reference
+ // is bound to the object represented by the rvalue (see 3.10).
+ // FIXME: How can an array type be reference-compatible with anything?
+ // Don't we mean the element types of T1 and T2?
+
+ // - 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. [...]
+ // Determine whether we are allowed to call explicit constructors or
+ // explicit conversion operators.
+ bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct);
+ ImplicitConversionSequence ICS
+ = S.TryImplicitConversion(Initializer, cv1T1,
+ /*SuppressUserConversions=*/false, AllowExplicit,
+ /*ForceRValue=*/false,
+ /*FIXME:InOverloadResolution=*/false,
+ /*UserCast=*/Kind.isExplicitCast());
+
+ if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) {
+ // FIXME: Use the conversion function set stored in ICS to turn
+ // this into an overloading ambiguity diagnostic. However, we need
+ // to keep that set as an OverloadCandidateSet rather than as some
+ // other kind of set.
+ Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed);
+ return;
+ }
+
+ // [...] 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 &&
+ !cv1T1.isAtLeastAsQualifiedAs(cv2T2)) {
+ Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers);
+ return;
+ }
+
+ // Perform the actual conversion.
+ Sequence.AddConversionSequenceStep(ICS, cv1T1);
+ Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true);
+ return;
+}
+
+/// \brief Attempt character array initialization from a string literal
+/// (C++ [dcl.init.string], C99 6.7.8).
+static void TryStringLiteralInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr *Initializer,
+ InitializationSequence &Sequence) {
+ // FIXME: Implement!
+}
+
+/// \brief Attempt initialization by constructor (C++ [dcl.init]), which
+/// enumerates the constructors of the initialized entity and performs overload
+/// resolution to select the best.
+static void TryConstructorInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr **Args, unsigned NumArgs,
+ QualType DestType,
+ InitializationSequence &Sequence) {
+ Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization);
+
+ // Build the candidate set directly in the initialization sequence
+ // structure, so that it will persist if we fail.
+ OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
+ CandidateSet.clear();
+
+ // Determine whether we are allowed to call explicit constructors or
+ // explicit conversion operators.
+ bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct ||
+ Kind.getKind() == InitializationKind::IK_Value ||
+ Kind.getKind() == InitializationKind::IK_Default);
+
+ // The type we're converting to is a class type. Enumerate its constructors
+ // to see if one is suitable.
+ const RecordType *DestRecordType = DestType->getAs<RecordType>();
+ assert(DestRecordType && "Constructor initialization requires record type");
+ CXXRecordDecl *DestRecordDecl
+ = cast<CXXRecordDecl>(DestRecordType->getDecl());
+
+ 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) {
+ // 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 (!Constructor->isInvalidDecl() &&
+ Constructor->isConvertingConstructor(AllowExplicit)) {
+ if (ConstructorTmpl)
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0,
+ Args, NumArgs, CandidateSet);
+ else
+ S.AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+ }
+ }
+
+ SourceLocation DeclLoc = Kind.getLocation();
+
+ // Perform overload resolution. If it fails, return the failed result.
+ OverloadCandidateSet::iterator Best;
+ if (OverloadingResult Result
+ = S.BestViableFunction(CandidateSet, DeclLoc, Best)) {
+ Sequence.SetOverloadFailure(
+ InitializationSequence::FK_ConstructorOverloadFailed,
+ Result);
+ return;
+ }
+
+ // Add the constructor initialization step. Any cv-qualification conversion is
+ // subsumed by the initialization.
+ Sequence.AddConstructorInitializationStep(
+ cast<CXXConstructorDecl>(Best->Function),
+ DestType);
+}
+
+/// \brief Attempt value initialization (C++ [dcl.init]p7).
+static void TryValueInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ InitializationSequence &Sequence) {
+ // C++ [dcl.init]p5:
+ //
+ // To value-initialize an object of type T means:
+ QualType T = Entity.getType().getType();
+
+ // -- if T is an array type, then each element is value-initialized;
+ while (const ArrayType *AT = S.Context.getAsArrayType(T))
+ T = AT->getElementType();
+
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ // -- if T is a class type (clause 9) with a user-declared
+ // constructor (12.1), then the default constructor for T is
+ // called (and the initialization is ill-formed if T has no
+ // accessible default constructor);
+ //
+ // FIXME: we really want to refer to a single subobject of the array,
+ // but Entity doesn't have a way to capture that (yet).
+ if (ClassDecl->hasUserDeclaredConstructor())
+ return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence);
+
+ // FIXME: non-union class type w/ non-trivial default constructor gets
+ // zero-initialized, then constructor gets called.
+ }
+ }
+
+ Sequence.AddZeroInitializationStep(Entity.getType().getType());
+ Sequence.setSequenceKind(InitializationSequence::ZeroInitialization);
+}
+
+/// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]),
+/// which enumerates all conversion functions and performs overload resolution
+/// to select the best.
+static void TryUserDefinedConversion(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr *Initializer,
+ InitializationSequence &Sequence) {
+ Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion);
+
+ QualType DestType = Entity.getType().getType();
+ assert(!DestType->isReferenceType() && "References are handled elsewhere");
+ QualType SourceType = Initializer->getType();
+ assert((DestType->isRecordType() || SourceType->isRecordType()) &&
+ "Must have a class type to perform a user-defined conversion");
+
+ // Build the candidate set directly in the initialization sequence
+ // structure, so that it will persist if we fail.
+ OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
+ CandidateSet.clear();
+
+ // Determine whether we are allowed to call explicit constructors or
+ // explicit conversion operators.
+ bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct;
+
+ if (const RecordType *DestRecordType = DestType->getAs<RecordType>()) {
+ // The type we're converting to is a class type. Enumerate its constructors
+ // to see if there is a suitable conversion.
+ CXXRecordDecl *DestRecordDecl
+ = cast<CXXRecordDecl>(DestRecordType->getDecl());
+
+ 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) {
+ // 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 (!Constructor->isInvalidDecl() &&
+ Constructor->isConvertingConstructor(AllowExplicit)) {
+ if (ConstructorTmpl)
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0,
+ &Initializer, 1, CandidateSet);
+ else
+ S.AddOverloadCandidate(Constructor, &Initializer, 1, CandidateSet);
+ }
+ }
+ }
+
+ if (const RecordType *SourceRecordType = SourceType->getAs<RecordType>()) {
+ // The type we're converting from is a class type, enumerate its conversion
+ // functions.
+ CXXRecordDecl *SourceRecordDecl
+ = cast<CXXRecordDecl>(SourceRecordType->getDecl());
+
+ const UnresolvedSet *Conversions
+ = SourceRecordDecl->getVisibleConversionFunctions();
+ for (UnresolvedSet::iterator I = Conversions->begin(),
+ E = Conversions->end();
+ I != E; ++I) {
+ NamedDecl *D = *I;
+ CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+ FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
+ CXXConversionDecl *Conv;
+ if (ConvTemplate)
+ Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ else
+ Conv = cast<CXXConversionDecl>(*I);
+
+ if (AllowExplicit || !Conv->isExplicit()) {
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, Initializer,
+ DestType, CandidateSet);
+ else
+ S.AddConversionCandidate(Conv, ActingDC, Initializer, DestType,
+ CandidateSet);
+ }
+ }
+ }
+
+ SourceLocation DeclLoc = Initializer->getLocStart();
+
+ // Perform overload resolution. If it fails, return the failed result.
+ OverloadCandidateSet::iterator Best;
+ if (OverloadingResult Result
+ = S.BestViableFunction(CandidateSet, DeclLoc, Best)) {
+ Sequence.SetOverloadFailure(
+ InitializationSequence::FK_UserConversionOverloadFailed,
+ Result);
+ return;
+ }
+
+ FunctionDecl *Function = Best->Function;
+
+ if (isa<CXXConstructorDecl>(Function)) {
+ // Add the user-defined conversion step. Any cv-qualification conversion is
+ // subsumed by the initialization.
+ Sequence.AddUserConversionStep(Function, DestType);
+ return;
+ }
+
+ // Add the user-defined conversion step that calls the conversion function.
+ QualType ConvType = Function->getResultType().getNonReferenceType();
+ Sequence.AddUserConversionStep(Function, 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;
+ ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
+ ICS.Standard = Best->FinalConversion;
+ Sequence.AddConversionSequenceStep(ICS, DestType);
+ }
+}
+
+/// \brief Attempt an implicit conversion (C++ [conv]) converting from one
+/// non-class type to another.
+static void TryImplicitConversion(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr *Initializer,
+ InitializationSequence &Sequence) {
+ ImplicitConversionSequence ICS
+ = S.TryImplicitConversion(Initializer, Entity.getType().getType(),
+ /*SuppressUserConversions=*/true,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*FIXME:InOverloadResolution=*/false,
+ /*UserCast=*/Kind.isExplicitCast());
+
+ if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) {
+ Sequence.SetFailed(InitializationSequence::FK_ConversionFailed);
+ return;
+ }
+
+ Sequence.AddConversionSequenceStep(ICS, Entity.getType().getType());
+}
+
+InitializationSequence::InitializationSequence(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr **Args,
+ unsigned NumArgs) {
+ ASTContext &Context = S.Context;
+
+ // C++0x [dcl.init]p16:
+ // The semantics of initializers are as follows. The destination type is
+ // the type of the object or reference being initialized and the source
+ // type is the type of the initializer expression. The source type is not
+ // defined when the initializer is a braced-init-list or when it is a
+ // parenthesized list of expressions.
+ QualType DestType = Entity.getType().getType();
+
+ if (DestType->isDependentType() ||
+ Expr::hasAnyTypeDependentArguments(Args, NumArgs)) {
+ SequenceKind = DependentSequence;
+ return;
+ }
+
+ QualType SourceType;
+ Expr *Initializer = 0;
+ if (Kind.getKind() == InitializationKind::IK_Copy) {
+ Initializer = Args[0];
+ if (!isa<InitListExpr>(Initializer))
+ SourceType = Initializer->getType();
+ }
+
+ // - If the initializer is a braced-init-list, the object is
+ // list-initialized (8.5.4).
+ if (InitListExpr *InitList = dyn_cast_or_null<InitListExpr>(Initializer)) {
+ TryListInitialization(S, Entity, Kind, InitList, *this);
+ return;
+ }
+
+ // - If the destination type is a reference type, see 8.5.3.
+ if (DestType->isReferenceType()) {
+ // C++0x [dcl.init.ref]p1:
+ // A variable declared to be a T& or T&&, that is, "reference to type T"
+ // (8.3.2), shall be initialized by an object, or function, of type T or
+ // by an object that can be converted into a T.
+ // (Therefore, multiple arguments are not permitted.)
+ if (NumArgs != 1)
+ SetFailed(FK_TooManyInitsForReference);
+ else
+ TryReferenceInitialization(S, Entity, Kind, Args[0], *this);
+ return;
+ }
+
+ // - If the destination type is an array of characters, an array of
+ // char16_t, an array of char32_t, or an array of wchar_t, and the
+ // initializer is a string literal, see 8.5.2.
+ if (Initializer && IsStringInit(Initializer, DestType, Context)) {
+ TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this);
+ return;
+ }
+
+ // - If the initializer is (), the object is value-initialized.
+ if (Kind.getKind() == InitializationKind::IK_Value) {
+ TryValueInitialization(S, Entity, Kind, *this);
+ return;
+ }
+
+ // - Otherwise, if the destination type is an array, the program is
+ // ill-formed.
+ if (const ArrayType *AT = Context.getAsArrayType(DestType)) {
+ if (AT->getElementType()->isAnyCharacterType())
+ SetFailed(FK_ArrayNeedsInitListOrStringLiteral);
+ else
+ SetFailed(FK_ArrayNeedsInitList);
+
+ return;
+ }
+
+ // - If the destination type is a (possibly cv-qualified) class type:
+ if (DestType->isRecordType()) {
+ // - If the initialization is direct-initialization, or if it is
+ // copy-initialization where the cv-unqualified version of the
+ // source type is the same class as, or a derived class of, the
+ // class of the destination, constructors are considered. [...]
+ if (Kind.getKind() == InitializationKind::IK_Direct ||
+ (Kind.getKind() == InitializationKind::IK_Copy &&
+ (Context.hasSameUnqualifiedType(SourceType, DestType) ||
+ S.IsDerivedFrom(SourceType, DestType))))
+ TryConstructorInitialization(S, Entity, Kind, Args, NumArgs,
+ Entity.getType().getType(), *this);
+ // - Otherwise (i.e., for the remaining copy-initialization cases),
+ // user-defined conversion sequences that can convert from the source
+ // type to the destination type or (when a conversion function is
+ // used) to a derived class thereof are enumerated as described in
+ // 13.3.1.4, and the best one is chosen through overload resolution
+ // (13.3).
+ else
+ TryUserDefinedConversion(S, Entity, Kind, Initializer, *this);
+ return;
+ }
+
+ // - Otherwise, if the source type is a (possibly cv-qualified) class
+ // type, conversion functions are considered.
+ if (SourceType->isRecordType()) {
+ TryUserDefinedConversion(S, Entity, Kind, Initializer, *this);
+ return;
+ }
+
+ // - Otherwise, the initial value of the object being initialized is the
+ // (possibly converted) value of the initializer expression. Standard
+ // conversions (Clause 4) will be used, if necessary, to convert the
+ // initializer expression to the cv-unqualified version of the
+ // destination type; no user-defined conversions are considered.
+ TryImplicitConversion(S, Entity, Kind, Initializer, *this);
+}
+
+InitializationSequence::~InitializationSequence() {
+ for (llvm::SmallVectorImpl<Step>::iterator Step = Steps.begin(),
+ StepEnd = Steps.end();
+ Step != StepEnd; ++Step)
+ Step->Destroy();
+}
+
+//===----------------------------------------------------------------------===//
+// Perform initialization
+//===----------------------------------------------------------------------===//
+
+Action::OwningExprResult
+InitializationSequence::Perform(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Action::MultiExprArg Args,
+ QualType *ResultType) {
+ if (SequenceKind == FailedSequence) {
+ unsigned NumArgs = Args.size();
+ Diagnose(S, Entity, Kind, (Expr **)Args.release(), NumArgs);
+ return S.ExprError();
+ }
+
+ if (SequenceKind == DependentSequence) {
+ // If the declaration is a non-dependent, incomplete array type
+ // that has an initializer, then its type will be completed once
+ // the initializer is instantiated.
+ if (ResultType && !Entity.getType().getType()->isDependentType() &&
+ Args.size() == 1) {
+ QualType DeclType = Entity.getType().getType();
+ if (const IncompleteArrayType *ArrayT
+ = S.Context.getAsIncompleteArrayType(DeclType)) {
+ // FIXME: We don't currently have the ability to accurately
+ // compute the length of an initializer list without
+ // performing full type-checking of the initializer list
+ // (since we have to determine where braces are implicitly
+ // introduced and such). So, we fall back to making the array
+ // type a dependently-sized array type with no specified
+ // bound.
+ if (isa<InitListExpr>((Expr *)Args.get()[0])) {
+ SourceRange Brackets;
+ // Scavange the location of the brackets from the entity, if we can.
+ if (isa<IncompleteArrayTypeLoc>(Entity.getType())) {
+ IncompleteArrayTypeLoc ArrayLoc
+ = cast<IncompleteArrayTypeLoc>(Entity.getType());
+ Brackets = ArrayLoc.getBracketsRange();
+ }
+
+ *ResultType
+ = S.Context.getDependentSizedArrayType(ArrayT->getElementType(),
+ /*NumElts=*/0,
+ ArrayT->getSizeModifier(),
+ ArrayT->getIndexTypeCVRQualifiers(),
+ Brackets);
+ }
+
+ }
+ }
+
+ if (Kind.getKind() == InitializationKind::IK_Copy)
+ return Sema::OwningExprResult(S, Args.release()[0]);
+
+ unsigned NumArgs = Args.size();
+ return S.Owned(new (S.Context) ParenListExpr(S.Context,
+ SourceLocation(),
+ (Expr **)Args.release(),
+ NumArgs,
+ SourceLocation()));
+ }
+
+ QualType DestType = Entity.getType().getType().getNonReferenceType();
+ if (ResultType)
+ *ResultType = Entity.getType().getType();
+
+ Sema::OwningExprResult CurInit(S);
+ // For copy initialization and any other initialization forms that
+ // only have a single initializer, we start with the (only)
+ // initializer we have.
+ // FIXME: DPG is not happy about this. There's confusion regarding whether
+ // we're supposed to start the conversion from the solitary initializer or
+ // from the set of arguments.
+ if (Kind.getKind() == InitializationKind::IK_Copy ||
+ SequenceKind != ConstructorInitialization) {
+ assert(Args.size() == 1);
+ CurInit = Sema::OwningExprResult(S, Args.release()[0]);
+ if (CurInit.isInvalid())
+ return S.ExprError();
+ }
+
+ // Walk through the computed steps for the initialization sequence,
+ // performing the specified conversions along the way.
+ for (step_iterator Step = step_begin(), StepEnd = step_end();
+ Step != StepEnd; ++Step) {
+ if (CurInit.isInvalid())
+ return S.ExprError();
+
+ Expr *CurInitExpr = (Expr *)CurInit.get();
+ QualType SourceType = CurInitExpr->getType();
+
+ switch (Step->Kind) {
+ case SK_ResolveAddressOfOverloadedFunction:
+ // Overload resolution determined which function invoke; update the
+ // initializer to reflect that choice.
+ CurInit = S.FixOverloadedFunctionReference(move(CurInit), Step->Function);
+ break;
+
+ case SK_CastDerivedToBaseRValue:
+ case SK_CastDerivedToBaseLValue: {
+ // We have a derived-to-base cast that produces either an rvalue or an
+ // lvalue. Perform that cast.
+
+ // 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))
+ return S.ExprError();
+
+ CurInit = S.Owned(new (S.Context) ImplicitCastExpr(Step->Type,
+ CastExpr::CK_DerivedToBase,
+ (Expr*)CurInit.release(),
+ Step->Kind == SK_CastDerivedToBaseLValue));
+ break;
+ }
+
+ case SK_BindReference:
+ if (FieldDecl *BitField = CurInitExpr->getBitField()) {
+ // References cannot bind to bit fields (C++ [dcl.init.ref]p5).
+ S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield)
+ << Entity.getType().getType().isVolatileQualified()
+ << BitField->getDeclName()
+ << CurInitExpr->getSourceRange();
+ S.Diag(BitField->getLocation(), diag::note_bitfield_decl);
+ return S.ExprError();
+ }
+
+ // Reference binding does not have any corresponding ASTs.
+
+ // Check exception specifications
+ if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType))
+ return S.ExprError();
+ break;
+
+ case SK_BindReferenceToTemporary:
+ // Check exception specifications
+ if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType))
+ return S.ExprError();
+
+ // FIXME: At present, we have no AST to describe when we need to make a
+ // temporary to bind a reference to. We should.
+ break;
+
+ case SK_UserConversion: {
+ // We have a user-defined conversion that invokes either a constructor
+ // or a conversion function.
+ CastExpr::CastKind CastKind = CastExpr::CK_Unknown;
+ if (CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(Step->Function)) {
+ // Build a call to the selected constructor.
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
+ SourceLocation Loc = CurInitExpr->getLocStart();
+ CurInit.release(); // Ownership transferred into MultiExprArg, below.
+
+ // Determine the arguments required to actually perform the constructor
+ // call.
+ if (S.CompleteConstructorCall(Constructor,
+ Sema::MultiExprArg(S,
+ (void **)&CurInitExpr,
+ 1),
+ Loc, ConstructorArgs))
+ return S.ExprError();
+
+ // Build the an expression that constructs a temporary.
+ CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor,
+ move_arg(ConstructorArgs));
+ if (CurInit.isInvalid())
+ return S.ExprError();
+
+ CastKind = CastExpr::CK_ConstructorConversion;
+ } else {
+ // Build a call to the conversion function.
+ CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Step->Function);
+
+ // FIXME: Should we move this initialization into a separate
+ // derived-to-base conversion? I believe the answer is "no", because
+ // we don't want to turn off access control here for c-style casts.
+ if (S.PerformObjectArgumentInitialization(CurInitExpr, Conversion))
+ return S.ExprError();
+
+ // Do a little dance to make sure that CurInit has the proper
+ // pointer.
+ CurInit.release();
+
+ // Build the actual call to the conversion function.
+ CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, Conversion));
+ if (CurInit.isInvalid() || !CurInit.get())
+ return S.ExprError();
+
+ CastKind = CastExpr::CK_UserDefinedConversion;
+ }
+
+ CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+ CurInitExpr = CurInit.takeAs<Expr>();
+ CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(),
+ CastKind,
+ CurInitExpr,
+ false));
+ break;
+ }
+
+ case SK_QualificationConversionLValue:
+ case SK_QualificationConversionRValue:
+ // Perform a qualification conversion; these can never go wrong.
+ S.ImpCastExprToType(CurInitExpr, Step->Type,
+ CastExpr::CK_NoOp,
+ Step->Kind == SK_QualificationConversionLValue);
+ CurInit.release();
+ CurInit = S.Owned(CurInitExpr);
+ break;
+
+ case SK_ConversionSequence:
+ if (S.PerformImplicitConversion(CurInitExpr, Step->Type, "converting",
+ false, false, *Step->ICS))
+ return S.ExprError();
+
+ CurInit.release();
+ CurInit = S.Owned(CurInitExpr);
+ break;
+
+ case SK_ListInitialization: {
+ InitListExpr *InitList = cast<InitListExpr>(CurInitExpr);
+ QualType Ty = Step->Type;
+ if (S.CheckInitList(InitList, ResultType? *ResultType : Ty))
+ return S.ExprError();
+
+ CurInit.release();
+ CurInit = S.Owned(InitList);
+ break;
+ }
+
+ case SK_ConstructorInitialization: {
+ CXXConstructorDecl *Constructor
+ = cast<CXXConstructorDecl>(Step->Function);
+
+ // Build a call to the selected constructor.
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
+ SourceLocation Loc = Kind.getLocation();
+
+ // Determine the arguments required to actually perform the constructor
+ // call.
+ if (S.CompleteConstructorCall(Constructor, move(Args),
+ Loc, ConstructorArgs))
+ return S.ExprError();
+
+ // Build the an expression that constructs a temporary.
+ CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor,
+ move_arg(ConstructorArgs));
+ if (CurInit.isInvalid())
+ return S.ExprError();
+
+ CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+ break;
+ }
+
+ case SK_ZeroInitialization: {
+ if (Kind.getKind() == InitializationKind::IK_Value)
+ CurInit = S.Owned(new (S.Context) CXXZeroInitValueExpr(Step->Type,
+ Kind.getRange().getBegin(),
+ Kind.getRange().getEnd()));
+ else
+ CurInit = S.Owned(new (S.Context) ImplicitValueInitExpr(Step->Type));
+ break;
+ }
+ }
+ }
+
+ return move(CurInit);
+}
+
+//===----------------------------------------------------------------------===//
+// Diagnose initialization failures
+//===----------------------------------------------------------------------===//
+bool InitializationSequence::Diagnose(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr **Args, unsigned NumArgs) {
+ if (SequenceKind != FailedSequence)
+ return false;
+
+ QualType DestType = Entity.getType().getType();
+ switch (Failure) {
+ case FK_TooManyInitsForReference:
+ S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits)
+ << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd());
+ break;
+
+ case FK_ArrayNeedsInitList:
+ case FK_ArrayNeedsInitListOrStringLiteral:
+ S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list)
+ << (Failure == FK_ArrayNeedsInitListOrStringLiteral);
+ break;
+
+ case FK_AddressOfOverloadFailed:
+ S.ResolveAddressOfOverloadedFunction(Args[0],
+ DestType.getNonReferenceType(),
+ true);
+ break;
+
+ case FK_ReferenceInitOverloadFailed:
+ case FK_UserConversionOverloadFailed:
+ switch (FailedOverloadResult) {
+ case OR_Ambiguous:
+ S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition)
+ << Args[0]->getType() << DestType.getNonReferenceType()
+ << Args[0]->getSourceRange();
+ S.PrintOverloadCandidates(FailedCandidateSet, true);
+ break;
+
+ case OR_No_Viable_Function:
+ S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition)
+ << Args[0]->getType() << DestType.getNonReferenceType()
+ << Args[0]->getSourceRange();
+ S.PrintOverloadCandidates(FailedCandidateSet, false);
+ break;
+
+ case OR_Deleted: {
+ S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function)
+ << Args[0]->getType() << DestType.getNonReferenceType()
+ << Args[0]->getSourceRange();
+ OverloadCandidateSet::iterator Best;
+ OverloadingResult Ovl = S.BestViableFunction(FailedCandidateSet,
+ Kind.getLocation(),
+ Best);
+ if (Ovl == OR_Deleted) {
+ S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
+ << Best->Function->isDeleted();
+ } else {
+ llvm_unreachable("Inconsistent overload resolution?");
+ }
+ break;
+ }
+
+ case OR_Success:
+ llvm_unreachable("Conversion did not fail!");
+ break;
+ }
+ break;
+
+ case FK_NonConstLValueReferenceBindingToTemporary:
+ case FK_NonConstLValueReferenceBindingToUnrelated:
+ S.Diag(Kind.getLocation(),
+ Failure == FK_NonConstLValueReferenceBindingToTemporary
+ ? diag::err_lvalue_reference_bind_to_temporary
+ : diag::err_lvalue_reference_bind_to_unrelated)
+ << DestType.getNonReferenceType()
+ << Args[0]->getType()
+ << Args[0]->getSourceRange();
+ break;
+
+ case FK_RValueReferenceBindingToLValue:
+ S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref)
+ << Args[0]->getSourceRange();
+ break;
+
+ case FK_ReferenceInitDropsQualifiers:
+ S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
+ << DestType.getNonReferenceType()
+ << Args[0]->getType()
+ << Args[0]->getSourceRange();
+ break;
+
+ case FK_ReferenceInitFailed:
+ S.Diag(Kind.getLocation(), diag::err_reference_bind_failed)
+ << DestType.getNonReferenceType()
+ << (Args[0]->isLvalue(S.Context) == Expr::LV_Valid)
+ << Args[0]->getType()
+ << Args[0]->getSourceRange();
+ break;
+
+ case FK_ConversionFailed:
+ S.Diag(Kind.getLocation(), diag::err_cannot_initialize_decl_noname)
+ << DestType
+ << (Args[0]->isLvalue(S.Context) == Expr::LV_Valid)
+ << Args[0]->getType()
+ << Args[0]->getSourceRange();
+ break;
+
+ case FK_TooManyInitsForScalar: {
+ InitListExpr *InitList = cast<InitListExpr>(Args[0]);
+
+ S.Diag(Kind.getLocation(), diag::err_excess_initializers)
+ << /*scalar=*/2
+ << SourceRange(InitList->getInit(1)->getLocStart(),
+ InitList->getLocEnd());
+ break;
+ }
+
+ case FK_ReferenceBindingToInitList:
+ S.Diag(Kind.getLocation(), diag::err_reference_bind_init_list)
+ << DestType.getNonReferenceType() << Args[0]->getSourceRange();
+ break;
+
+ case FK_InitListBadDestinationType:
+ S.Diag(Kind.getLocation(), diag::err_init_list_bad_dest_type)
+ << (DestType->isRecordType()) << DestType << Args[0]->getSourceRange();
+ break;
+
+ case FK_ConstructorOverloadFailed: {
+ SourceRange ArgsRange;
+ if (NumArgs)
+ ArgsRange = SourceRange(Args[0]->getLocStart(),
+ Args[NumArgs - 1]->getLocEnd());
+
+ // FIXME: Using "DestType" for the entity we're printing is probably
+ // bad.
+ switch (FailedOverloadResult) {
+ case OR_Ambiguous:
+ S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init)
+ << DestType << ArgsRange;
+ S.PrintOverloadCandidates(FailedCandidateSet, true);
+ break;
+
+ case OR_No_Viable_Function:
+ S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init)
+ << DestType << ArgsRange;
+ S.PrintOverloadCandidates(FailedCandidateSet, false);
+ break;
+
+ case OR_Deleted: {
+ S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
+ << true << DestType << ArgsRange;
+ OverloadCandidateSet::iterator Best;
+ OverloadingResult Ovl = S.BestViableFunction(FailedCandidateSet,
+ Kind.getLocation(),
+ Best);
+ if (Ovl == OR_Deleted) {
+ S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
+ << Best->Function->isDeleted();
+ } else {
+ llvm_unreachable("Inconsistent overload resolution?");
+ }
+ break;
+ }
+
+ case OR_Success:
+ llvm_unreachable("Conversion did not fail!");
+ break;
+ }
+ break;
+ }
+ }
+
+ return true;
+}
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
new file mode 100644
index 0000000..2d4b01f
--- /dev/null
+++ b/lib/Sema/SemaInit.h
@@ -0,0 +1,579 @@
+//===--- SemaInit.h - Semantic Analysis for Initializers --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides supporting data types for initialization of objects.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_SEMA_INIT_H
+#define LLVM_CLANG_SEMA_INIT_H
+
+#include "SemaOverload.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/Parse/Action.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/SmallVector.h"
+#include <cassert>
+
+namespace clang {
+
+class CXXBaseSpecifier;
+class DeclaratorDecl;
+class DeclaratorInfo;
+class FieldDecl;
+class FunctionDecl;
+class ParmVarDecl;
+class Sema;
+class TypeLoc;
+class VarDecl;
+
+/// \brief Describes an entity that is being initialized.
+class InitializedEntity {
+public:
+ /// \brief Specifies the kind of entity being initialized.
+ enum EntityKind {
+ /// \brief The entity being initialized is a variable.
+ EK_Variable,
+ /// \brief The entity being initialized is a function parameter.
+ EK_Parameter,
+ /// \brief The entity being initialized is the result of a function call.
+ EK_Result,
+ /// \brief The entity being initialized is an exception object that
+ /// is being thrown.
+ EK_Exception,
+ /// \brief The entity being initialized is a temporary object.
+ EK_Temporary,
+ /// \brief The entity being initialized is a base member subobject.
+ EK_Base,
+ /// \brief The entity being initialized is a non-static data member
+ /// subobject.
+ EK_Member
+ };
+
+private:
+ /// \brief The kind of entity being initialized.
+ EntityKind Kind;
+
+ /// \brief The type of the object or reference being initialized along with
+ /// its location information.
+ TypeLoc TL;
+
+ union {
+ /// \brief When Kind == EK_Variable, EK_Parameter, or EK_Member,
+ /// the VarDecl, ParmVarDecl, or FieldDecl, respectively.
+ DeclaratorDecl *VariableOrMember;
+
+ /// \brief When Kind == EK_Result or EK_Exception, the location of the
+ /// 'return' or 'throw' keyword, respectively. When Kind == EK_Temporary,
+ /// the location where the temporary is being created.
+ unsigned Location;
+
+ /// \brief When Kind == EK_Base, the base specifier that provides the
+ /// base class.
+ CXXBaseSpecifier *Base;
+ };
+
+ InitializedEntity() { }
+
+ /// \brief Create the initialization entity for a variable.
+ InitializedEntity(VarDecl *Var)
+ : Kind(EK_Variable),
+ VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Var))
+ {
+ InitDeclLoc();
+ }
+
+ /// \brief Create the initialization entity for a parameter.
+ InitializedEntity(ParmVarDecl *Parm)
+ : Kind(EK_Parameter),
+ VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Parm))
+ {
+ InitDeclLoc();
+ }
+
+ /// \brief Create the initialization entity for the result of a function,
+ /// throwing an object, or performing an explicit cast.
+ InitializedEntity(EntityKind Kind, SourceLocation Loc, TypeLoc TL)
+ : Kind(Kind), TL(TL), Location(Loc.getRawEncoding()) { }
+
+ /// \brief Create the initialization entity for a member subobject.
+ InitializedEntity(FieldDecl *Member)
+ : Kind(EK_Member),
+ VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Member))
+ {
+ InitDeclLoc();
+ }
+
+ /// \brief Initialize type-location information from a declaration.
+ void InitDeclLoc();
+
+public:
+ /// \brief Create the initialization entity for a variable.
+ static InitializedEntity InitializeVariable(VarDecl *Var) {
+ return InitializedEntity(Var);
+ }
+
+ /// \brief Create the initialization entity for a parameter.
+ static InitializedEntity InitializeParameter(ParmVarDecl *Parm) {
+ return InitializedEntity(Parm);
+ }
+
+ /// \brief Create the initialization entity for the result of a function.
+ static InitializedEntity InitializeResult(SourceLocation ReturnLoc,
+ TypeLoc TL) {
+ return InitializedEntity(EK_Result, ReturnLoc, TL);
+ }
+
+ /// \brief Create the initialization entity for an exception object.
+ static InitializedEntity InitializeException(SourceLocation ThrowLoc,
+ TypeLoc TL) {
+ return InitializedEntity(EK_Exception, ThrowLoc, TL);
+ }
+
+ /// \brief Create the initialization entity for a temporary.
+ static InitializedEntity InitializeTemporary(EntityKind Kind, TypeLoc TL) {
+ return InitializedEntity(Kind, SourceLocation(), TL);
+ }
+
+ /// \brief Create the initialization entity for a base class subobject.
+ static InitializedEntity InitializeBase(ASTContext &Context,
+ CXXBaseSpecifier *Base);
+
+ /// \brief Create the initialize entity for a member subobject.
+ static InitializedEntity InitializeMember(FieldDecl *Member) {
+ return InitializedEntity(Member);
+ }
+
+ /// \brief Determine the kind of initialization.
+ EntityKind getKind() const { return Kind; }
+
+ /// \brief Retrieve type being initialized.
+ TypeLoc getType() const { return TL; }
+
+ /// \brief Determine the location of the 'return' keyword when initializing
+ /// the result of a function call.
+ SourceLocation getReturnLoc() const {
+ assert(getKind() == EK_Result && "No 'return' location!");
+ return SourceLocation::getFromRawEncoding(Location);
+ }
+
+ /// \brief Determine the location of the 'throw' keyword when initializing
+ /// an exception object.
+ SourceLocation getThrowLoc() const {
+ assert(getKind() == EK_Exception && "No 'throw' location!");
+ return SourceLocation::getFromRawEncoding(Location);
+ }
+};
+
+/// \brief Describes the kind of initialization being performed, along with
+/// location information for tokens related to the initialization (equal sign,
+/// parentheses).
+class InitializationKind {
+public:
+ /// \brief The kind of initialization being performed.
+ enum InitKind {
+ IK_Direct, ///< Direct initialization
+ IK_Copy, ///< Copy initialization
+ IK_Default, ///< Default initialization
+ IK_Value ///< Value initialization
+ };
+
+private:
+ /// \brief The kind of initialization that we're storing.
+ enum StoredInitKind {
+ SIK_Direct = IK_Direct, ///< Direct initialization
+ SIK_Copy = IK_Copy, ///< Copy initialization
+ SIK_Default = IK_Default, ///< Default initialization
+ SIK_Value = IK_Value, ///< Value initialization
+ SIK_DirectCast, ///< Direct initialization due to a cast
+ /// \brief Direct initialization due to a C-style or functional cast.
+ SIK_DirectCStyleOrFunctionalCast
+ };
+
+ /// \brief The kind of initialization being performed.
+ StoredInitKind Kind;
+
+ /// \brief The source locations involved in the initialization.
+ SourceLocation Locations[3];
+
+ InitializationKind(StoredInitKind Kind, SourceLocation Loc1,
+ SourceLocation Loc2, SourceLocation Loc3)
+ : Kind(Kind)
+ {
+ Locations[0] = Loc1;
+ Locations[1] = Loc2;
+ Locations[2] = Loc3;
+ }
+
+public:
+ /// \brief Create a direct initialization.
+ static InitializationKind CreateDirect(SourceLocation InitLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ return InitializationKind(SIK_Direct, InitLoc, LParenLoc, RParenLoc);
+ }
+
+ /// \brief Create a direct initialization due to a cast.
+ static InitializationKind CreateCast(SourceRange TypeRange,
+ bool IsCStyleCast) {
+ return InitializationKind(IsCStyleCast? SIK_DirectCStyleOrFunctionalCast
+ : SIK_DirectCast,
+ TypeRange.getBegin(), TypeRange.getBegin(),
+ TypeRange.getEnd());
+ }
+
+ /// \brief Create a copy initialization.
+ static InitializationKind CreateCopy(SourceLocation InitLoc,
+ SourceLocation EqualLoc) {
+ return InitializationKind(SIK_Copy, InitLoc, EqualLoc, EqualLoc);
+ }
+
+ /// \brief Create a default initialization.
+ static InitializationKind CreateDefault(SourceLocation InitLoc) {
+ return InitializationKind(SIK_Default, InitLoc, InitLoc, InitLoc);
+ }
+
+ /// \brief Create a value initialization.
+ static InitializationKind CreateValue(SourceLocation InitLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ return InitializationKind(SIK_Value, InitLoc, LParenLoc, RParenLoc);
+ }
+
+ /// \brief Determine the initialization kind.
+ InitKind getKind() const {
+ if (Kind > SIK_Value)
+ return IK_Direct;
+
+ return (InitKind)Kind;
+ }
+
+ /// \brief Determine whether this initialization is an explicit cast.
+ bool isExplicitCast() const {
+ return Kind == SIK_DirectCast || Kind == SIK_DirectCStyleOrFunctionalCast;
+ }
+
+ /// \brief Determine whether this initialization is a C-style cast.
+ bool isCStyleOrFunctionalCast() const {
+ return Kind == SIK_DirectCStyleOrFunctionalCast;
+ }
+
+ /// \brief Retrieve the location at which initialization is occurring.
+ SourceLocation getLocation() const { return Locations[0]; }
+
+ /// \brief Retrieve the source range that covers the initialization.
+ SourceRange getRange() const {
+ return SourceRange(Locations[0], Locations[2]);
+ }
+
+ /// \brief Retrieve the location of the equal sign for copy initialization
+ /// (if present).
+ SourceLocation getEqualLoc() const {
+ assert(Kind == SIK_Copy && "Only copy initialization has an '='");
+ return Locations[1];
+ }
+
+ /// \brief Retrieve the source range containing the locations of the open
+ /// and closing parentheses for value and direct initializations.
+ SourceRange getParenRange() const {
+ assert((getKind() == IK_Direct || Kind == SIK_Value) &&
+ "Only direct- and value-initialization have parentheses");
+ return SourceRange(Locations[1], Locations[2]);
+ }
+};
+
+/// \brief Describes the sequence of initializations required to initialize
+/// a given object or reference with a set of arguments.
+class InitializationSequence {
+public:
+ /// \brief Describes the kind of initialization sequence computed.
+ ///
+ /// FIXME: Much of this information is in the initialization steps... why is
+ /// it duplicated here?
+ enum SequenceKind {
+ /// \brief A failed initialization sequence. The failure kind tells what
+ /// happened.
+ FailedSequence = 0,
+
+ /// \brief A dependent initialization, which could not be
+ /// type-checked due to the presence of dependent types or
+ /// dependently-type expressions.
+ DependentSequence,
+
+ /// \brief A user-defined conversion sequence.
+ UserDefinedConversion,
+
+ /// \brief A constructor call.
+ ConstructorInitialization,
+
+ /// \brief A reference binding.
+ ReferenceBinding,
+
+ /// \brief List initialization
+ ListInitialization,
+
+ /// \brief Zero-initialization.
+ ZeroInitialization
+ };
+
+ /// \brief Describes the kind of a particular step in an initialization
+ /// sequence.
+ enum StepKind {
+ /// \brief Resolve the address of an overloaded function to a specific
+ /// function declaration.
+ SK_ResolveAddressOfOverloadedFunction,
+ /// \brief Perform a derived-to-base cast, producing an rvalue.
+ SK_CastDerivedToBaseRValue,
+ /// \brief Perform a derived-to-base cast, producing an lvalue.
+ SK_CastDerivedToBaseLValue,
+ /// \brief Reference binding to an lvalue.
+ SK_BindReference,
+ /// \brief Reference binding to a temporary.
+ SK_BindReferenceToTemporary,
+ /// \brief Perform a user-defined conversion, either via a conversion
+ /// function or via a constructor.
+ SK_UserConversion,
+ /// \brief Perform a qualification conversion, producing an rvalue.
+ SK_QualificationConversionRValue,
+ /// \brief Perform a qualification conversion, producing an lvalue.
+ SK_QualificationConversionLValue,
+ /// \brief Perform an implicit conversion sequence.
+ SK_ConversionSequence,
+ /// \brief Perform list-initialization
+ SK_ListInitialization,
+ /// \brief Perform initialization via a constructor.
+ SK_ConstructorInitialization,
+ /// \brief Zero-initialize the object
+ SK_ZeroInitialization
+ };
+
+ /// \brief A single step in the initialization sequence.
+ class Step {
+ public:
+ /// \brief The kind of conversion or initialization step we are taking.
+ StepKind Kind;
+
+ // \brief The type that results from this initialization.
+ QualType Type;
+
+ union {
+ /// \brief When Kind == SK_ResolvedOverloadedFunction or Kind ==
+ /// SK_UserConversion, the function that the expression should be
+ /// resolved to or the conversion function to call, respectively.
+ FunctionDecl *Function;
+
+ /// \brief When Kind = SK_ConversionSequence, the implicit conversion
+ /// sequence
+ ImplicitConversionSequence *ICS;
+ };
+
+ void Destroy();
+ };
+
+private:
+ /// \brief The kind of initialization sequence computed.
+ enum SequenceKind SequenceKind;
+
+ /// \brief Steps taken by this initialization.
+ llvm::SmallVector<Step, 4> Steps;
+
+public:
+ /// \brief Describes why initialization failed.
+ enum FailureKind {
+ /// \brief Too many initializers provided for a reference.
+ FK_TooManyInitsForReference,
+ /// \brief Array must be initialized with an initializer list.
+ FK_ArrayNeedsInitList,
+ /// \brief Array must be initialized with an initializer list or a
+ /// string literal.
+ FK_ArrayNeedsInitListOrStringLiteral,
+ /// \brief Cannot resolve the address of an overloaded function.
+ FK_AddressOfOverloadFailed,
+ /// \brief Overloading due to reference initialization failed.
+ FK_ReferenceInitOverloadFailed,
+ /// \brief Non-const lvalue reference binding to a temporary.
+ FK_NonConstLValueReferenceBindingToTemporary,
+ /// \brief Non-const lvalue reference binding to an lvalue of unrelated
+ /// type.
+ FK_NonConstLValueReferenceBindingToUnrelated,
+ /// \brief Rvalue reference binding to an lvalue.
+ FK_RValueReferenceBindingToLValue,
+ /// \brief Reference binding drops qualifiers.
+ FK_ReferenceInitDropsQualifiers,
+ /// \brief Reference binding failed.
+ FK_ReferenceInitFailed,
+ /// \brief Implicit conversion failed.
+ FK_ConversionFailed,
+ /// \brief Too many initializers for scalar
+ FK_TooManyInitsForScalar,
+ /// \brief Reference initialization from an initializer list
+ FK_ReferenceBindingToInitList,
+ /// \brief Initialization of some unused destination type with an
+ /// initializer list.
+ FK_InitListBadDestinationType,
+ /// \brief Overloading for a user-defined conversion failed.
+ FK_UserConversionOverloadFailed,
+ /// \brief Overloaded for initialization by constructor failed.
+ FK_ConstructorOverloadFailed
+ };
+
+private:
+ /// \brief The reason why initialization failued.
+ FailureKind Failure;
+
+ /// \brief The failed result of overload resolution.
+ OverloadingResult FailedOverloadResult;
+
+ /// \brief The candidate set created when initialization failed.
+ OverloadCandidateSet FailedCandidateSet;
+
+public:
+ /// \brief Try to perform initialization of the given entity, creating a
+ /// record of the steps required to perform the initialization.
+ ///
+ /// The generated initialization sequence will either contain enough
+ /// information to diagnose
+ ///
+ /// \param S the semantic analysis object.
+ ///
+ /// \param Entity the entity being initialized.
+ ///
+ /// \param Kind the kind of initialization being performed.
+ ///
+ /// \param Args the argument(s) provided for initialization.
+ ///
+ /// \param NumArgs the number of arguments provided for initialization.
+ InitializationSequence(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr **Args,
+ unsigned NumArgs);
+
+ ~InitializationSequence();
+
+ /// \brief Perform the actual initialization of the given entity based on
+ /// the computed initialization sequence.
+ ///
+ /// \param S the semantic analysis object.
+ ///
+ /// \param Entity the entity being initialized.
+ ///
+ /// \param Kind the kind of initialization being performed.
+ ///
+ /// \param Args the argument(s) provided for initialization, ownership of
+ /// which is transfered into the routine.
+ ///
+ /// \param ResultType if non-NULL, will be set to the type of the
+ /// initialized object, which is the type of the declaration in most
+ /// cases. However, when the initialized object is a variable of
+ /// incomplete array type and the initializer is an initializer
+ /// list, this type will be set to the completed array type.
+ ///
+ /// \returns an expression that performs the actual object initialization, if
+ /// the initialization is well-formed. Otherwise, emits diagnostics
+ /// and returns an invalid expression.
+ Action::OwningExprResult Perform(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Action::MultiExprArg Args,
+ QualType *ResultType = 0);
+
+ /// \brief Diagnose an potentially-invalid initialization sequence.
+ ///
+ /// \returns true if the initialization sequence was ill-formed,
+ /// false otherwise.
+ bool Diagnose(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr **Args, unsigned NumArgs);
+
+ /// \brief Determine the kind of initialization sequence computed.
+ enum SequenceKind getKind() const { return SequenceKind; }
+
+ /// \brief Set the kind of sequence computed.
+ void setSequenceKind(enum SequenceKind SK) { SequenceKind = SK; }
+
+ /// \brief Determine whether the initialization sequence is valid.
+ operator bool() const { return SequenceKind != FailedSequence; }
+
+ typedef llvm::SmallVector<Step, 4>::const_iterator step_iterator;
+ step_iterator step_begin() const { return Steps.begin(); }
+ step_iterator step_end() const { return Steps.end(); }
+
+ /// \brief Add a new step in the initialization that resolves the address
+ /// of an overloaded function to a specific function declaration.
+ ///
+ /// \param Function the function to which the overloaded function reference
+ /// resolves.
+ void AddAddressOverloadResolutionStep(FunctionDecl *Function);
+
+ /// \brief Add a new step in the initialization that performs a derived-to-
+ /// base cast.
+ ///
+ /// \param BaseType the base type to which we will be casting.
+ ///
+ /// \param IsLValue true if the result of this cast will be treated as
+ /// an lvalue.
+ void AddDerivedToBaseCastStep(QualType BaseType, bool IsLValue);
+
+ /// \brief Add a new step binding a reference to an object.
+ ///
+ /// \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.
+ void AddReferenceBindingStep(QualType T, bool BindingTemporary);
+
+ /// \brief Add a new step invoking a conversion function, which is either
+ /// a constructor or a conversion function.
+ void AddUserConversionStep(FunctionDecl *Function, QualType T);
+
+ /// \brief Add a new step that performs a qualification conversion to the
+ /// given type.
+ void AddQualificationConversionStep(QualType Ty, bool IsLValue);
+
+ /// \brief Add a new step that applies an implicit conversion sequence.
+ void AddConversionSequenceStep(const ImplicitConversionSequence &ICS,
+ QualType T);
+
+ /// \brief Add a list-initialiation step
+ void AddListInitializationStep(QualType T);
+
+ /// \brief Add a constructor-initialization step.
+ void AddConstructorInitializationStep(CXXConstructorDecl *Constructor,
+ QualType T);
+
+ /// \brief Add a zero-initialization step.
+ void AddZeroInitializationStep(QualType T);
+
+ /// \brief Note that this initialization sequence failed.
+ void SetFailed(FailureKind Failure) {
+ SequenceKind = FailedSequence;
+ this->Failure = Failure;
+ }
+
+ /// \brief Note that this initialization sequence failed due to failed
+ /// overload resolution.
+ void SetOverloadFailure(FailureKind Failure, OverloadingResult Result);
+
+ /// \brief Retrieve a reference to the candidate set when overload
+ /// resolution fails.
+ OverloadCandidateSet &getFailedCandidateSet() {
+ return FailedCandidateSet;
+ }
+
+ /// \brief Determine why initialization failed.
+ FailureKind getFailureKind() const {
+ assert(getKind() == FailedSequence && "Not an initialization failure!");
+ return Failure;
+ }
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_SEMA_INIT_H
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 8f09827..724e2fc 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -222,6 +222,11 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member;
break;
+ case Sema::LookupUsingDeclName:
+ IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag
+ | Decl::IDNS_Member | Decl::IDNS_Using;
+ break;
+
case Sema::LookupObjCProtocolName:
IDNS = Decl::IDNS_ObjCProtocol;
break;
@@ -229,10 +234,6 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
case Sema::LookupObjCImplementationName:
IDNS = Decl::IDNS_ObjCImplementation;
break;
-
- case Sema::LookupObjCCategoryImplName:
- IDNS = Decl::IDNS_ObjCCategoryImpl;
- break;
}
return IDNS;
}
@@ -245,7 +246,7 @@ void LookupResult::deletePaths(CXXBasePaths *Paths) {
/// Resolves the result kind of this lookup.
void LookupResult::resolveKind() {
unsigned N = Decls.size();
-
+
// Fast case: no possible ambiguity.
if (N == 0) {
assert(ResultKind == NotFound);
@@ -282,9 +283,6 @@ void LookupResult::resolveKind() {
// If it's not unique, pull something off the back (and
// continue at this index).
Decls[I] = Decls[--N];
- } else if (isa<UnresolvedUsingValueDecl>(D)) {
- // FIXME: support unresolved using value declarations
- Decls[I] = Decls[--N];
} else {
// Otherwise, do some decl type analysis and then continue.
@@ -318,13 +316,13 @@ void LookupResult::resolveKind() {
// wherever the object, function, or enumerator name is visible.
// But it's still an error if there are distinct tag types found,
// even if they're not visible. (ref?)
- if (HideTags && HasTag && !Ambiguous && !HasUnresolved &&
- (HasFunction || HasNonFunction))
+ if (HideTags && HasTag && !Ambiguous &&
+ (HasFunction || HasNonFunction || HasUnresolved))
Decls[UniqueTagIndex] = Decls[--N];
Decls.set_size(N);
- if (HasFunction && HasNonFunction)
+ if (HasNonFunction && (HasFunction || HasUnresolved))
Ambiguous = true;
if (Ambiguous)
@@ -337,44 +335,6 @@ void LookupResult::resolveKind() {
ResultKind = LookupResult::Found;
}
-/// @brief Converts the result of name lookup into a single (possible
-/// NULL) pointer to a declaration.
-///
-/// The resulting declaration will either be the declaration we found
-/// (if only a single declaration was found), an
-/// OverloadedFunctionDecl (if an overloaded function was found), or
-/// NULL (if no declaration was found). This conversion must not be
-/// used anywhere where name lookup could result in an ambiguity.
-///
-/// The OverloadedFunctionDecl conversion is meant as a stop-gap
-/// solution, since it causes the OverloadedFunctionDecl to be
-/// leaked. FIXME: Eventually, there will be a better way to iterate
-/// over the set of overloaded functions returned by name lookup.
-NamedDecl *LookupResult::getAsSingleDecl(ASTContext &C) const {
- size_t size = Decls.size();
- if (size == 0) return 0;
- if (size == 1) return (*begin())->getUnderlyingDecl();
-
- if (isAmbiguous()) return 0;
-
- iterator I = begin(), E = end();
-
- OverloadedFunctionDecl *Ovl
- = OverloadedFunctionDecl::Create(C, (*I)->getDeclContext(),
- (*I)->getDeclName());
- for (; I != E; ++I) {
- NamedDecl *ND = (*I)->getUnderlyingDecl();
- assert(ND->isFunctionOrFunctionTemplate());
- if (isa<FunctionDecl>(ND))
- Ovl->addOverload(cast<FunctionDecl>(ND));
- else
- Ovl->addOverload(cast<FunctionTemplateDecl>(ND));
- // FIXME: UnresolvedUsingDecls.
- }
-
- return Ovl;
-}
-
void LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) {
CXXBasePaths::paths_iterator I, E;
DeclContext::lookup_iterator DI, DE;
@@ -521,7 +481,12 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
DeclContext *OuterCtx = findOuterContext(S);
for (; Ctx && Ctx->getPrimaryContext() != OuterCtx;
Ctx = Ctx->getLookupParent()) {
- if (Ctx->isFunctionOrMethod())
+ // We do not directly look into function or method contexts
+ // (since all local variables are found via the identifier
+ // changes) or in transparent contexts (since those entities
+ // will be found in the nearest enclosing non-transparent
+ // context).
+ if (Ctx->isFunctionOrMethod() || Ctx->isTransparentContext())
continue;
// Perform qualified name lookup into this context.
@@ -649,6 +614,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
case Sema::LookupOperatorName:
case Sema::LookupNestedNameSpecifierName:
case Sema::LookupNamespaceName:
+ case Sema::LookupUsingDeclName:
assert(false && "C does not perform these kinds of name lookup");
break;
@@ -670,9 +636,6 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
IDNS = Decl::IDNS_ObjCImplementation;
break;
- case Sema::LookupObjCCategoryImplName:
- IDNS = Decl::IDNS_ObjCCategoryImpl;
- break;
}
// Scan up the scope chain looking for a decl that matches this
@@ -964,12 +927,14 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) {
case LookupTagName:
BaseCallback = &CXXRecordDecl::FindTagMember;
break;
+
+ case LookupUsingDeclName:
+ // This lookup is for redeclarations only.
case LookupOperatorName:
case LookupNamespaceName:
case LookupObjCProtocolName:
case LookupObjCImplementationName:
- case LookupObjCCategoryImplName:
// These lookups will never find a member in a C++ class (or base class).
return false;
@@ -1202,7 +1167,7 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
}
}
- llvm::llvm_unreachable("unknown ambiguity kind");
+ llvm_unreachable("unknown ambiguity kind");
return true;
}
@@ -1610,7 +1575,7 @@ NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name,
RedeclarationKind Redecl) {
LookupResult R(*this, Name, SourceLocation(), NameKind, Redecl);
LookupName(R, S);
- return R.getAsSingleDecl(Context);
+ return R.getAsSingle<NamedDecl>();
}
/// \brief Find the protocol with the given name, if any.
@@ -1619,13 +1584,6 @@ ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) {
return cast_or_null<ObjCProtocolDecl>(D);
}
-/// \brief Find the Objective-C category implementation with the given
-/// name, if any.
-ObjCCategoryImplDecl *Sema::LookupObjCCategoryImpl(IdentifierInfo *II) {
- Decl *D = LookupSingleName(TUScope, II, LookupObjCCategoryImplName);
- return cast_or_null<ObjCCategoryImplDecl>(D);
-}
-
void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
QualType T1, QualType T2,
FunctionSet &Functions) {
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 6ea6a14..561cfdb 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -38,6 +38,7 @@ GetConversionCategory(ImplicitConversionKind Kind) {
ICC_Lvalue_Transformation,
ICC_Lvalue_Transformation,
ICC_Lvalue_Transformation,
+ ICC_Identity,
ICC_Qualification_Adjustment,
ICC_Promotion,
ICC_Promotion,
@@ -66,6 +67,7 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) {
ICR_Exact_Match,
ICR_Exact_Match,
ICR_Exact_Match,
+ ICR_Exact_Match,
ICR_Promotion,
ICR_Promotion,
ICR_Promotion,
@@ -91,6 +93,7 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
"Lvalue-to-rvalue",
"Array-to-pointer",
"Function-to-pointer",
+ "Noreturn adjustment",
"Qualification",
"Integral promotion",
"Floating point promotion",
@@ -172,7 +175,7 @@ isPointerConversionToVoidPointer(ASTContext& Context) const {
if (First == ICK_Array_To_Pointer)
FromType = Context.getArrayDecayedType(FromType);
- if (Second == ICK_Pointer_Conversion)
+ if (Second == ICK_Pointer_Conversion && FromType->isPointerType())
if (const PointerType* ToPtrType = ToType->getAs<PointerType>())
return ToPtrType->getPointeeType()->isVoidType();
@@ -255,12 +258,13 @@ void ImplicitConversionSequence::DebugPrint() const {
}
// IsOverload - Determine whether the given New declaration is an
-// overload of the Old declaration. This routine returns false if New
-// and Old cannot be overloaded, e.g., if they are functions with the
-// same signature (C++ 1.3.10) or if the Old declaration isn't a
-// function (or overload set). When it does return false and Old is an
-// OverloadedFunctionDecl, MatchedDecl will be set to point to the
-// FunctionDecl that New cannot be overloaded with.
+// overload of the declarations in Old. This routine returns false if
+// New and Old cannot be overloaded, e.g., if New has the same
+// signature as some function in Old (C++ 1.3.10) or if the Old
+// declarations aren't functions (or function templates) at all. When
+// it does return false, MatchedDecl will point to the decl that New
+// cannot be overloaded with. This decl may be a UsingShadowDecl on
+// top of the underlying declaration.
//
// Example: Given the following input:
//
@@ -271,42 +275,51 @@ void ImplicitConversionSequence::DebugPrint() const {
// When we process #1, there is no previous declaration of "f",
// so IsOverload will not be used.
//
-// When we process #2, Old is a FunctionDecl for #1. By comparing the
-// parameter types, we see that #1 and #2 are overloaded (since they
-// have different signatures), so this routine returns false;
-// MatchedDecl is unchanged.
+// When we process #2, Old contains only the FunctionDecl for #1. By
+// comparing the parameter types, we see that #1 and #2 are overloaded
+// (since they have different signatures), so this routine returns
+// false; MatchedDecl is unchanged.
//
-// When we process #3, Old is an OverloadedFunctionDecl containing #1
-// and #2. We compare the signatures of #3 to #1 (they're overloaded,
-// so we do nothing) and then #3 to #2. Since the signatures of #3 and
-// #2 are identical (return types of functions are not part of the
+// When we process #3, Old is an overload set containing #1 and #2. We
+// compare the signatures of #3 to #1 (they're overloaded, so we do
+// nothing) and then #3 to #2. Since the signatures of #3 and #2 are
+// identical (return types of functions are not part of the
// signature), IsOverload returns false and MatchedDecl will be set to
// point to the FunctionDecl for #2.
-bool
-Sema::IsOverload(FunctionDecl *New, LookupResult &Previous, NamedDecl *&Match) {
- for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
+Sema::OverloadKind
+Sema::CheckOverload(FunctionDecl *New, const LookupResult &Old,
+ NamedDecl *&Match) {
+ for (LookupResult::iterator I = Old.begin(), E = Old.end();
I != E; ++I) {
- NamedDecl *Old = (*I)->getUnderlyingDecl();
- if (FunctionTemplateDecl *OldT = dyn_cast<FunctionTemplateDecl>(Old)) {
+ NamedDecl *OldD = (*I)->getUnderlyingDecl();
+ if (FunctionTemplateDecl *OldT = dyn_cast<FunctionTemplateDecl>(OldD)) {
if (!IsOverload(New, OldT->getTemplatedDecl())) {
- Match = Old;
- return false;
+ Match = *I;
+ return Ovl_Match;
}
- } else if (FunctionDecl *OldF = dyn_cast<FunctionDecl>(Old)) {
+ } else if (FunctionDecl *OldF = dyn_cast<FunctionDecl>(OldD)) {
if (!IsOverload(New, OldF)) {
- Match = Old;
- return false;
+ Match = *I;
+ return Ovl_Match;
}
+ } else if (isa<UsingDecl>(OldD) || isa<TagDecl>(OldD)) {
+ // We can overload with these, which can show up when doing
+ // redeclaration checks for UsingDecls.
+ assert(Old.getLookupKind() == LookupUsingDeclName);
+ } else if (isa<UnresolvedUsingValueDecl>(OldD)) {
+ // Optimistically assume that an unresolved using decl will
+ // overload; if it doesn't, we'll have to diagnose during
+ // template instantiation.
} else {
// (C++ 13p1):
// Only function declarations can be overloaded; object and type
// declarations cannot be overloaded.
- Match = Old;
- return false;
+ Match = *I;
+ return Ovl_NonFunction;
}
}
- return true;
+ return Ovl_Overload;
}
bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old) {
@@ -474,6 +487,23 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
return ICS;
}
+/// \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,
+ QualType ToType, QualType &ResultTy) {
+ if (Context.hasSameUnqualifiedType(FromType, ToType))
+ return false;
+
+ // Strip the noreturn off the type we're converting from; noreturn can
+ // safely be removed.
+ FromType = Context.getNoReturnType(FromType, false);
+ if (!Context.hasSameUnqualifiedType(FromType, ToType))
+ return false;
+
+ ResultTy = FromType;
+ return true;
+}
+
/// IsStandardConversion - Determines whether there is a standard
/// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the
/// expression From to the type ToType. Standard conversion sequences
@@ -553,7 +583,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// function. (C++ 4.3p1).
FromType = Context.getPointerType(FromType);
} else if (FunctionDecl *Fn
- = ResolveAddressOfOverloadedFunction(From, ToType, false)) {
+ = ResolveAddressOfOverloadedFunction(From, ToType, false)) {
// Address of overloaded function (C++ [over.over]).
SCS.First = ICK_Function_To_Pointer;
@@ -644,7 +674,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
} else if (ToType->isBooleanType() &&
(FromType->isArithmeticType() ||
FromType->isEnumeralType() ||
- FromType->isPointerType() ||
+ FromType->isAnyPointerType() ||
FromType->isBlockPointerType() ||
FromType->isMemberPointerType() ||
FromType->isNullPtrType())) {
@@ -655,6 +685,9 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
Context.typesAreCompatible(ToType, FromType)) {
// Compatible conversions (Clang extension for C function overloading)
SCS.Second = ICK_Compatible_Conversion;
+ } else if (IsNoReturnConversion(Context, FromType, ToType, FromType)) {
+ // Treat a conversion that strips "noreturn" as an identity conversion.
+ SCS.Second = ICK_NoReturn_Adjustment;
} else {
// No second conversion required.
SCS.Second = ICK_Identity;
@@ -728,19 +761,21 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
// can be converted to an rvalue of the first of the following types
// that can represent all the values of its underlying type: int,
// unsigned int, long, or unsigned long (C++ 4.5p2).
- if ((FromType->isEnumeralType() || FromType->isWideCharType())
- && ToType->isIntegerType()) {
+
+ // We pre-calculate the promotion type for enum types.
+ if (const EnumType *FromEnumType = FromType->getAs<EnumType>())
+ if (ToType->isIntegerType())
+ return Context.hasSameUnqualifiedType(ToType,
+ FromEnumType->getDecl()->getPromotionType());
+
+ if (FromType->isWideCharType() && ToType->isIntegerType()) {
// Determine whether the type we're converting from is signed or
// unsigned.
bool FromIsSigned;
uint64_t FromSize = Context.getTypeSize(FromType);
- if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) {
- QualType UnderlyingType = FromEnumType->getDecl()->getIntegerType();
- FromIsSigned = UnderlyingType->isSignedIntegerType();
- } else {
- // FIXME: Is wchar_t signed or unsigned? We assume it's signed for now.
- FromIsSigned = true;
- }
+
+ // FIXME: Is wchar_t signed or unsigned? We assume it's signed for now.
+ FromIsSigned = true;
// The types we'll try to promote to, in the appropriate
// order. Try each of these types.
@@ -1233,7 +1268,7 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType,
return false;
}
-
+
/// CheckMemberPointerConversion - Check the member pointer conversion from the
/// expression From to the type ToType. This routine checks for ambiguous or
/// virtual (FIXME: or inaccessible) base-to-derived member pointer conversions
@@ -1371,13 +1406,13 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) {
/// for overload resolution.
/// \param UserCast true if looking for user defined conversion for a static
/// cast.
-Sema::OverloadingResult Sema::IsUserDefinedConversion(
- Expr *From, QualType ToType,
- UserDefinedConversionSequence& User,
- OverloadCandidateSet& CandidateSet,
- bool AllowConversionFunctions,
- bool AllowExplicit, bool ForceRValue,
- bool UserCast) {
+OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
+ UserDefinedConversionSequence& User,
+ OverloadCandidateSet& CandidateSet,
+ bool AllowConversionFunctions,
+ bool AllowExplicit,
+ bool ForceRValue,
+ bool UserCast) {
if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) {
if (RequireCompleteType(From->getLocStart(), ToType, PDiag())) {
// We're not going to find any constructors.
@@ -1446,6 +1481,11 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion(
= FromRecordDecl->getVisibleConversionFunctions();
for (UnresolvedSet::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
+ NamedDecl *D = *I;
+ CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
CXXConversionDecl *Conv;
FunctionTemplateDecl *ConvTemplate;
if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(*I)))
@@ -1455,10 +1495,11 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion(
if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
- AddTemplateConversionCandidate(ConvTemplate, From, ToType,
- CandidateSet);
+ AddTemplateConversionCandidate(ConvTemplate, ActingContext,
+ From, ToType, CandidateSet);
else
- AddConversionCandidate(Conv, From, ToType, CandidateSet);
+ AddConversionCandidate(Conv, ActingContext, From, ToType,
+ CandidateSet);
}
}
}
@@ -2075,8 +2116,10 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
/// parameter of the given member function (@c Method) from the
/// expression @p From.
ImplicitConversionSequence
-Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) {
- QualType ClassType = Context.getTypeDeclType(Method->getParent());
+Sema::TryObjectArgumentInitialization(QualType FromType,
+ CXXMethodDecl *Method,
+ CXXRecordDecl *ActingContext) {
+ QualType ClassType = Context.getTypeDeclType(ActingContext);
// [class.dtor]p2: A destructor can be invoked for a const, volatile or
// const volatile object.
unsigned Quals = isa<CXXDestructorDecl>(Method) ?
@@ -2090,7 +2133,6 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) {
ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
// We need to have an object of class type.
- QualType FromType = From->getType();
if (const PointerType *PT = FromType->getAs<PointerType>())
FromType = PT->getPointeeType();
@@ -2150,8 +2192,11 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) {
DestType = ImplicitParamRecordType;
}
+ // Note that we always use the true parent context when performing
+ // the actual argument initialization.
ImplicitConversionSequence ICS
- = TryObjectArgumentInitialization(From, Method);
+ = TryObjectArgumentInitialization(From->getType(), Method,
+ Method->getParent());
if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion)
return Diag(From->getSourceRange().getBegin(),
diag::err_implicit_object_parameter_init)
@@ -2226,9 +2271,11 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// that is named without a member access expression (e.g.,
// "this->f") that was either written explicitly or created
// implicitly. This can happen with a qualified call to a member
- // function, e.g., X::f(). We use a NULL object as the implied
- // object argument (C++ [over.call.func]p3).
- AddMethodCandidate(Method, 0, Args, NumArgs, CandidateSet,
+ // function, e.g., X::f(). We use an empty type for the implied
+ // object argument (C++ [over.call.func]p3), and the acting context
+ // is irrelevant.
+ AddMethodCandidate(Method, Method->getParent(),
+ QualType(), Args, NumArgs, CandidateSet,
SuppressUserConversions, ForceRValue);
return;
}
@@ -2340,10 +2387,12 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions,
for (FunctionSet::const_iterator F = Functions.begin(),
FEnd = Functions.end();
F != FEnd; ++F) {
+ // FIXME: using declarations
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*F)) {
if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic())
AddMethodCandidate(cast<CXXMethodDecl>(FD),
- Args[0], Args + 1, NumArgs - 1,
+ cast<CXXMethodDecl>(FD)->getParent(),
+ Args[0]->getType(), Args + 1, NumArgs - 1,
CandidateSet, SuppressUserConversions);
else
AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
@@ -2353,8 +2402,9 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions,
if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) &&
!cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic())
AddMethodTemplateCandidate(FunTmpl,
+ cast<CXXRecordDecl>(FunTmpl->getDeclContext()),
/*FIXME: explicit args */ 0,
- Args[0], Args + 1, NumArgs - 1,
+ Args[0]->getType(), Args + 1, NumArgs - 1,
CandidateSet,
SuppressUserConversions);
else
@@ -2368,13 +2418,14 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions,
/// AddMethodCandidate - Adds a named decl (which is some kind of
/// method) as a method candidate to the given overload set.
-void Sema::AddMethodCandidate(NamedDecl *Decl, Expr *Object,
+void Sema::AddMethodCandidate(NamedDecl *Decl,
+ QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions, bool ForceRValue) {
// FIXME: use this
- //DeclContext *ActingContext = Decl->getDeclContext();
+ CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext());
if (isa<UsingShadowDecl>(Decl))
Decl = cast<UsingShadowDecl>(Decl)->getTargetDecl();
@@ -2382,13 +2433,14 @@ void Sema::AddMethodCandidate(NamedDecl *Decl, Expr *Object,
if (FunctionTemplateDecl *TD = dyn_cast<FunctionTemplateDecl>(Decl)) {
assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) &&
"Expected a member function template");
- AddMethodTemplateCandidate(TD, /*ExplicitArgs*/ 0,
- Object, Args, NumArgs,
+ AddMethodTemplateCandidate(TD, ActingContext, /*ExplicitArgs*/ 0,
+ ObjectType, Args, NumArgs,
CandidateSet,
SuppressUserConversions,
ForceRValue);
} else {
- AddMethodCandidate(cast<CXXMethodDecl>(Decl), Object, Args, NumArgs,
+ AddMethodCandidate(cast<CXXMethodDecl>(Decl), ActingContext,
+ ObjectType, Args, NumArgs,
CandidateSet, SuppressUserConversions, ForceRValue);
}
}
@@ -2403,8 +2455,8 @@ void Sema::AddMethodCandidate(NamedDecl *Decl, Expr *Object,
/// a slightly hacky way to implement the overloading rules for elidable copy
/// initialization in C++0x (C++0x 12.8p15).
void
-Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
- Expr **Args, unsigned NumArgs,
+Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
+ QualType ObjectType, Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions, bool ForceRValue) {
const FunctionProtoType* Proto
@@ -2453,13 +2505,14 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
Candidate.Viable = true;
Candidate.Conversions.resize(NumArgs + 1);
- if (Method->isStatic() || !Object)
+ if (Method->isStatic() || ObjectType.isNull())
// The implicit object argument is ignored.
Candidate.IgnoreObjectArgument = true;
else {
// Determine the implicit conversion sequence for the object
// parameter.
- Candidate.Conversions[0] = TryObjectArgumentInitialization(Object, Method);
+ Candidate.Conversions[0]
+ = TryObjectArgumentInitialization(ObjectType, Method, ActingContext);
if (Candidate.Conversions[0].ConversionKind
== ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
@@ -2500,8 +2553,10 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
/// function template specialization.
void
Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
+ CXXRecordDecl *ActingContext,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
- Expr *Object, Expr **Args, unsigned NumArgs,
+ QualType ObjectType,
+ Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
bool ForceRValue) {
@@ -2533,7 +2588,8 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
assert(Specialization && "Missing member function template specialization?");
assert(isa<CXXMethodDecl>(Specialization) &&
"Specialization is not a member function?");
- AddMethodCandidate(cast<CXXMethodDecl>(Specialization), Object, Args, NumArgs,
+ AddMethodCandidate(cast<CXXMethodDecl>(Specialization), ActingContext,
+ ObjectType, Args, NumArgs,
CandidateSet, SuppressUserConversions, ForceRValue);
}
@@ -2585,6 +2641,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
/// conversion function produces).
void
Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
+ CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet) {
assert(!Conversion->getDescribedFunctionTemplate() &&
@@ -2611,7 +2668,9 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
// object parameter.
Candidate.Viable = true;
Candidate.Conversions.resize(1);
- Candidate.Conversions[0] = TryObjectArgumentInitialization(From, Conversion);
+ Candidate.Conversions[0]
+ = TryObjectArgumentInitialization(From->getType(), Conversion,
+ ActingContext);
// Conversion functions to a different type in the base class is visible in
// the derived class. So, a derived to base conversion should not participate
// in overload resolution.
@@ -2683,6 +2742,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
/// [temp.deduct.conv]).
void
Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
+ CXXRecordDecl *ActingDC,
Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet) {
assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) &&
@@ -2705,7 +2765,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
// Add the conversion function template specialization produced by
// template argument deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
- AddConversionCandidate(Specialization, From, ToType, CandidateSet);
+ AddConversionCandidate(Specialization, ActingDC, From, ToType, CandidateSet);
}
/// AddSurrogateCandidate - Adds a "surrogate" candidate function that
@@ -2714,8 +2774,10 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
/// with the given arguments (C++ [over.call.object]p2-4). Proto is
/// the type of function that we'll eventually be calling.
void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
+ CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
- Expr *Object, Expr **Args, unsigned NumArgs,
+ QualType ObjectType,
+ Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet) {
if (!CandidateSet.isNewCandidate(Conversion))
return;
@@ -2735,7 +2797,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// Determine the implicit conversion sequence for the implicit
// object parameter.
ImplicitConversionSequence ObjectInit
- = TryObjectArgumentInitialization(Object, Conversion);
+ = TryObjectArgumentInitialization(ObjectType, Conversion, ActingContext);
if (ObjectInit.ConversionKind == ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
return;
@@ -2870,7 +2932,8 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
OperEnd = Operators.end();
Oper != OperEnd;
++Oper)
- AddMethodCandidate(*Oper, Args[0], Args + 1, NumArgs - 1, CandidateSet,
+ AddMethodCandidate(*Oper, Args[0]->getType(),
+ Args + 1, NumArgs - 1, CandidateSet,
/* SuppressUserConversions = */ false);
}
}
@@ -4111,10 +4174,9 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
/// function, Best points to the candidate function found.
///
/// \returns The result of overload resolution.
-Sema::OverloadingResult
-Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
- SourceLocation Loc,
- OverloadCandidateSet::iterator& Best) {
+OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
+ SourceLocation Loc,
+ OverloadCandidateSet::iterator& Best) {
// Find the best viable function.
Best = CandidateSet.end();
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
@@ -4426,7 +4488,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
continue;
if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*I)) {
- if (FunctionType == Context.getCanonicalType(FunDecl->getType())) {
+ QualType ResultTy;
+ if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) ||
+ IsNoReturnConversion(Context, FunDecl->getType(), FunctionType,
+ ResultTy)) {
Matches.insert(cast<FunctionDecl>(FunDecl->getCanonicalDecl()));
FoundNonTemplateFunction = true;
}
@@ -5122,7 +5187,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
/// parameter). The caller needs to validate that the member
/// expression refers to a member function or an overloaded member
/// function.
-Sema::ExprResult
+Sema::OwningExprResult
Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
SourceLocation LParenLoc, Expr **Args,
unsigned NumArgs, SourceLocation *CommaLocs,
@@ -5131,46 +5196,46 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
// argument and the member function we're referring to.
Expr *NakedMemExpr = MemExprE->IgnoreParens();
- // Extract the object argument.
- Expr *ObjectArg;
-
MemberExpr *MemExpr;
CXXMethodDecl *Method = 0;
if (isa<MemberExpr>(NakedMemExpr)) {
MemExpr = cast<MemberExpr>(NakedMemExpr);
- ObjectArg = MemExpr->getBase();
Method = cast<CXXMethodDecl>(MemExpr->getMemberDecl());
} else {
UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(NakedMemExpr);
- ObjectArg = UnresExpr->getBase();
+
+ QualType ObjectType = UnresExpr->getBaseType();
// Add overload candidates
OverloadCandidateSet CandidateSet;
+ // FIXME: avoid copy.
+ TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
+ if (UnresExpr->hasExplicitTemplateArgs()) {
+ UnresExpr->copyTemplateArgumentsInto(TemplateArgsBuffer);
+ TemplateArgs = &TemplateArgsBuffer;
+ }
+
for (UnresolvedMemberExpr::decls_iterator I = UnresExpr->decls_begin(),
E = UnresExpr->decls_end(); I != E; ++I) {
- // TODO: note if we found something through a using declaration
- NamedDecl *Func = (*I)->getUnderlyingDecl();
-
+ NamedDecl *Func = *I;
+ CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(Func->getDeclContext());
+ if (isa<UsingShadowDecl>(Func))
+ Func = cast<UsingShadowDecl>(Func)->getTargetDecl();
+
if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
// If explicit template arguments were provided, we can't call a
// non-template member function.
- if (UnresExpr->hasExplicitTemplateArgs())
+ if (TemplateArgs)
continue;
- AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet,
- /*SuppressUserConversions=*/false);
+ AddMethodCandidate(Method, ActingDC, ObjectType, Args, NumArgs,
+ CandidateSet, /*SuppressUserConversions=*/false);
} else {
- // FIXME: avoid copy.
- TemplateArgumentListInfo TemplateArgs;
- if (UnresExpr->hasExplicitTemplateArgs())
- UnresExpr->copyTemplateArgumentsInto(TemplateArgs);
-
AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func),
- (UnresExpr->hasExplicitTemplateArgs()
- ? &TemplateArgs : 0),
- ObjectArg, Args, NumArgs,
+ ActingDC, TemplateArgs,
+ ObjectType, Args, NumArgs,
CandidateSet,
/*SuppressUsedConversions=*/false);
}
@@ -5190,14 +5255,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
<< DeclName << MemExprE->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
// FIXME: Leaking incoming expressions!
- return true;
+ return ExprError();
case OR_Ambiguous:
Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call)
<< DeclName << MemExprE->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
// FIXME: Leaking incoming expressions!
- return true;
+ return ExprError();
case OR_Deleted:
Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call)
@@ -5205,16 +5270,24 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
<< DeclName << MemExprE->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
// FIXME: Leaking incoming expressions!
- return true;
+ return ExprError();
}
MemExprE = FixOverloadedFunctionReference(MemExprE, Method);
+
+ // If overload resolution picked a static member, build a
+ // non-member call based on that function.
+ if (Method->isStatic()) {
+ return BuildResolvedCallExpr(MemExprE, Method, LParenLoc,
+ Args, NumArgs, RParenLoc);
+ }
+
MemExpr = cast<MemberExpr>(MemExprE->IgnoreParens());
}
assert(Method && "Member call to something that isn't a method?");
ExprOwningPtr<CXXMemberCallExpr>
- TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExpr, Args,
+ TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExprE, Args,
NumArgs,
Method->getResultType().getNonReferenceType(),
RParenLoc));
@@ -5222,24 +5295,25 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
// Check for a valid return type.
if (CheckCallReturnType(Method->getResultType(), MemExpr->getMemberLoc(),
TheCall.get(), Method))
- return true;
+ return ExprError();
// Convert the object argument (for a non-static member function call).
+ Expr *ObjectArg = MemExpr->getBase();
if (!Method->isStatic() &&
PerformObjectArgumentInitialization(ObjectArg, Method))
- return true;
+ return ExprError();
MemExpr->setBase(ObjectArg);
// Convert the rest of the arguments
const FunctionProtoType *Proto = cast<FunctionProtoType>(Method->getType());
if (ConvertArgumentsForCall(&*TheCall, MemExpr, Method, Proto, Args, NumArgs,
RParenLoc))
- return true;
+ return ExprError();
if (CheckFunctionCall(Method, TheCall.get()))
- return true;
+ return ExprError();
- return MaybeBindToTemporary(TheCall.release()).release();
+ return MaybeBindToTemporary(TheCall.release());
}
/// BuildCallToObjectOfClassType - Build a call to an object of class
@@ -5276,7 +5350,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper) {
- AddMethodCandidate(*Oper, Object, Args, NumArgs, CandidateSet,
+ AddMethodCandidate(*Oper, Object->getType(), Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/ false);
}
@@ -5302,12 +5376,17 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
= cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
for (UnresolvedSet::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
+ NamedDecl *D = *I;
+ CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
// Skip over templated conversion functions; they aren't
// surrogates.
- if (isa<FunctionTemplateDecl>(*I))
+ if (isa<FunctionTemplateDecl>(D))
continue;
- CXXConversionDecl *Conv = cast<CXXConversionDecl>(*I);
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(D);
// Strip the reference type (if any) and then the pointer type (if
// any) to get down to what might be a function type.
@@ -5316,7 +5395,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
ConvType = ConvPtrType->getPointeeType();
if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>())
- AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet);
+ AddSurrogateCandidate(Conv, ActingContext, Proto,
+ Object->getType(), Args, NumArgs,
+ CandidateSet);
}
// Perform overload resolution.
@@ -5372,8 +5453,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// Create an implicit member expr to refer to the conversion operator.
// and then call it.
- CXXMemberCallExpr *CE =
- BuildCXXMemberCallExpr(Object, Conv);
+ CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(Object, Conv);
return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc,
MultiExprArg(*this, (ExprTy**)Args, NumArgs),
@@ -5503,9 +5583,16 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
R.suppressDiagnostics();
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
- Oper != OperEnd; ++Oper)
- AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Base, 0, 0, CandidateSet,
+ Oper != OperEnd; ++Oper) {
+ NamedDecl *D = *Oper;
+ CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+ AddMethodCandidate(cast<CXXMethodDecl>(D), ActingContext,
+ Base->getType(), 0, 0, CandidateSet,
/*SuppressUserConversions=*/false);
+ }
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
@@ -5632,19 +5719,11 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
}
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
+ // FIXME: avoid copy.
+ TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
if (ULE->hasExplicitTemplateArgs()) {
- // FIXME: avoid copy.
- TemplateArgumentListInfo TemplateArgs;
- if (ULE->hasExplicitTemplateArgs())
- ULE->copyTemplateArgumentsInto(TemplateArgs);
-
- return DeclRefExpr::Create(Context,
- ULE->getQualifier(),
- ULE->getQualifierRange(),
- Fn,
- ULE->getNameLoc(),
- Fn->getType(),
- &TemplateArgs);
+ ULE->copyTemplateArgumentsInto(TemplateArgsBuffer);
+ TemplateArgs = &TemplateArgsBuffer;
}
return DeclRefExpr::Create(Context,
@@ -5652,23 +5731,43 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
ULE->getQualifierRange(),
Fn,
ULE->getNameLoc(),
- Fn->getType());
+ Fn->getType(),
+ TemplateArgs);
}
if (UnresolvedMemberExpr *MemExpr = dyn_cast<UnresolvedMemberExpr>(E)) {
// FIXME: avoid copy.
- TemplateArgumentListInfo TemplateArgs;
- if (MemExpr->hasExplicitTemplateArgs())
- MemExpr->copyTemplateArgumentsInto(TemplateArgs);
+ TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
+ if (MemExpr->hasExplicitTemplateArgs()) {
+ MemExpr->copyTemplateArgumentsInto(TemplateArgsBuffer);
+ TemplateArgs = &TemplateArgsBuffer;
+ }
- return MemberExpr::Create(Context, MemExpr->getBase()->Retain(),
+ Expr *Base;
+
+ // If we're filling in
+ if (MemExpr->isImplicitAccess()) {
+ if (cast<CXXMethodDecl>(Fn)->isStatic()) {
+ return DeclRefExpr::Create(Context,
+ MemExpr->getQualifier(),
+ MemExpr->getQualifierRange(),
+ Fn,
+ MemExpr->getMemberLoc(),
+ Fn->getType(),
+ TemplateArgs);
+ } else
+ Base = new (Context) CXXThisExpr(SourceLocation(),
+ MemExpr->getBaseType());
+ } else
+ Base = MemExpr->getBase()->Retain();
+
+ return MemberExpr::Create(Context, Base,
MemExpr->isArrow(),
MemExpr->getQualifier(),
MemExpr->getQualifierRange(),
Fn,
MemExpr->getMemberLoc(),
- (MemExpr->hasExplicitTemplateArgs()
- ? &TemplateArgs : 0),
+ TemplateArgs,
Fn->getType());
}
@@ -5676,4 +5775,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
return E->Retain();
}
+Sema::OwningExprResult Sema::FixOverloadedFunctionReference(OwningExprResult E,
+ FunctionDecl *Fn) {
+ return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Fn));
+}
+
} // end namespace clang
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 0d1f37a..3613d60 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -15,12 +15,26 @@
#ifndef LLVM_CLANG_SEMA_OVERLOAD_H
#define LLVM_CLANG_SEMA_OVERLOAD_H
+#include "clang/AST/Decl.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
namespace clang {
+ class ASTContext;
class CXXConstructorDecl;
+ class CXXConversionDecl;
class FunctionDecl;
+ /// OverloadingResult - Capture the result of performing overload
+ /// resolution.
+ enum OverloadingResult {
+ 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.
+ };
+
/// ImplicitConversionKind - The kind of implicit conversion used to
/// convert an argument to a parameter's type. The enumerator values
/// match with Table 9 of (C++ 13.3.3.1.1) and are listed such that
@@ -30,6 +44,7 @@ namespace clang {
ICK_Lvalue_To_Rvalue, ///< Lvalue-to-rvalue conversion (C++ 4.1)
ICK_Array_To_Pointer, ///< Array-to-pointer conversion (C++ 4.2)
ICK_Function_To_Pointer, ///< Function-to-pointer (C++ 4.3)
+ ICK_NoReturn_Adjustment, ///< Removal of noreturn from a type (Clang)
ICK_Qualification, ///< Qualification conversions (C++ 4.4)
ICK_Integral_Promotion, ///< Integral promotions (C++ 4.5)
ICK_Floating_Promotion, ///< Floating point promotions (C++ 4.6)
@@ -270,6 +285,7 @@ namespace clang {
/// OverloadCandidateSet - A set of overload candidates, used in C++
/// overload resolution (C++ 13.3).
class OverloadCandidateSet : public llvm::SmallVector<OverloadCandidate, 16> {
+ typedef llvm::SmallVector<OverloadCandidate, 16> inherited;
llvm::SmallPtrSet<Decl *, 16> Functions;
public:
@@ -278,6 +294,12 @@ namespace clang {
bool isNewCandidate(Decl *F) {
return Functions.insert(F->getCanonicalDecl());
}
+
+ /// \brief Clear out all of the candidates.
+ void clear() {
+ inherited::clear();
+ Functions.clear();
+ }
};
} // end namespace clang
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index f47577e..ac1b1ec 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -108,36 +108,36 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
if (R.empty())
return TNK_Non_template;
- NamedDecl *Template = R.getAsSingleDecl(Context);
-
- if (SS.isSet() && !SS.isInvalid()) {
- NestedNameSpecifier *Qualifier
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- if (OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(Template))
- TemplateResult
- = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false,
- Ovl));
- else
- TemplateResult
- = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false,
- cast<TemplateDecl>(Template)));
- } else if (OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(Template)) {
- TemplateResult = TemplateTy::make(TemplateName(Ovl));
+ TemplateName Template;
+ TemplateNameKind TemplateKind;
+
+ unsigned ResultCount = R.end() - R.begin();
+ if (ResultCount > 1) {
+ // We assume that we'll preserve the qualifier from a function
+ // template name in other ways.
+ Template = Context.getOverloadedTemplateName(R.begin(), R.end());
+ TemplateKind = TNK_Function_template;
} else {
- TemplateResult = TemplateTy::make(
- TemplateName(cast<TemplateDecl>(Template)));
- }
+ TemplateDecl *TD = cast<TemplateDecl>((*R.begin())->getUnderlyingDecl());
+
+ if (SS.isSet() && !SS.isInvalid()) {
+ NestedNameSpecifier *Qualifier
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ Template = Context.getQualifiedTemplateName(Qualifier, false, TD);
+ } else {
+ Template = TemplateName(TD);
+ }
- if (isa<ClassTemplateDecl>(Template) ||
- isa<TemplateTemplateParmDecl>(Template))
- return TNK_Type_template;
+ if (isa<FunctionTemplateDecl>(TD))
+ TemplateKind = TNK_Function_template;
+ else {
+ assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD));
+ TemplateKind = TNK_Type_template;
+ }
+ }
- assert((isa<FunctionTemplateDecl>(Template) ||
- isa<OverloadedFunctionDecl>(Template)) &&
- "Unhandled template kind in Sema::isTemplateName");
- return TNK_Function_template;
+ TemplateResult = TemplateTy::make(Template);
+ return TemplateKind;
}
void Sema::LookupTemplateName(LookupResult &Found,
@@ -248,126 +248,30 @@ void Sema::LookupTemplateName(LookupResult &Found,
}
}
-/// Constructs a full type for the given nested-name-specifier.
-static QualType GetTypeForQualifier(ASTContext &Context,
- NestedNameSpecifier *Qualifier) {
- // Three possibilities:
-
- // 1. A namespace (global or not).
- assert(!Qualifier->getAsNamespace() && "can't construct type for namespace");
-
- // 2. A type (templated or not).
- Type *Ty = Qualifier->getAsType();
- if (Ty) return QualType(Ty, 0);
-
- // 3. A dependent identifier.
- assert(Qualifier->getAsIdentifier());
- return Context.getTypenameType(Qualifier->getPrefix(),
- Qualifier->getAsIdentifier());
-}
-
-static bool HasDependentTypeAsBase(ASTContext &Context,
- CXXRecordDecl *Record,
- CanQualType T) {
- for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
- E = Record->bases_end(); I != E; ++I) {
- CanQualType BaseT = Context.getCanonicalType((*I).getType());
- if (BaseT == T)
- return true;
-
- // We have to recurse here to cover some really bizarre cases.
- // Obviously, we can only have the dependent type as an indirect
- // base class through a dependent base class, and usually it's
- // impossible to know which instantiation a dependent base class
- // will have. But! If we're actually *inside* the dependent base
- // class, then we know its instantiation and can therefore be
- // reasonably expected to look into it.
-
- // template <class T> class A : Base<T> {
- // class Inner : A<T> {
- // void foo() {
- // Base<T>::foo(); // statically known to be an implicit member
- // reference
- // }
- // };
- // };
-
- CanQual<RecordType> RT = BaseT->getAs<RecordType>();
-
- // Base might be a dependent member type, in which case we
- // obviously can't look into it.
- if (!RT) continue;
-
- CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(RT->getDecl());
- if (BaseRecord->isDefinition() &&
- HasDependentTypeAsBase(Context, BaseRecord, T))
- return true;
- }
-
- return false;
-}
-
-/// Checks whether the given dependent nested-name specifier
-/// introduces an implicit member reference. This is only true if the
-/// nested-name specifier names a type identical to one of the current
-/// instance method's context's (possibly indirect) base classes.
-static bool IsImplicitDependentMemberReference(Sema &SemaRef,
- NestedNameSpecifier *Qualifier,
- QualType &ThisType) {
- // If the context isn't a C++ method, then it isn't an implicit
- // member reference.
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext);
- if (!MD || MD->isStatic())
- return false;
-
- ASTContext &Context = SemaRef.Context;
-
- // We want to check whether the method's context is known to inherit
- // from the type named by the nested name specifier. The trivial
- // case here is:
- // template <class T> class Base { ... };
- // template <class T> class Derived : Base<T> {
- // void foo() {
- // Base<T>::foo();
- // }
- // };
-
- QualType QT = GetTypeForQualifier(Context, Qualifier);
- CanQualType T = Context.getCanonicalType(QT);
-
- // And now, just walk the non-dependent type hierarchy, trying to
- // find the given type as a literal base class.
- CXXRecordDecl *Record = cast<CXXRecordDecl>(MD->getParent());
- if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T ||
- HasDependentTypeAsBase(Context, Record, T)) {
- ThisType = MD->getThisType(Context);
- return true;
- }
-
- return false;
-}
-
-/// ActOnDependentIdExpression - Handle a dependent declaration name
-/// that was just parsed.
+/// ActOnDependentIdExpression - Handle a dependent id-expression that
+/// was just parsed. This is only possible with an explicit scope
+/// specifier naming a dependent type.
Sema::OwningExprResult
Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
DeclarationName Name,
SourceLocation NameLoc,
- bool CheckForImplicitMember,
+ bool isAddressOfOperand,
const TemplateArgumentListInfo *TemplateArgs) {
NestedNameSpecifier *Qualifier
= static_cast<NestedNameSpecifier*>(SS.getScopeRep());
- QualType ThisType;
- if (CheckForImplicitMember &&
- IsImplicitDependentMemberReference(*this, Qualifier, ThisType)) {
- Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType);
-
+ if (!isAddressOfOperand &&
+ isa<CXXMethodDecl>(CurContext) &&
+ cast<CXXMethodDecl>(CurContext)->isInstance()) {
+ QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context);
+
// Since the 'this' expression is synthesized, we don't need to
// perform the double-lookup check.
NamedDecl *FirstQualifierInScope = 0;
- return Owned(CXXDependentScopeMemberExpr::Create(Context, This, true,
+ return Owned(CXXDependentScopeMemberExpr::Create(Context,
+ /*This*/ 0, ThisType,
+ /*IsArrow*/ true,
/*Op*/ SourceLocation(),
Qualifier, SS.getRange(),
FirstQualifierInScope,
@@ -426,10 +330,10 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
switch (Arg.getKind()) {
case ParsedTemplateArgument::Type: {
- DeclaratorInfo *DI;
+ TypeSourceInfo *DI;
QualType T = SemaRef.GetTypeFromParser(Arg.getAsType(), &DI);
if (!DI)
- DI = SemaRef.Context.getTrivialDeclaratorInfo(T, Arg.getLocation());
+ DI = SemaRef.Context.getTrivialTypeSourceInfo(T, Arg.getLocation());
return TemplateArgumentLoc(TemplateArgument(T), DI);
}
@@ -447,7 +351,7 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
}
}
- llvm::llvm_unreachable("Unhandled parsed template argument");
+ llvm_unreachable("Unhandled parsed template argument");
return TemplateArgumentLoc();
}
@@ -515,10 +419,10 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam,
TemplateTypeParmDecl *Parm
= cast<TemplateTypeParmDecl>(TypeParam.getAs<Decl>());
- DeclaratorInfo *DefaultDInfo;
- GetTypeFromParser(DefaultT, &DefaultDInfo);
+ TypeSourceInfo *DefaultTInfo;
+ GetTypeFromParser(DefaultT, &DefaultTInfo);
- assert(DefaultDInfo && "expected source information for type");
+ assert(DefaultTInfo && "expected source information for type");
// C++0x [temp.param]p9:
// A default template-argument may be specified for any kind of
@@ -533,12 +437,12 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam,
// FIXME: Implement this check! Needs a recursive walk over the types.
// Check the template argument itself.
- if (CheckTemplateArgument(Parm, DefaultDInfo)) {
+ if (CheckTemplateArgument(Parm, DefaultTInfo)) {
Parm->setInvalidDecl();
return;
}
- Parm->setDefaultArgument(DefaultDInfo, false);
+ Parm->setDefaultArgument(DefaultTInfo, false);
}
/// \brief Check that the type of a non-type template parameter is
@@ -592,8 +496,8 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
unsigned Depth,
unsigned Position) {
- DeclaratorInfo *DInfo = 0;
- QualType T = GetTypeForDeclarator(D, S, &DInfo);
+ TypeSourceInfo *TInfo = 0;
+ QualType T = GetTypeForDeclarator(D, S, &TInfo);
assert(S->isTemplateParamScope() &&
"Non-type template parameter not in template parameter scope!");
@@ -615,7 +519,7 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
NonTypeTemplateParmDecl *Param
= NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(),
- Depth, Position, ParamName, T, DInfo);
+ Depth, Position, ParamName, T, TInfo);
if (Invalid)
Param->setInvalidDecl();
@@ -1266,8 +1170,27 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
ExplicitSpecializationsInSpecifier;
for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
NNS; NNS = NNS->getPrefix()) {
+ const Type *T = NNS->getAsType();
+ if (!T) break;
+
+ // C++0x [temp.expl.spec]p17:
+ // A member or a member template may be nested within many
+ // enclosing class templates. In an explicit specialization for
+ // such a member, the member declaration shall be preceded by a
+ // template<> for each enclosing class template that is
+ // explicitly specialized.
+ // We interpret this as forbidding typedefs of template
+ // specializations in the scope specifiers of out-of-line decls.
+ if (const TypedefType *TT = dyn_cast<TypedefType>(T)) {
+ const Type *UnderlyingT = TT->LookThroughTypedefs().getTypePtr();
+ if (isa<TemplateSpecializationType>(UnderlyingT))
+ // FIXME: better source location information.
+ Diag(DeclStartLoc, diag::err_typedef_in_def_scope) << QualType(T,0);
+ T = UnderlyingT;
+ }
+
if (const TemplateSpecializationType *SpecType
- = dyn_cast_or_null<TemplateSpecializationType>(NNS->getAsType())) {
+ = dyn_cast<TemplateSpecializationType>(T)) {
TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl();
if (!Template)
continue; // FIXME: should this be an error? probably...
@@ -1481,7 +1404,7 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc,
if (Result.isNull())
return true;
- DeclaratorInfo *DI = Context.CreateDeclaratorInfo(Result);
+ TypeSourceInfo *DI = Context.CreateTypeSourceInfo(Result);
TemplateSpecializationTypeLoc TL
= cast<TemplateSpecializationTypeLoc>(DI->getTypeLoc());
TL.setTemplateNameLoc(TemplateLoc);
@@ -1501,7 +1424,7 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult,
return Sema::TypeResult();
// FIXME: preserve source info, ideally without copying the DI.
- DeclaratorInfo *DI;
+ TypeSourceInfo *DI;
QualType Type = GetTypeFromParser(TypeResult.get(), &DI);
// Verify the tag specifier.
@@ -1687,7 +1610,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
return true;
}
- if (CheckTemplateArgument(Param, AL.getSourceDeclaratorInfo()))
+ if (CheckTemplateArgument(Param, AL.getTypeSourceInfo()))
return true;
// Add the converted template type argument.
@@ -1718,14 +1641,14 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
/// parameters that precede \p Param in the template parameter list.
///
/// \returns the substituted template argument, or NULL if an error occurred.
-static DeclaratorInfo *
+static TypeSourceInfo *
SubstDefaultTemplateArgument(Sema &SemaRef,
TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
TemplateTypeParmDecl *Param,
TemplateArgumentListBuilder &Converted) {
- DeclaratorInfo *ArgType = Param->getDefaultArgumentInfo();
+ TypeSourceInfo *ArgType = Param->getDefaultArgumentInfo();
// If the argument type is dependent, instantiate it now based
// on the previously-computed template arguments.
@@ -1851,7 +1774,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
if (!TypeParm->hasDefaultArgument())
return TemplateArgumentLoc();
- DeclaratorInfo *DI = SubstDefaultTemplateArgument(*this, Template,
+ TypeSourceInfo *DI = SubstDefaultTemplateArgument(*this, Template,
TemplateLoc,
RAngleLoc,
TypeParm,
@@ -2012,7 +1935,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
}
case TemplateArgument::Pack:
- llvm::llvm_unreachable("Caller must expand template argument packs");
+ llvm_unreachable("Caller must expand template argument packs");
break;
}
@@ -2065,16 +1988,16 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
return true;
case TemplateArgument::Declaration:
- llvm::llvm_unreachable(
+ llvm_unreachable(
"Declaration argument with template template parameter");
break;
case TemplateArgument::Integral:
- llvm::llvm_unreachable(
+ llvm_unreachable(
"Integral argument with template template parameter");
break;
case TemplateArgument::Pack:
- llvm::llvm_unreachable("Caller must expand template argument packs");
+ llvm_unreachable("Caller must expand template argument packs");
break;
}
@@ -2168,7 +2091,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
break;
}
- DeclaratorInfo *ArgType = SubstDefaultTemplateArgument(*this,
+ TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this,
Template,
TemplateLoc,
RAngleLoc,
@@ -2240,8 +2163,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
/// This routine implements the semantics of C++ [temp.arg.type]. It
/// returns true if an error occurred, and false otherwise.
bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
- DeclaratorInfo *ArgInfo) {
- assert(ArgInfo && "invalid DeclaratorInfo");
+ TypeSourceInfo *ArgInfo) {
+ assert(ArgInfo && "invalid TypeSourceInfo");
QualType Arg = ArgInfo->getType();
// C++ [temp.arg.type]p2:
@@ -4469,8 +4392,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (D.getDeclSpec().isInlineSpecified() && getLangOptions().CPlusPlus0x)
Diag(D.getDeclSpec().getInlineSpecLoc(),
diag::err_explicit_instantiation_inline)
- << CodeModificationHint::CreateRemoval(
- SourceRange(D.getDeclSpec().getInlineSpecLoc()));
+ <<CodeModificationHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
// FIXME: check for constexpr specifier.
@@ -4493,8 +4415,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (Previous.isAmbiguous())
return true;
- VarDecl *Prev = dyn_cast_or_null<VarDecl>(
- Previous.getAsSingleDecl(Context));
+ VarDecl *Prev = Previous.getAsSingle<VarDecl>();
if (!Prev || !Prev->isStaticDataMember()) {
// We expect to see a data data member here.
Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known)
@@ -4793,7 +4714,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
break;
case LookupResult::FoundUnresolvedValue:
- llvm::llvm_unreachable("unresolved using decl in non-dependent context");
+ llvm_unreachable("unresolved using decl in non-dependent context");
return QualType();
case LookupResult::FoundOverloaded:
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 613ffde..b4754db 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -2361,6 +2361,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
case Type::Enum:
case Type::ObjCInterface:
case Type::ObjCObjectPointer:
+ case Type::UnresolvedUsing:
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base)
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 623cde8..dddb93c8 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -544,7 +544,7 @@ namespace {
/// \brief Rebuild the exception declaration and register the declaration
/// as an instantiated local.
VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T,
- DeclaratorInfo *Declarator,
+ TypeSourceInfo *Declarator,
IdentifierInfo *Name,
SourceLocation Loc, SourceRange TypeRange);
@@ -552,13 +552,10 @@ namespace {
/// elaborated type.
QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag);
- Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E,
- bool isAddressOfOperand);
- Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E,
- bool isAddressOfOperand);
+ Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E);
+ Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E);
- Sema::OwningExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E,
- bool isAddressOfOperand);
+ Sema::OwningExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E);
/// \brief Transforms a template type parameter type by performing
/// substitution of the corresponding template type argument.
@@ -632,7 +629,7 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D,
VarDecl *
TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl,
QualType T,
- DeclaratorInfo *Declarator,
+ TypeSourceInfo *Declarator,
IdentifierInfo *Name,
SourceLocation Loc,
SourceRange TypeRange) {
@@ -670,8 +667,7 @@ TemplateInstantiator::RebuildElaboratedType(QualType T,
}
Sema::OwningExprResult
-TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E,
- bool isAddressOfOperand) {
+TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
if (!E->isTypeDependent())
return SemaRef.Owned(E->Retain());
@@ -694,8 +690,7 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E,
}
Sema::OwningExprResult
-TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E,
- bool isAddressOfOperand) {
+TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
// FIXME: Clean this up a bit
NamedDecl *D = E->getDecl();
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
@@ -782,29 +777,11 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E,
// FindInstantiatedDecl will find it in the local instantiation scope.
}
- NamedDecl *InstD = SemaRef.FindInstantiatedDecl(D, TemplateArgs);
- if (!InstD)
- return SemaRef.ExprError();
-
- assert(!isa<UsingDecl>(InstD) && "decl ref instantiated to UsingDecl");
-
- CXXScopeSpec SS;
- NestedNameSpecifier *Qualifier = 0;
- if (E->getQualifier()) {
- Qualifier = TransformNestedNameSpecifier(E->getQualifier(),
- E->getQualifierRange());
- if (!Qualifier)
- return SemaRef.ExprError();
-
- SS.setScopeRep(Qualifier);
- SS.setRange(E->getQualifierRange());
- }
-
- return SemaRef.BuildDeclarationNameExpr(SS, E->getLocation(), InstD);
+ return TreeTransform<TemplateInstantiator>::TransformDeclRefExpr(E);
}
Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr(
- CXXDefaultArgExpr *E, bool isAddressOfOperand) {
+ CXXDefaultArgExpr *E) {
assert(!cast<FunctionDecl>(E->getParam()->getDeclContext())->
getDescribedFunctionTemplate() &&
"Default arg expressions are never formed in dependent cases.");
@@ -889,7 +866,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
///
/// \returns If the instantiation succeeds, the instantiated
/// type. Otherwise, produces diagnostics and returns a NULL type.
-DeclaratorInfo *Sema::SubstType(DeclaratorInfo *T,
+TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T,
const MultiLevelTemplateArgumentList &Args,
SourceLocation Loc,
DeclarationName Entity) {
@@ -936,6 +913,13 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end();
Base != BaseEnd; ++Base) {
if (!Base->getType()->isDependentType()) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+
+ // Make sure to set the attributes from the base.
+ SetClassDeclAttributesFromBase(Instantiation, BaseDecl,
+ Base->isVirtual());
+
InstantiatedBases.push_back(new (Context) CXXBaseSpecifier(*Base));
continue;
}
@@ -1053,12 +1037,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Member != MemberEnd; ++Member) {
Decl *NewMember = SubstDecl(*Member, Instantiation, TemplateArgs);
if (NewMember) {
- if (NewMember->isInvalidDecl()) {
- Invalid = true;
- } else if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
Fields.push_back(DeclPtrTy::make(Field));
- else if (UsingDecl *UD = dyn_cast<UsingDecl>(NewMember))
- Instantiation->addDecl(UD);
+ else if (NewMember->isInvalidDecl())
+ Invalid = true;
} else {
// FIXME: Eventually, a NULL return will mean that one of the
// instantiations was a semantic disaster, and we'll want to set Invalid =
@@ -1070,13 +1052,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
ActOnFields(0, Instantiation->getLocation(), DeclPtrTy::make(Instantiation),
Fields.data(), Fields.size(), SourceLocation(), SourceLocation(),
0);
+ CheckCompletedCXXClass(Instantiation);
if (Instantiation->isInvalidDecl())
Invalid = true;
- // Add any implicitly-declared members that we might need.
- if (!Invalid)
- AddImplicitlyDeclaredMembersToClass(Instantiation);
-
// Exit the scope of this instantiation.
CurContext = PreviousContext;
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index a125857..8d74bd7 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Lex/Preprocessor.h"
@@ -66,6 +67,8 @@ namespace {
Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
+ Decl *VisitUsingDecl(UsingDecl *D);
+ Decl *VisitUsingShadowDecl(UsingShadowDecl *D);
Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
@@ -125,13 +128,13 @@ TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) {
Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
bool Invalid = false;
- DeclaratorInfo *DI = D->getTypeDeclaratorInfo();
+ TypeSourceInfo *DI = D->getTypeSourceInfo();
if (DI->getType()->isDependentType()) {
DI = SemaRef.SubstType(DI, TemplateArgs,
D->getLocation(), D->getDeclName());
if (!DI) {
Invalid = true;
- DI = SemaRef.Context.getTrivialDeclaratorInfo(SemaRef.Context.IntTy);
+ DI = SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.Context.IntTy);
}
}
@@ -147,9 +150,38 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
return Typedef;
}
+/// \brief Instantiate the arguments provided as part of initialization.
+///
+/// \returns true if an error occurred, false otherwise.
+static bool InstantiateInitializationArguments(Sema &SemaRef,
+ Expr **Args, unsigned NumArgs,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ llvm::SmallVectorImpl<SourceLocation> &FakeCommaLocs,
+ ASTOwningVector<&ActionBase::DeleteExpr> &InitArgs) {
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ // When we hit the first defaulted argument, break out of the loop:
+ // we don't pass those default arguments on.
+ if (Args[I]->isDefaultArgument())
+ break;
+
+ Sema::OwningExprResult Arg = SemaRef.SubstExpr(Args[I], TemplateArgs);
+ if (Arg.isInvalid())
+ return true;
+
+ Expr *ArgExpr = (Expr *)Arg.get();
+ InitArgs.push_back(Arg.release());
+
+ // FIXME: We're faking all of the comma locations. Do we need them?
+ FakeCommaLocs.push_back(
+ SemaRef.PP.getLocForEndOfToken(ArgExpr->getLocEnd()));
+ }
+
+ return false;
+}
+
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// Do substitution on the type of the declaration
- DeclaratorInfo *DI = SemaRef.SubstType(D->getDeclaratorInfo(),
+ TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(),
TemplateArgs,
D->getTypeSpecStartLoc(),
D->getDeclName());
@@ -193,48 +225,82 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
TSK_ImplicitInstantiation);
if (D->getInit()) {
- OwningExprResult Init
- = SemaRef.SubstExpr(D->getInit(), TemplateArgs);
- if (Init.isInvalid())
- Var->setInvalidDecl();
- else if (!D->getType()->isDependentType() &&
- !D->getInit()->isTypeDependent() &&
- !D->getInit()->isValueDependent()) {
- // If neither the declaration's type nor its initializer are dependent,
- // we don't want to redo all the checking, especially since the
- // initializer might have been wrapped by a CXXConstructExpr since we did
- // it the first time.
- Var->setType(D->getType());
- Var->setInit(SemaRef.Context, Init.takeAs<Expr>());
- }
- else if (ParenListExpr *PLE = dyn_cast<ParenListExpr>((Expr *)Init.get())) {
- // FIXME: We're faking all of the comma locations, which is suboptimal.
- // Do we even need these comma locations?
- llvm::SmallVector<SourceLocation, 4> FakeCommaLocs;
- if (PLE->getNumExprs() > 0) {
- FakeCommaLocs.reserve(PLE->getNumExprs() - 1);
- for (unsigned I = 0, N = PLE->getNumExprs() - 1; I != N; ++I) {
- Expr *E = PLE->getExpr(I)->Retain();
- FakeCommaLocs.push_back(
- SemaRef.PP.getLocForEndOfToken(E->getLocEnd()));
- }
- PLE->getExpr(PLE->getNumExprs() - 1)->Retain();
+ if (Var->isStaticDataMember() && !D->isOutOfLine())
+ SemaRef.PushExpressionEvaluationContext(Sema::Unevaluated);
+ else
+ SemaRef.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
+
+ // Extract the initializer, skipping through any temporary-binding
+ // expressions and look at the subexpression as it was written.
+ Expr *DInit = D->getInit();
+ while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(DInit))
+ DInit = Binder->getSubExpr();
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(DInit))
+ DInit = ICE->getSubExprAsWritten();
+
+ if (ParenListExpr *PLE = dyn_cast<ParenListExpr>(DInit)) {
+ // The initializer is a parenthesized list of expressions that is
+ // type-dependent. Instantiate each of the expressions; we'll be
+ // performing direct initialization with them.
+ llvm::SmallVector<SourceLocation, 4> CommaLocs;
+ ASTOwningVector<&ActionBase::DeleteExpr> InitArgs(SemaRef);
+ if (!InstantiateInitializationArguments(SemaRef,
+ PLE->getExprs(),
+ PLE->getNumExprs(),
+ TemplateArgs,
+ CommaLocs, InitArgs)) {
+ // Add the direct initializer to the declaration.
+ SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var),
+ PLE->getLParenLoc(),
+ move_arg(InitArgs),
+ CommaLocs.data(),
+ PLE->getRParenLoc());
}
+ } else if (CXXConstructExpr *Construct =dyn_cast<CXXConstructExpr>(DInit)) {
+ // The initializer resolved to a constructor. Instantiate the constructor
+ // arguments.
+ llvm::SmallVector<SourceLocation, 4> CommaLocs;
+ ASTOwningVector<&ActionBase::DeleteExpr> InitArgs(SemaRef);
+
+ if (!InstantiateInitializationArguments(SemaRef,
+ Construct->getArgs(),
+ Construct->getNumArgs(),
+ TemplateArgs,
+ CommaLocs, InitArgs)) {
+ if (D->hasCXXDirectInitializer()) {
+ SourceLocation FakeLParenLoc =
+ SemaRef.PP.getLocForEndOfToken(D->getLocation());
+ SourceLocation FakeRParenLoc = CommaLocs.empty()? FakeLParenLoc
+ : CommaLocs.back();
+ SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var),
+ FakeLParenLoc,
+ move_arg(InitArgs),
+ CommaLocs.data(),
+ FakeRParenLoc);
+ } else if (InitArgs.size() == 1) {
+ Expr *Init = (Expr*)(InitArgs.take()[0]);
+ SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var),
+ SemaRef.Owned(Init),
+ false);
+ } else {
+ assert(InitArgs.size() == 0);
+ SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false);
+ }
+ }
+ } else {
+ OwningExprResult Init
+ = SemaRef.SubstExpr(D->getInit(), TemplateArgs);
- // Add the direct initializer to the declaration.
- SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var),
- PLE->getLParenLoc(),
- Sema::MultiExprArg(SemaRef,
- (void**)PLE->getExprs(),
- PLE->getNumExprs()),
- FakeCommaLocs.data(),
- PLE->getRParenLoc());
-
- // When Init is destroyed, it will destroy the instantiated ParenListExpr;
- // we've explicitly retained all of its subexpressions already.
- } else
- SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init),
- D->hasCXXDirectInitializer());
+ // FIXME: Not happy about invalidating decls just because of a bad
+ // initializer, unless it affects the type.
+ if (Init.isInvalid())
+ Var->setInvalidDecl();
+ else
+ SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init),
+ D->hasCXXDirectInitializer());
+ }
+
+ SemaRef.PopExpressionEvaluationContext();
} else if (!Var->isStaticDataMember() || Var->isOutOfLine())
SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false);
@@ -243,12 +309,12 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
bool Invalid = false;
- DeclaratorInfo *DI = D->getDeclaratorInfo();
+ TypeSourceInfo *DI = D->getTypeSourceInfo();
if (DI->getType()->isDependentType()) {
DI = SemaRef.SubstType(DI, TemplateArgs,
D->getLocation(), D->getDeclName());
if (!DI) {
- DI = D->getDeclaratorInfo();
+ DI = D->getTypeSourceInfo();
Invalid = true;
} else if (DI->getType()->isFunctionType()) {
// C++ [temp.arg.type]p3:
@@ -561,7 +627,12 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
InstTemplate->setAccess(D->getAccess());
assert(InstTemplate &&
"VisitFunctionDecl/CXXMethodDecl didn't create a template!");
- if (!InstTemplate->getInstantiatedFromMemberTemplate())
+
+ // Link the instantiation back to the pattern *unless* this is a
+ // non-definition friend declaration.
+ if (!InstTemplate->getInstantiatedFromMemberTemplate() &&
+ !(InstTemplate->getFriendObjectKind() &&
+ !D->getTemplatedDecl()->isThisDeclarationADefinition()))
InstTemplate->setInstantiatedFromMemberTemplate(D);
// Add non-friends into the owner.
@@ -638,7 +709,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
TemplateArgs);
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
- D->getDeclName(), T, D->getDeclaratorInfo(),
+ D->getDeclName(), T, D->getTypeSourceInfo(),
D->getStorageClass(),
D->isInlineSpecified(), D->hasWrittenPrototype());
Function->setLexicalDeclContext(Owner);
@@ -700,7 +771,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
Previous.clear();
}
- SemaRef.CheckFunctionDeclaration(Function, Previous, false, Redeclaration,
+ SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous,
+ false, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
// If the original function was part of a friend declaration,
@@ -771,7 +843,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Method = CXXConstructorDecl::Create(SemaRef.Context, Record,
Constructor->getLocation(),
Name, T,
- Constructor->getDeclaratorInfo(),
+ Constructor->getTypeSourceInfo(),
Constructor->isExplicit(),
Constructor->isInlineSpecified(), false);
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
@@ -789,12 +861,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
ConvTy);
Method = CXXConversionDecl::Create(SemaRef.Context, Record,
Conversion->getLocation(), Name,
- T, Conversion->getDeclaratorInfo(),
+ T, Conversion->getTypeSourceInfo(),
Conversion->isInlineSpecified(),
Conversion->isExplicit());
} else {
Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
- D->getDeclName(), T, D->getDeclaratorInfo(),
+ D->getDeclName(), T, D->getTypeSourceInfo(),
D->isStatic(), D->isInlineSpecified());
}
@@ -860,15 +932,16 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
- SemaRef.CheckFunctionDeclaration(Method, Previous, false, Redeclaration,
+ SemaRef.CheckFunctionDeclaration(0, Method, Previous, false, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
+ if (D->isPure())
+ SemaRef.CheckPureMethod(Method, SourceRange());
+
if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) &&
!Method->getFriendObjectKind())
Owner->addDecl(Method);
- SemaRef.AddOverriddenMethods(Record, Method);
-
return Method;
}
@@ -886,7 +959,7 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
QualType T;
- DeclaratorInfo *DI = D->getDeclaratorInfo();
+ TypeSourceInfo *DI = D->getTypeSourceInfo();
if (DI) {
DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(),
D->getDeclName());
@@ -948,7 +1021,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
NonTypeTemplateParmDecl *D) {
// Substitute into the type of the non-type template parameter.
QualType T;
- DeclaratorInfo *DI = D->getDeclaratorInfo();
+ TypeSourceInfo *DI = D->getTypeSourceInfo();
if (DI) {
DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(),
D->getDeclName());
@@ -1027,6 +1100,80 @@ Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
return Inst;
}
+Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
+ // The nested name specifier is non-dependent, so no transformation
+ // is required.
+
+ // We only need to do redeclaration lookups if we're in a class
+ // scope (in fact, it's not really even possible in non-class
+ // scopes).
+ bool CheckRedeclaration = Owner->isRecord();
+
+ LookupResult Prev(SemaRef, D->getDeclName(), D->getLocation(),
+ Sema::LookupUsingDeclName, Sema::ForRedeclaration);
+
+ UsingDecl *NewUD = UsingDecl::Create(SemaRef.Context, Owner,
+ D->getLocation(),
+ D->getNestedNameRange(),
+ D->getUsingLocation(),
+ D->getTargetNestedNameDecl(),
+ D->getDeclName(),
+ D->isTypeName());
+
+ CXXScopeSpec SS;
+ SS.setScopeRep(D->getTargetNestedNameDecl());
+ SS.setRange(D->getNestedNameRange());
+
+ if (CheckRedeclaration) {
+ Prev.setHideTags(false);
+ SemaRef.LookupQualifiedName(Prev, Owner);
+
+ // Check for invalid redeclarations.
+ if (SemaRef.CheckUsingDeclRedeclaration(D->getUsingLocation(),
+ D->isTypeName(), SS,
+ D->getLocation(), Prev))
+ NewUD->setInvalidDecl();
+
+ }
+
+ if (!NewUD->isInvalidDecl() &&
+ SemaRef.CheckUsingDeclQualifier(D->getUsingLocation(), SS,
+ D->getLocation()))
+ NewUD->setInvalidDecl();
+
+ SemaRef.Context.setInstantiatedFromUsingDecl(NewUD, D);
+ NewUD->setAccess(D->getAccess());
+ Owner->addDecl(NewUD);
+
+ // Don't process the shadow decls for an invalid decl.
+ if (NewUD->isInvalidDecl())
+ return NewUD;
+
+ // Process the shadow decls.
+ for (UsingDecl::shadow_iterator I = D->shadow_begin(), E = D->shadow_end();
+ I != E; ++I) {
+ UsingShadowDecl *Shadow = *I;
+ NamedDecl *InstTarget =
+ cast<NamedDecl>(SemaRef.FindInstantiatedDecl(Shadow->getTargetDecl(),
+ TemplateArgs));
+
+ if (CheckRedeclaration &&
+ SemaRef.CheckUsingShadowDecl(NewUD, InstTarget, Prev))
+ continue;
+
+ UsingShadowDecl *InstShadow
+ = SemaRef.BuildUsingShadowDecl(/*Scope*/ 0, NewUD, InstTarget);
+ SemaRef.Context.setInstantiatedFromUsingShadowDecl(InstShadow, Shadow);
+ }
+
+ return NewUD;
+}
+
+Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) {
+ // Ignore these; we handle them in bulk when processing the UsingDecl.
+ return 0;
+}
+
Decl * TemplateDeclInstantiator
::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
NestedNameSpecifier *NNS =
@@ -1047,8 +1194,8 @@ Decl * TemplateDeclInstantiator
/*instantiation*/ true,
/*typename*/ true, D->getTypenameLoc());
if (UD)
- SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD),
- D);
+ SemaRef.Context.setInstantiatedFromUsingDecl(cast<UsingDecl>(UD), D);
+
return UD;
}
@@ -1072,8 +1219,8 @@ Decl * TemplateDeclInstantiator
/*instantiation*/ true,
/*typename*/ false, SourceLocation());
if (UD)
- SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD),
- D);
+ SemaRef.Context.setInstantiatedFromUsingDecl(cast<UsingDecl>(UD), D);
+
return UD;
}
@@ -1336,6 +1483,43 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
}
}
+ const FunctionProtoType *Proto = Tmpl->getType()->getAs<FunctionProtoType>();
+ assert(Proto && "Function template without prototype?");
+
+ if (Proto->hasExceptionSpec() || Proto->hasAnyExceptionSpec() ||
+ Proto->getNoReturnAttr()) {
+ // The function has an exception specification or a "noreturn"
+ // attribute. Substitute into each of the exception types.
+ llvm::SmallVector<QualType, 4> Exceptions;
+ for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) {
+ // FIXME: Poor location information!
+ QualType T
+ = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs,
+ New->getLocation(), New->getDeclName());
+ if (T.isNull() ||
+ SemaRef.CheckSpecifiedExceptionType(T, New->getLocation()))
+ continue;
+
+ Exceptions.push_back(T);
+ }
+
+ // Rebuild the function type
+
+ const FunctionProtoType *NewProto
+ = New->getType()->getAs<FunctionProtoType>();
+ assert(NewProto && "Template instantiation without function prototype?");
+ New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
+ NewProto->arg_type_begin(),
+ NewProto->getNumArgs(),
+ NewProto->isVariadic(),
+ NewProto->getTypeQuals(),
+ Proto->hasExceptionSpec(),
+ Proto->hasAnyExceptionSpec(),
+ Exceptions.size(),
+ Exceptions.data(),
+ Proto->getNoReturnAttr()));
+ }
+
return false;
}
@@ -1352,17 +1536,8 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
New->setAccess(Tmpl->getAccess());
- if (Tmpl->isVirtualAsWritten()) {
- New->setVirtualAsWritten(true);
- Record->setAggregate(false);
- Record->setPOD(false);
- Record->setEmpty(false);
- Record->setPolymorphic(true);
- }
- if (Tmpl->isPure()) {
- New->setPure();
- Record->setAbstract(true);
- }
+ if (Tmpl->isVirtualAsWritten())
+ Record->setMethodAsVirtual(New);
// FIXME: attributes
// FIXME: New needs a pointer to Tmpl
@@ -1623,14 +1798,19 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
MemInitResult NewInit;
if (Init->isBaseInitializer()) {
- QualType BaseType(Init->getBaseClass(), 0);
- BaseType = SubstType(BaseType, TemplateArgs, Init->getSourceLocation(),
- New->getDeclName());
-
- NewInit = BuildBaseInitializer(BaseType,
+ TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(),
+ TemplateArgs,
+ Init->getSourceLocation(),
+ New->getDeclName());
+ if (!BaseTInfo) {
+ New->setInvalidDecl();
+ continue;
+ }
+
+ NewInit = BuildBaseInitializer(BaseTInfo->getType(), BaseTInfo,
(Expr **)NewArgs.data(),
NewArgs.size(),
- Init->getSourceLocation(),
+ Init->getLParenLoc(),
Init->getRParenLoc(),
New->getParent());
} else if (Init->isMemberInitializer()) {
@@ -1646,6 +1826,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(),
NewArgs.size(),
Init->getSourceLocation(),
+ Init->getLParenLoc(),
Init->getRParenLoc());
}
@@ -1749,16 +1930,28 @@ static bool isInstantiationOf(EnumDecl *Pattern,
return false;
}
+static bool isInstantiationOf(UsingShadowDecl *Pattern,
+ UsingShadowDecl *Instance,
+ ASTContext &C) {
+ return C.getInstantiatedFromUsingShadowDecl(Instance) == Pattern;
+}
+
+static bool isInstantiationOf(UsingDecl *Pattern,
+ UsingDecl *Instance,
+ ASTContext &C) {
+ return C.getInstantiatedFromUsingDecl(Instance) == Pattern;
+}
+
static bool isInstantiationOf(UnresolvedUsingValueDecl *Pattern,
UsingDecl *Instance,
ASTContext &C) {
- return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern;
+ return C.getInstantiatedFromUsingDecl(Instance) == Pattern;
}
static bool isInstantiationOf(UnresolvedUsingTypenameDecl *Pattern,
UsingDecl *Instance,
ASTContext &C) {
- return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern;
+ return C.getInstantiatedFromUsingDecl(Instance) == Pattern;
}
static bool isInstantiationOfStaticDataMember(VarDecl *Pattern,
@@ -1776,6 +1969,8 @@ static bool isInstantiationOfStaticDataMember(VarDecl *Pattern,
return false;
}
+// Other is the prospective instantiation
+// D is the prospective pattern
static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
if (D->getKind() != Other->getKind()) {
if (UnresolvedUsingTypenameDecl *UUD
@@ -1827,6 +2022,12 @@ static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
}
}
+ if (UsingDecl *Using = dyn_cast<UsingDecl>(Other))
+ return isInstantiationOf(cast<UsingDecl>(D), Using, Ctx);
+
+ if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(Other))
+ return isInstantiationOf(cast<UsingShadowDecl>(D), Shadow, Ctx);
+
return D->getDeclName() && isa<NamedDecl>(Other) &&
D->getDeclName() == cast<NamedDecl>(Other)->getDeclName();
}
@@ -1979,7 +2180,10 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
ParentDC->decls_end());
}
- assert(Result && "Unable to find instantiation of declaration!");
+ // UsingShadowDecls can instantiate to nothing because of using hiding.
+ assert((Result || isa<UsingShadowDecl>(D))
+ && "Unable to find instantiation of declaration!");
+
D = Result;
}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index afce5e3..37f19f2 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -356,10 +356,14 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){
// or incomplete types shall not be restrict-qualified." C++ also allows
// restrict-qualified references.
if (TypeQuals & DeclSpec::TQ_restrict) {
- if (Result->isPointerType() || Result->isReferenceType()) {
- QualType EltTy = Result->isPointerType() ?
- Result->getAs<PointerType>()->getPointeeType() :
- Result->getAs<ReferenceType>()->getPointeeType();
+ if (Result->isAnyPointerType() || Result->isReferenceType()) {
+ QualType EltTy;
+ if (Result->isObjCObjectPointerType())
+ EltTy = Result;
+ else
+ EltTy = Result->isPointerType() ?
+ Result->getAs<PointerType>()->getPointeeType() :
+ Result->getAs<ReferenceType>()->getPointeeType();
// If we have a pointer or reference, the pointee must have an object
// incomplete type.
@@ -846,20 +850,20 @@ QualType Sema::BuildBlockPointerType(QualType T, unsigned CVR,
return Context.getQualifiedType(Context.getBlockPointerType(T), Quals);
}
-QualType Sema::GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo) {
+QualType Sema::GetTypeFromParser(TypeTy *Ty, TypeSourceInfo **TInfo) {
QualType QT = QualType::getFromOpaquePtr(Ty);
if (QT.isNull()) {
- if (DInfo) *DInfo = 0;
+ if (TInfo) *TInfo = 0;
return QualType();
}
- DeclaratorInfo *DI = 0;
+ TypeSourceInfo *DI = 0;
if (LocInfoType *LIT = dyn_cast<LocInfoType>(QT)) {
QT = LIT->getType();
- DI = LIT->getDeclaratorInfo();
+ DI = LIT->getTypeSourceInfo();
}
- if (DInfo) *DInfo = DI;
+ if (TInfo) *TInfo = DI;
return QT;
}
@@ -870,7 +874,7 @@ QualType Sema::GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo) {
/// owns the declaration of a type (e.g., the definition of a struct
/// type), then *OwnedDecl will receive the owned declaration.
QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
- DeclaratorInfo **DInfo,
+ TypeSourceInfo **TInfo,
TagDecl **OwnedDecl) {
// Determine the type of the declarator. Not all forms of declarator
// have a type.
@@ -897,6 +901,9 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
break;
}
+ if (T.isNull())
+ return T;
+
if (T == Context.UndeducedAutoTy) {
int Error = -1;
@@ -1186,7 +1193,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::Global:
- llvm::llvm_unreachable("Nested-name-specifier must name a type");
+ llvm_unreachable("Nested-name-specifier must name a type");
break;
case NestedNameSpecifier::TypeSpec:
@@ -1256,11 +1263,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (const AttributeList *Attrs = D.getAttributes())
ProcessTypeAttributeList(T, Attrs);
- if (DInfo) {
+ if (TInfo) {
if (D.isInvalidType())
- *DInfo = 0;
+ *TInfo = 0;
else
- *DInfo = GetDeclaratorInfoForDeclarator(D, T);
+ *TInfo = GetTypeSourceInfoForDeclarator(D, T);
}
return T;
@@ -1326,18 +1333,18 @@ namespace {
}
}
void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
- DeclaratorInfo *DInfo = 0;
- Sema::GetTypeFromParser(DS.getTypeRep(), &DInfo);
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo);
// If we got no declarator info from previous Sema routines,
// just fill with the typespec loc.
- if (!DInfo) {
+ if (!TInfo) {
TL.initialize(DS.getTypeSpecTypeLoc());
return;
}
TemplateSpecializationTypeLoc OldTL =
- cast<TemplateSpecializationTypeLoc>(DInfo->getTypeLoc());
+ cast<TemplateSpecializationTypeLoc>(TInfo->getTypeLoc());
TL.copy(OldTL);
}
void VisitTypeLoc(TypeLoc TL) {
@@ -1353,7 +1360,7 @@ namespace {
DeclaratorLocFiller(const DeclaratorChunk &Chunk) : Chunk(Chunk) {}
void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
- llvm::llvm_unreachable("qualified type locs not expected here!");
+ llvm_unreachable("qualified type locs not expected here!");
}
void VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
@@ -1408,18 +1415,18 @@ namespace {
}
void VisitTypeLoc(TypeLoc TL) {
- llvm::llvm_unreachable("unsupported TypeLoc kind in declarator!");
+ llvm_unreachable("unsupported TypeLoc kind in declarator!");
}
};
}
-/// \brief Create and instantiate a DeclaratorInfo with type source information.
+/// \brief Create and instantiate a TypeSourceInfo with type source information.
///
/// \param T QualType referring to the type as written in source code.
-DeclaratorInfo *
-Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T) {
- DeclaratorInfo *DInfo = Context.CreateDeclaratorInfo(T);
- UnqualTypeLoc CurrTL = DInfo->getTypeLoc().getUnqualifiedLoc();
+TypeSourceInfo *
+Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T) {
+ TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T);
+ UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc();
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
DeclaratorLocFiller(D.getTypeObject(i)).Visit(CurrTL);
@@ -1428,16 +1435,16 @@ Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T) {
TypeSpecLocFiller(D.getDeclSpec()).Visit(CurrTL);
- return DInfo;
+ return TInfo;
}
-/// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo.
-QualType Sema::CreateLocInfoType(QualType T, DeclaratorInfo *DInfo) {
+/// \brief Create a LocInfoType to hold the given QualType and TypeSourceInfo.
+QualType Sema::CreateLocInfoType(QualType T, TypeSourceInfo *TInfo) {
// FIXME: LocInfoTypes are "transient", only needed for passing to/from Parser
// and Sema during declaration parsing. Try deallocating/caching them when
// it's appropriate, instead of allocating them and keeping them around.
LocInfoType *LocT = (LocInfoType*)BumpAlloc.Allocate(sizeof(LocInfoType), 8);
- new (LocT) LocInfoType(T, DInfo);
+ new (LocT) LocInfoType(T, TInfo);
assert(LocT->getTypeClass() != T->getTypeClass() &&
"LocInfoType's TypeClass conflicts with an existing Type class");
return QualType(LocT, 0);
@@ -1512,9 +1519,9 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
// the parser.
assert(D.getIdentifier() == 0 && "Type name should have no identifier!");
- DeclaratorInfo *DInfo = 0;
+ TypeSourceInfo *TInfo = 0;
TagDecl *OwnedTag = 0;
- QualType T = GetTypeForDeclarator(D, S, &DInfo, &OwnedTag);
+ QualType T = GetTypeForDeclarator(D, S, &TInfo, &OwnedTag);
if (D.isInvalidType())
return true;
@@ -1531,8 +1538,8 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
<< Context.getTypeDeclType(OwnedTag);
}
- if (DInfo)
- T = CreateLocInfoType(T, DInfo);
+ if (TInfo)
+ T = CreateLocInfoType(T, TInfo);
return T.getAsOpaquePtr();
}
@@ -1640,6 +1647,53 @@ static void HandleNoReturnTypeAttribute(QualType &Type,
Type = S.Context.getNoReturnType(Type);
}
+/// HandleVectorSizeAttribute - this attribute is only applicable to integral
+/// and float scalars, although arrays, pointers, and function return values are
+/// allowed in conjunction with this construct. Aggregates with this attribute
+/// are invalid, even if they are of the same size as a corresponding scalar.
+/// The raw attribute should contain precisely 1 argument, the vector size for
+/// the variable, measured in bytes. If curType and rawAttr are well formed,
+/// this routine will return a new vector type.
+static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, Sema &S) {
+ // Check the attribute arugments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+ Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt vecSize(32);
+ if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << "vector_size" << sizeExpr->getSourceRange();
+ 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;
+ return;
+ }
+ unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType));
+ // vecSize is specified in bytes - convert to bits.
+ unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8);
+
+ // the vector size needs to be an integral multiple of the type size.
+ if (vectorSize % typeSize) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size)
+ << sizeExpr->getSourceRange();
+ return;
+ }
+ if (vectorSize == 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_zero_size)
+ << sizeExpr->getSourceRange();
+ return;
+ }
+
+ // Success! Instantiate the vector type, the number of elements is > 0, and
+ // not required to be a power of 2, unlike GCC.
+ CurType = S.Context.getVectorType(CurType, vectorSize/typeSize);
+}
+
void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
// Scan through and apply attributes to this type where it makes sense. Some
// attributes (such as __address_space__, __vector_size__, etc) apply to the
@@ -1659,6 +1713,9 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
case AttributeList::AT_noreturn:
HandleNoReturnTypeAttribute(Result, *AL, *this);
break;
+ case AttributeList::AT_vector_size:
+ HandleVectorSizeAttr(Result, *AL, *this);
+ break;
}
}
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 28b2174..fd19987 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -172,13 +172,23 @@ public:
return T.isNull();
}
+ /// \brief Determine whether the given call argument should be dropped, e.g.,
+ /// because it is a default argument.
+ ///
+ /// Subclasses can provide an alternative implementation of this routine to
+ /// determine which kinds of call arguments get dropped. By default,
+ /// CXXDefaultArgument nodes are dropped (prior to transformation).
+ bool DropCallArgument(Expr *E) {
+ return E->isDefaultArgument();
+ }
+
/// \brief Transforms the given type into another type.
///
/// By default, this routine transforms a type by creating a
- /// DeclaratorInfo for it and delegating to the appropriate
+ /// TypeSourceInfo for it and delegating to the appropriate
/// function. This is expensive, but we don't mind, because
/// this method is deprecated anyway; all users should be
- /// switched to storing DeclaratorInfos.
+ /// switched to storing TypeSourceInfos.
///
/// \returns the transformed type.
QualType TransformType(QualType T);
@@ -191,7 +201,7 @@ public:
/// may override this function (to take over all type
/// transformations) or some set of the TransformXXXType functions
/// to alter the transformation.
- DeclaratorInfo *TransformType(DeclaratorInfo *DI);
+ TypeSourceInfo *TransformType(TypeSourceInfo *DI);
/// \brief Transform the given type-with-location into a new
/// type, collecting location information in the given builder
@@ -218,19 +228,7 @@ public:
/// other mechanism.
///
/// \returns the transformed expression.
- OwningExprResult TransformExpr(Expr *E) {
- return getDerived().TransformExpr(E, /*isAddressOfOperand=*/false);
- }
-
- /// \brief Transform the given expression.
- ///
- /// By default, this routine transforms an expression by delegating to the
- /// appropriate TransformXXXExpr function to build a new expression.
- /// Subclasses may override this function to transform expressions using some
- /// other mechanism.
- ///
- /// \returns the transformed expression.
- OwningExprResult TransformExpr(Expr *E, bool isAddressOfOperand);
+ OwningExprResult TransformExpr(Expr *E);
/// \brief Transform the given declaration, which is referenced from a type
/// or expression.
@@ -301,9 +299,9 @@ public:
void InventTemplateArgumentLoc(const TemplateArgument &Arg,
TemplateArgumentLoc &ArgLoc);
- /// \brief Fakes up a DeclaratorInfo for a type.
- DeclaratorInfo *InventDeclaratorInfo(QualType T) {
- return SemaRef.Context.getTrivialDeclaratorInfo(T,
+ /// \brief Fakes up a TypeSourceInfo for a type.
+ TypeSourceInfo *InventTypeSourceInfo(QualType T) {
+ return SemaRef.Context.getTrivialTypeSourceInfo(T,
getDerived().getBaseLocation());
}
@@ -328,7 +326,7 @@ public:
#define STMT(Node, Parent) \
OwningStmtResult Transform##Node(Node *S);
#define EXPR(Node, Parent) \
- OwningExprResult Transform##Node(Node *E, bool isAddressOfOperand);
+ OwningExprResult Transform##Node(Node *E);
#define ABSTRACT_EXPR(Node, Parent)
#include "clang/AST/StmtNodes.def"
@@ -461,6 +459,10 @@ public:
/// \brief Build a new unprototyped function type.
QualType RebuildFunctionNoProtoType(QualType ResultType);
+ /// \brief Rebuild an unresolved typename type, given the decl that
+ /// the UnresolvedUsingTypenameDecl was transformed to.
+ QualType RebuildUnresolvedUsingType(Decl *D);
+
/// \brief Build a new typedef type.
QualType RebuildTypedefType(TypedefDecl *Typedef) {
return SemaRef.Context.getTypeDeclType(Typedef);
@@ -779,7 +781,7 @@ public:
/// By default, performs semantic analysis to build the new decaration.
/// Subclasses may override this routine to provide different behavior.
VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T,
- DeclaratorInfo *Declarator,
+ TypeSourceInfo *Declarator,
IdentifierInfo *Name,
SourceLocation Loc,
SourceRange TypeRange) {
@@ -826,15 +828,15 @@ public:
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildDeclRefExpr(NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
- NamedDecl *ND, SourceLocation Loc,
- bool isAddressOfOperand) {
+ ValueDecl *VD, SourceLocation Loc,
+ TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
SS.setScopeRep(Qualifier);
SS.setRange(QualifierRange);
- return getSema().BuildDeclarationNameExpr(Loc, ND,
- /*FIXME:*/false,
- &SS,
- isAddressOfOperand);
+
+ // FIXME: loses template args.
+
+ return getSema().BuildDeclarationNameExpr(SS, Loc, VD);
}
/// \brief Build a new expression in parentheses.
@@ -863,11 +865,14 @@ public:
SS.setScopeRep(Qualifier);
}
+ QualType BaseType = ((Expr*) Base.get())->getType();
+
DeclarationName Name
= SemaRef.Context.DeclarationNames.getCXXDestructorName(
SemaRef.Context.getCanonicalType(DestroyedType));
- return getSema().BuildMemberReferenceExpr(move(Base), OperatorLoc, isArrow,
+ return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
+ OperatorLoc, isArrow,
SS, /*FIXME: FirstQualifier*/ 0,
Name, DestroyedTypeLoc,
/*TemplateArgs*/ 0);
@@ -887,10 +892,10 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- OwningExprResult RebuildSizeOfAlignOf(DeclaratorInfo *DInfo,
+ OwningExprResult RebuildSizeOfAlignOf(TypeSourceInfo *TInfo,
SourceLocation OpLoc,
bool isSizeOf, SourceRange R) {
- return getSema().CreateSizeOfAlignOfExpr(DInfo, OpLoc, isSizeOf, R);
+ return getSema().CreateSizeOfAlignOfExpr(TInfo, OpLoc, isSizeOf, R);
}
/// \brief Build a new sizeof or alignof expression with an expression
@@ -944,7 +949,7 @@ public:
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
SourceLocation MemberLoc,
- NamedDecl *Member,
+ ValueDecl *Member,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
NamedDecl *FirstQualifierInScope) {
if (!Member->getDeclName()) {
@@ -964,7 +969,11 @@ public:
SS.setScopeRep(Qualifier);
}
- return getSema().BuildMemberReferenceExpr(move(Base), OpLoc, isArrow,
+ QualType BaseType = ((Expr*) Base.get())->getType();
+
+ // FIXME: wait, this is re-performing lookup?
+ return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
+ OpLoc, isArrow,
SS, FirstQualifierInScope,
Member->getDeclName(), MemberLoc,
ExplicitTemplateArgs);
@@ -994,19 +1003,6 @@ public:
move(LHS), move(RHS));
}
- /// \brief Build a new implicit cast expression.
- ///
- /// By default, builds a new implicit cast without any semantic analysis.
- /// Subclasses may override this routine to provide different behavior.
- OwningExprResult RebuildImplicitCastExpr(QualType T, CastExpr::CastKind Kind,
- ExprArg SubExpr, bool isLvalue) {
- ImplicitCastExpr *ICE
- = new (getSema().Context) ImplicitCastExpr(T, Kind,
- (Expr *)SubExpr.release(),
- isLvalue);
- return getSema().Owned(ICE);
- }
-
/// \brief Build a new C-style cast expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -1042,8 +1038,10 @@ public:
SourceLocation OpLoc,
SourceLocation AccessorLoc,
IdentifierInfo &Accessor) {
+
CXXScopeSpec SS;
- return getSema().BuildMemberReferenceExpr(move(Base),
+ QualType BaseType = ((Expr*) Base.get())->getType();
+ return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
OpLoc, /*IsArrow*/ false,
SS, /*FirstQualifierInScope*/ 0,
DeclarationName(&Accessor),
@@ -1471,13 +1469,17 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildCXXConstructExpr(QualType T,
+ SourceLocation Loc,
CXXConstructorDecl *Constructor,
bool IsElidable,
MultiExprArg Args) {
- return getSema().BuildCXXConstructExpr(/*FIXME:ConstructLoc*/
- SourceLocation(),
- T, Constructor, IsElidable,
- move(Args));
+ ASTOwningVector<&ActionBase::DeleteExpr> ConvertedArgs(SemaRef);
+ if (getSema().CompleteConstructorCall(Constructor, move(Args), Loc,
+ ConvertedArgs))
+ return getSema().ExprError();
+
+ return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable,
+ move_arg(ConvertedArgs));
}
/// \brief Build a new object-construction expression.
@@ -1522,6 +1524,7 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildCXXDependentScopeMemberExpr(ExprArg BaseE,
+ QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
@@ -1534,7 +1537,8 @@ public:
SS.setRange(QualifierRange);
SS.setScopeRep(Qualifier);
- return SemaRef.BuildMemberReferenceExpr(move(BaseE), OperatorLoc, IsArrow,
+ return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType,
+ OperatorLoc, IsArrow,
SS, FirstQualifierInScope,
Name, MemberLoc, TemplateArgs);
}
@@ -1544,19 +1548,19 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildUnresolvedMemberExpr(ExprArg BaseE,
+ QualType BaseType,
SourceLocation OperatorLoc,
bool IsArrow,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
- OwningExprResult Base = move(BaseE);
-
CXXScopeSpec SS;
SS.setRange(QualifierRange);
SS.setScopeRep(Qualifier);
- return SemaRef.BuildMemberReferenceExpr(move(Base), OperatorLoc, IsArrow,
+ return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType,
+ OperatorLoc, IsArrow,
SS, R, TemplateArgs);
}
@@ -1660,8 +1664,7 @@ Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) {
template<typename Derived>
-Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E,
- bool isAddressOfOperand) {
+Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E) {
if (!E)
return SemaRef.Owned(E);
@@ -1669,8 +1672,7 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E,
case Stmt::NoStmtClass: break;
#define STMT(Node, Parent) case Stmt::Node##Class: break;
#define EXPR(Node, Parent) \
- case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E), \
- isAddressOfOperand);
+ case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E));
#include "clang/AST/StmtNodes.def"
}
@@ -1870,12 +1872,12 @@ void TreeTransform<Derived>::InventTemplateArgumentLoc(
SourceLocation Loc = getDerived().getBaseLocation();
switch (Arg.getKind()) {
case TemplateArgument::Null:
- llvm::llvm_unreachable("null template argument in TreeTransform");
+ llvm_unreachable("null template argument in TreeTransform");
break;
case TemplateArgument::Type:
Output = TemplateArgumentLoc(Arg,
- SemaRef.Context.getTrivialDeclaratorInfo(Arg.getAsType(), Loc));
+ SemaRef.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
break;
@@ -1907,9 +1909,9 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
return false;
case TemplateArgument::Type: {
- DeclaratorInfo *DI = Input.getSourceDeclaratorInfo();
+ TypeSourceInfo *DI = Input.getTypeSourceInfo();
if (DI == NULL)
- DI = InventDeclaratorInfo(Input.getArgument().getAsType());
+ DI = InventTypeSourceInfo(Input.getArgument().getAsType());
DI = getDerived().TransformType(DI);
if (!DI) return true;
@@ -2016,10 +2018,10 @@ QualType TreeTransform<Derived>::TransformType(QualType T) {
// Temporary workaround. All of these transformations should
// eventually turn into transformations on TypeLocs.
- DeclaratorInfo *DI = getSema().Context.CreateDeclaratorInfo(T);
+ TypeSourceInfo *DI = getSema().Context.CreateTypeSourceInfo(T);
DI->getTypeLoc().initialize(getDerived().getBaseLocation());
- DeclaratorInfo *NewDI = getDerived().TransformType(DI);
+ TypeSourceInfo *NewDI = getDerived().TransformType(DI);
if (!NewDI)
return QualType();
@@ -2028,7 +2030,7 @@ QualType TreeTransform<Derived>::TransformType(QualType T) {
}
template<typename Derived>
-DeclaratorInfo *TreeTransform<Derived>::TransformType(DeclaratorInfo *DI) {
+TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI) {
if (getDerived().AlreadyTransformed(DI->getType()))
return DI;
@@ -2041,7 +2043,7 @@ DeclaratorInfo *TreeTransform<Derived>::TransformType(DeclaratorInfo *DI) {
if (Result.isNull())
return 0;
- return TLB.getDeclaratorInfo(SemaRef.Context, Result);
+ return TLB.getTypeSourceInfo(SemaRef.Context, Result);
}
template<typename Derived>
@@ -2055,7 +2057,7 @@ TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T) {
#include "clang/AST/TypeLocNodes.def"
}
- llvm::llvm_unreachable("unhandled type loc!");
+ llvm_unreachable("unhandled type loc!");
return QualType();
}
@@ -2489,10 +2491,10 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
ParmVarDecl *NewParm;
if (OldParm) {
- DeclaratorInfo *OldDI = OldParm->getDeclaratorInfo();
+ TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
assert(OldDI->getType() == T->getArgType(i));
- DeclaratorInfo *NewDI = getDerived().TransformType(OldDI);
+ TypeSourceInfo *NewDI = getDerived().TransformType(OldDI);
if (!NewDI)
return QualType();
@@ -2567,6 +2569,29 @@ QualType TreeTransform<Derived>::TransformFunctionNoProtoType(
return Result;
}
+template<typename Derived> QualType
+TreeTransform<Derived>::TransformUnresolvedUsingType(TypeLocBuilder &TLB,
+ UnresolvedUsingTypeLoc TL) {
+ UnresolvedUsingType *T = TL.getTypePtr();
+ Decl *D = getDerived().TransformDecl(T->getDecl());
+ if (!D)
+ return QualType();
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() || D != T->getDecl()) {
+ Result = getDerived().RebuildUnresolvedUsingType(D);
+ if (Result.isNull())
+ return QualType();
+ }
+
+ // We might get an arbitrary type spec type back. We should at
+ // least always get a type spec type, though.
+ TypeSpecTypeLoc NewTL = TLB.pushTypeSpec(Result);
+ NewTL.setNameLoc(TL.getNameLoc());
+
+ return Result;
+}
+
template<typename Derived>
QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB,
TypedefTypeLoc TL) {
@@ -2622,7 +2647,7 @@ QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB,
TypeOfTypeLoc TL) {
TypeOfType *T = TL.getTypePtr();
- // FIXME: should be an inner type, or at least have a DeclaratorInfo.
+ // FIXME: should be an inner type, or at least have a TypeSourceInfo.
QualType Underlying = getDerived().TransformType(T->getUnderlyingType());
if (Underlying.isNull())
return QualType();
@@ -3364,7 +3389,7 @@ TreeTransform<Derived>::TransformCXXCatchStmt(CXXCatchStmt *S) {
Var = getDerived().RebuildExceptionDecl(ExceptionDecl,
T,
- ExceptionDecl->getDeclaratorInfo(),
+ ExceptionDecl->getTypeSourceInfo(),
ExceptionDecl->getIdentifier(),
ExceptionDecl->getLocation(),
/*FIXME: Inaccurate*/
@@ -3430,15 +3455,13 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
//===----------------------------------------------------------------------===//
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) {
return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
NestedNameSpecifier *Qualifier = 0;
if (E->getQualifier()) {
Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
@@ -3446,72 +3469,74 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E,
if (!Qualifier)
return SemaRef.ExprError();
}
-
- NamedDecl *ND
- = dyn_cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getDecl()));
+
+ ValueDecl *ND
+ = cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getDecl()));
if (!ND)
return SemaRef.ExprError();
if (!getDerived().AlwaysRebuild() &&
Qualifier == E->getQualifier() &&
ND == E->getDecl() &&
- !E->hasExplicitTemplateArgumentList())
- return SemaRef.Owned(E->Retain());
+ !E->hasExplicitTemplateArgumentList()) {
- // FIXME: We're losing the explicit template arguments in this transformation.
+ // Mark it referenced in the new context regardless.
+ // FIXME: this is a bit instantiation-specific.
+ SemaRef.MarkDeclarationReferenced(E->getLocation(), ND);
- llvm::SmallVector<TemplateArgumentLoc, 4> TransArgs(E->getNumTemplateArgs());
- for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) {
- if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I],
- TransArgs[I]))
- return SemaRef.ExprError();
+ return SemaRef.Owned(E->Retain());
}
-
- // FIXME: Pass the qualifier/qualifier range along.
+
+ TemplateArgumentListInfo TransArgs, *TemplateArgs = 0;
+ if (E->hasExplicitTemplateArgumentList()) {
+ TemplateArgs = &TransArgs;
+ TransArgs.setLAngleLoc(E->getLAngleLoc());
+ TransArgs.setRAngleLoc(E->getRAngleLoc());
+ for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) {
+ TemplateArgumentLoc Loc;
+ if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], Loc))
+ return SemaRef.ExprError();
+ TransArgs.addArgument(Loc);
+ }
+ }
+
return getDerived().RebuildDeclRefExpr(Qualifier, E->getQualifierRange(),
- ND, E->getLocation(),
- isAddressOfOperand);
+ ND, E->getLocation(), TemplateArgs);
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformIntegerLiteral(IntegerLiteral *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformIntegerLiteral(IntegerLiteral *E) {
return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E) {
return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformImaginaryLiteral(ImaginaryLiteral *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformImaginaryLiteral(ImaginaryLiteral *E) {
return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformStringLiteral(StringLiteral *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformStringLiteral(StringLiteral *E) {
return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) {
return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformParenExpr(ParenExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) {
OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
if (SubExpr.isInvalid())
return SemaRef.ExprError();
@@ -3525,10 +3550,8 @@ TreeTransform<Derived>::TransformParenExpr(ParenExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E,
- bool isAddressOfOperand) {
- OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr(),
- E->getOpcode() == UnaryOperator::AddrOf);
+TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) {
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
if (SubExpr.isInvalid())
return SemaRef.ExprError();
@@ -3542,12 +3565,11 @@ TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
if (E->isArgumentType()) {
- DeclaratorInfo *OldT = E->getArgumentTypeInfo();
+ TypeSourceInfo *OldT = E->getArgumentTypeInfo();
- DeclaratorInfo *NewT = getDerived().TransformType(OldT);
+ TypeSourceInfo *NewT = getDerived().TransformType(OldT);
if (!NewT)
return SemaRef.ExprError();
@@ -3581,8 +3603,7 @@ TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E) {
OwningExprResult LHS = getDerived().TransformExpr(E->getLHS());
if (LHS.isInvalid())
return SemaRef.ExprError();
@@ -3605,8 +3626,7 @@ TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCallExpr(CallExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCallExpr(CallExpr *E) {
// Transform the callee.
OwningExprResult Callee = getDerived().TransformExpr(E->getCallee());
if (Callee.isInvalid())
@@ -3645,8 +3665,7 @@ TreeTransform<Derived>::TransformCallExpr(CallExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
OwningExprResult Base = getDerived().TransformExpr(E->getBase());
if (Base.isInvalid())
return SemaRef.ExprError();
@@ -3660,8 +3679,8 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E,
return SemaRef.ExprError();
}
- NamedDecl *Member
- = cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getMemberDecl()));
+ ValueDecl *Member
+ = cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getMemberDecl()));
if (!Member)
return SemaRef.ExprError();
@@ -3701,16 +3720,14 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCastExpr(CastExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCastExpr(CastExpr *E) {
assert(false && "Cannot transform abstract class");
return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) {
OwningExprResult LHS = getDerived().TransformExpr(E->getLHS());
if (LHS.isInvalid())
return SemaRef.ExprError();
@@ -3731,15 +3748,13 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E,
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCompoundAssignOperator(
- CompoundAssignOperator *E,
- bool isAddressOfOperand) {
- return getDerived().TransformBinaryOperator(E, isAddressOfOperand);
+ CompoundAssignOperator *E) {
+ return getDerived().TransformBinaryOperator(E);
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E) {
OwningExprResult Cond = getDerived().TransformExpr(E->getCond());
if (Cond.isInvalid())
return SemaRef.ExprError();
@@ -3767,42 +3782,22 @@ TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E,
- bool isAddressOfOperand) {
- TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName());
-
- // FIXME: Will we ever have type information here? It seems like we won't,
- // so do we even need to transform the type?
- QualType T = getDerived().TransformType(E->getType());
- if (T.isNull())
- return SemaRef.ExprError();
-
- OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
- if (SubExpr.isInvalid())
- return SemaRef.ExprError();
-
- if (!getDerived().AlwaysRebuild() &&
- T == E->getType() &&
- SubExpr.get() == E->getSubExpr())
- return SemaRef.Owned(E->Retain());
-
- return getDerived().RebuildImplicitCastExpr(T, E->getCastKind(),
- move(SubExpr),
- E->isLvalueCast());
+TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) {
+ // Implicit casts are eliminated during transformation, since they
+ // will be recomputed by semantic analysis after transformation.
+ return getDerived().TransformExpr(E->getSubExprAsWritten());
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) {
assert(false && "Cannot transform abstract class");
return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) {
QualType T;
{
// FIXME: Source location isn't quite accurate.
@@ -3815,7 +3810,8 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E,
return SemaRef.ExprError();
}
- OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ OwningExprResult SubExpr
+ = getDerived().TransformExpr(E->getSubExprAsWritten());
if (SubExpr.isInvalid())
return SemaRef.ExprError();
@@ -3831,8 +3827,7 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) {
QualType T;
{
// FIXME: Source location isn't quite accurate.
@@ -3861,8 +3856,7 @@ TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E) {
OwningExprResult Base = getDerived().TransformExpr(E->getBase());
if (Base.isInvalid())
return SemaRef.ExprError();
@@ -3881,8 +3875,7 @@ TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) {
bool InitChanged = false;
ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef);
@@ -3904,8 +3897,7 @@ TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) {
Designation Desig;
// transform the initializer value
@@ -3974,8 +3966,7 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E,
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformImplicitValueInitExpr(
- ImplicitValueInitExpr *E,
- bool isAddressOfOperand) {
+ ImplicitValueInitExpr *E) {
TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName());
// FIXME: Will we ever have proper type location here? Will we actually
@@ -3993,8 +3984,7 @@ TreeTransform<Derived>::TransformImplicitValueInitExpr(
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E) {
// FIXME: Do we want the type as written?
QualType T;
@@ -4021,8 +4011,7 @@ TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) {
bool ArgumentChanged = false;
ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef);
for (unsigned I = 0, N = E->getNumExprs(); I != N; ++I) {
@@ -4046,16 +4035,14 @@ TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E,
/// the corresponding label statement by semantic analysis.
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformAddrLabelExpr(AddrLabelExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformAddrLabelExpr(AddrLabelExpr *E) {
return getDerived().RebuildAddrLabelExpr(E->getAmpAmpLoc(), E->getLabelLoc(),
E->getLabel());
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E) {
OwningStmtResult SubStmt
= getDerived().TransformCompoundStmt(E->getSubStmt(), true);
if (SubStmt.isInvalid())
@@ -4072,8 +4059,7 @@ TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E) {
QualType T1, T2;
{
// FIXME: Source location isn't quite accurate.
@@ -4099,8 +4085,7 @@ TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E) {
OwningExprResult Cond = getDerived().TransformExpr(E->getCond());
if (Cond.isInvalid())
return SemaRef.ExprError();
@@ -4126,22 +4111,83 @@ TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformGNUNullExpr(GNUNullExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformGNUNullExpr(GNUNullExpr *E) {
return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ switch (E->getOperator()) {
+ case OO_New:
+ case OO_Delete:
+ case OO_Array_New:
+ case OO_Array_Delete:
+ llvm_unreachable("new and delete operators cannot use CXXOperatorCallExpr");
+ return SemaRef.ExprError();
+
+ case OO_Call: {
+ // This is a call to an object's operator().
+ assert(E->getNumArgs() >= 1 && "Object call is missing arguments");
+
+ // Transform the object itself.
+ OwningExprResult Object = getDerived().TransformExpr(E->getArg(0));
+ if (Object.isInvalid())
+ return SemaRef.ExprError();
+
+ // FIXME: Poor location information
+ SourceLocation FakeLParenLoc
+ = SemaRef.PP.getLocForEndOfToken(
+ static_cast<Expr *>(Object.get())->getLocEnd());
+
+ // Transform the call arguments.
+ ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
+ llvm::SmallVector<SourceLocation, 4> FakeCommaLocs;
+ for (unsigned I = 1, N = E->getNumArgs(); I != N; ++I) {
+ if (getDerived().DropCallArgument(E->getArg(I)))
+ break;
+
+ OwningExprResult Arg = getDerived().TransformExpr(E->getArg(I));
+ if (Arg.isInvalid())
+ return SemaRef.ExprError();
+
+ // FIXME: Poor source location information.
+ SourceLocation FakeCommaLoc
+ = SemaRef.PP.getLocForEndOfToken(
+ static_cast<Expr *>(Arg.get())->getLocEnd());
+ FakeCommaLocs.push_back(FakeCommaLoc);
+ Args.push_back(Arg.release());
+ }
+
+ return getDerived().RebuildCallExpr(move(Object), FakeLParenLoc,
+ move_arg(Args),
+ FakeCommaLocs.data(),
+ E->getLocEnd());
+ }
+
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ case OO_##Name:
+#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
+#include "clang/Basic/OperatorKinds.def"
+ case OO_Subscript:
+ // Handled below.
+ break;
+
+ case OO_Conditional:
+ llvm_unreachable("conditional operator is not actually overloadable");
+ return SemaRef.ExprError();
+
+ case OO_None:
+ case NUM_OVERLOADED_OPERATORS:
+ llvm_unreachable("not an overloaded operator?");
+ return SemaRef.ExprError();
+ }
+
OwningExprResult Callee = getDerived().TransformExpr(E->getCallee());
if (Callee.isInvalid())
return SemaRef.ExprError();
- OwningExprResult First
- = getDerived().TransformExpr(E->getArg(0),
- E->getNumArgs() == 1 && E->getOperator() == OO_Amp);
+ OwningExprResult First = getDerived().TransformExpr(E->getArg(0));
if (First.isInvalid())
return SemaRef.ExprError();
@@ -4167,15 +4213,13 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E,
- bool isAddressOfOperand) {
- return getDerived().TransformCallExpr(E, isAddressOfOperand);
+TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) {
+ return getDerived().TransformCallExpr(E);
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
QualType ExplicitTy;
{
// FIXME: Source location isn't quite accurate.
@@ -4188,7 +4232,8 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E,
return SemaRef.ExprError();
}
- OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ OwningExprResult SubExpr
+ = getDerived().TransformExpr(E->getSubExprAsWritten());
if (SubExpr.isInvalid())
return SemaRef.ExprError();
@@ -4216,38 +4261,33 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E,
- bool isAddressOfOperand) {
- return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand);
+TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E) {
+ return getDerived().TransformCXXNamedCastExpr(E);
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXDynamicCastExpr(CXXDynamicCastExpr *E,
- bool isAddressOfOperand) {
- return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand);
+TreeTransform<Derived>::TransformCXXDynamicCastExpr(CXXDynamicCastExpr *E) {
+ return getDerived().TransformCXXNamedCastExpr(E);
}
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXReinterpretCastExpr(
- CXXReinterpretCastExpr *E,
- bool isAddressOfOperand) {
- return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand);
+ CXXReinterpretCastExpr *E) {
+ return getDerived().TransformCXXNamedCastExpr(E);
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXConstCastExpr(CXXConstCastExpr *E,
- bool isAddressOfOperand) {
- return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand);
+TreeTransform<Derived>::TransformCXXConstCastExpr(CXXConstCastExpr *E) {
+ return getDerived().TransformCXXNamedCastExpr(E);
}
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
- CXXFunctionalCastExpr *E,
- bool isAddressOfOperand) {
+ CXXFunctionalCastExpr *E) {
QualType ExplicitTy;
{
TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName());
@@ -4257,7 +4297,8 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
return SemaRef.ExprError();
}
- OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ OwningExprResult SubExpr
+ = getDerived().TransformExpr(E->getSubExprAsWritten());
if (SubExpr.isInvalid())
return SemaRef.ExprError();
@@ -4277,8 +4318,7 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
if (E->isTypeOperand()) {
TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
@@ -4318,23 +4358,20 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXNullPtrLiteralExpr(
- CXXNullPtrLiteralExpr *E,
- bool isAddressOfOperand) {
+ CXXNullPtrLiteralExpr *E) {
return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName());
QualType T = getDerived().TransformType(E->getType());
@@ -4350,8 +4387,7 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) {
OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
if (SubExpr.isInvalid())
return SemaRef.ExprError();
@@ -4365,8 +4401,7 @@ TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
ParmVarDecl *Param
= cast_or_null<ParmVarDecl>(getDerived().TransformDecl(E->getParam()));
if (!Param)
@@ -4381,8 +4416,7 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName());
QualType T = getDerived().TransformType(E->getType());
@@ -4401,8 +4435,7 @@ TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
// Transform the type that we're allocating
TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName());
QualType AllocType = getDerived().TransformType(E->getAllocatedType());
@@ -4460,8 +4493,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) {
OwningExprResult Operand = getDerived().TransformExpr(E->getArgument());
if (Operand.isInvalid())
return SemaRef.ExprError();
@@ -4479,8 +4511,7 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E,
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
- CXXPseudoDestructorExpr *E,
- bool isAddressOfOperand) {
+ CXXPseudoDestructorExpr *E) {
OwningExprResult Base = getDerived().TransformExpr(E->getBase());
if (Base.isInvalid())
return SemaRef.ExprError();
@@ -4517,8 +4548,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformUnresolvedLookupExpr(
- UnresolvedLookupExpr *Old,
- bool isAddressOfOperand) {
+ UnresolvedLookupExpr *Old) {
TemporaryBase Rebase(*this, Old->getNameLoc(), DeclarationName());
LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(),
@@ -4528,8 +4558,14 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
for (UnresolvedLookupExpr::decls_iterator I = Old->decls_begin(),
E = Old->decls_end(); I != E; ++I) {
NamedDecl *InstD = static_cast<NamedDecl*>(getDerived().TransformDecl(*I));
- if (!InstD)
- return SemaRef.ExprError();
+ if (!InstD) {
+ // Silently ignore these if a UsingShadowDecl instantiated to nothing.
+ // This can happen because of dependent hiding.
+ if (isa<UsingShadowDecl>(*I))
+ continue;
+ else
+ return SemaRef.ExprError();
+ }
// Expand using declarations.
if (isa<UsingDecl>(InstD)) {
@@ -4580,8 +4616,7 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
QualType T = getDerived().TransformType(E->getQueriedType());
@@ -4606,8 +4641,7 @@ TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E,
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
- DependentScopeDeclRefExpr *E,
- bool isAddressOfOperand) {
+ DependentScopeDeclRefExpr *E) {
NestedNameSpecifier *NNS
= getDerived().TransformNestedNameSpecifier(E->getQualifier(),
E->getQualifierRange());
@@ -4647,8 +4681,7 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
QualType T = getDerived().TransformType(E->getType());
@@ -4666,6 +4699,11 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E,
for (CXXConstructExpr::arg_iterator Arg = E->arg_begin(),
ArgEnd = E->arg_end();
Arg != ArgEnd; ++Arg) {
+ if (getDerived().DropCallArgument(*Arg)) {
+ ArgumentChanged = true;
+ break;
+ }
+
OwningExprResult TransArg = getDerived().TransformExpr(*Arg);
if (TransArg.isInvalid())
return SemaRef.ExprError();
@@ -4680,7 +4718,8 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E,
!ArgumentChanged)
return SemaRef.Owned(E->Retain());
- return getDerived().RebuildCXXConstructExpr(T, Constructor, E->isElidable(),
+ return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(),
+ Constructor, E->isElidable(),
move_arg(Args));
}
@@ -4692,8 +4731,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E,
/// must be unique.
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
if (SubExpr.isInvalid())
return SemaRef.ExprError();
@@ -4711,8 +4749,7 @@ TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXExprWithTemporaries(
- CXXExprWithTemporaries *E,
- bool isAddressOfOperand) {
+ CXXExprWithTemporaries *E) {
OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
if (SubExpr.isInvalid())
return SemaRef.ExprError();
@@ -4725,8 +4762,7 @@ TreeTransform<Derived>::TransformCXXExprWithTemporaries(
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
- CXXTemporaryObjectExpr *E,
- bool isAddressOfOperand) {
+ CXXTemporaryObjectExpr *E) {
TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName());
QualType T = getDerived().TransformType(E->getType());
if (T.isNull())
@@ -4776,8 +4812,7 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
- CXXUnresolvedConstructExpr *E,
- bool isAddressOfOperand) {
+ CXXUnresolvedConstructExpr *E) {
TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName());
QualType T = getDerived().TransformType(E->getTypeAsWritten());
if (T.isNull())
@@ -4816,21 +4851,34 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
- CXXDependentScopeMemberExpr *E,
- bool isAddressOfOperand) {
+ CXXDependentScopeMemberExpr *E) {
// Transform the base of the expression.
- OwningExprResult Base = getDerived().TransformExpr(E->getBase());
- if (Base.isInvalid())
- return SemaRef.ExprError();
+ OwningExprResult Base(SemaRef, (Expr*) 0);
+ Expr *OldBase;
+ QualType BaseType;
+ QualType ObjectType;
+ if (!E->isImplicitAccess()) {
+ OldBase = E->getBase();
+ Base = getDerived().TransformExpr(OldBase);
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
- // Start the member reference and compute the object's type.
- Sema::TypeTy *ObjectType = 0;
- Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base),
- E->getOperatorLoc(),
+ // Start the member reference and compute the object's type.
+ Sema::TypeTy *ObjectTy = 0;
+ Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base),
+ E->getOperatorLoc(),
E->isArrow()? tok::arrow : tok::period,
- ObjectType);
- if (Base.isInvalid())
- return SemaRef.ExprError();
+ ObjectTy);
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ ObjectType = QualType::getFromOpaquePtr(ObjectTy);
+ BaseType = ((Expr*) Base.get())->getType();
+ } else {
+ OldBase = 0;
+ BaseType = getDerived().TransformType(E->getBaseType());
+ ObjectType = BaseType->getAs<PointerType>()->getPointeeType();
+ }
// Transform the first part of the nested-name-specifier that qualifies
// the member name.
@@ -4843,29 +4891,31 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
if (E->getQualifier()) {
Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
E->getQualifierRange(),
- QualType::getFromOpaquePtr(ObjectType),
- FirstQualifierInScope);
+ ObjectType,
+ FirstQualifierInScope);
if (!Qualifier)
return SemaRef.ExprError();
}
DeclarationName Name
= getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc(),
- QualType::getFromOpaquePtr(ObjectType));
+ ObjectType);
if (!Name)
return SemaRef.ExprError();
- if (!E->hasExplicitTemplateArgumentList()) {
+ if (!E->hasExplicitTemplateArgs()) {
// This is a reference to a member without an explicitly-specified
// template argument list. Optimize for this common case.
if (!getDerived().AlwaysRebuild() &&
- Base.get() == E->getBase() &&
+ Base.get() == OldBase &&
+ BaseType == E->getBaseType() &&
Qualifier == E->getQualifier() &&
Name == E->getMember() &&
FirstQualifierInScope == E->getFirstQualifierFoundInScope())
return SemaRef.Owned(E->Retain());
return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base),
+ BaseType,
E->isArrow(),
E->getOperatorLoc(),
Qualifier,
@@ -4885,6 +4935,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
}
return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base),
+ BaseType,
E->isArrow(),
E->getOperatorLoc(),
Qualifier,
@@ -4897,12 +4948,18 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) {
// Transform the base of the expression.
- OwningExprResult Base = getDerived().TransformExpr(Old->getBase());
- if (Base.isInvalid())
- return SemaRef.ExprError();
+ OwningExprResult Base(SemaRef, (Expr*) 0);
+ QualType BaseType;
+ if (!Old->isImplicitAccess()) {
+ Base = getDerived().TransformExpr(Old->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+ BaseType = ((Expr*) Base.get())->getType();
+ } else {
+ BaseType = getDerived().TransformType(Old->getBaseType());
+ }
NestedNameSpecifier *Qualifier = 0;
if (Old->getQualifier()) {
@@ -4920,8 +4977,14 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old,
for (UnresolvedMemberExpr::decls_iterator I = Old->decls_begin(),
E = Old->decls_end(); I != E; ++I) {
NamedDecl *InstD = static_cast<NamedDecl*>(getDerived().TransformDecl(*I));
- if (!InstD)
- return SemaRef.ExprError();
+ if (!InstD) {
+ // Silently ignore these if a UsingShadowDecl instantiated to nothing.
+ // This can happen because of dependent hiding.
+ if (isa<UsingShadowDecl>(*I))
+ continue;
+ else
+ return SemaRef.ExprError();
+ }
// Expand using declarations.
if (isa<UsingDecl>(InstD)) {
@@ -4951,6 +5014,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old,
}
return getDerived().RebuildUnresolvedMemberExpr(move(Base),
+ BaseType,
Old->getOperatorLoc(),
Old->isArrow(),
Qualifier,
@@ -4962,15 +5026,13 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) {
// FIXME: poor source location
TemporaryBase Rebase(*this, E->getAtLoc(), DeclarationName());
QualType EncodedType = getDerived().TransformType(E->getEncodedType());
@@ -4988,8 +5050,7 @@ TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
// FIXME: Implement this!
assert(false && "Cannot transform Objective-C expressions yet");
return SemaRef.Owned(E->Retain());
@@ -4997,15 +5058,13 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E) {
return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) {
ObjCProtocolDecl *Protocol
= cast_or_null<ObjCProtocolDecl>(
getDerived().TransformDecl(E->getProtocol()));
@@ -5026,8 +5085,7 @@ TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) {
// FIXME: Implement this!
assert(false && "Cannot transform Objective-C expressions yet");
return SemaRef.Owned(E->Retain());
@@ -5035,8 +5093,7 @@ TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
// FIXME: Implement this!
assert(false && "Cannot transform Objective-C expressions yet");
return SemaRef.Owned(E->Retain());
@@ -5045,8 +5102,7 @@ TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E,
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr(
- ObjCImplicitSetterGetterRefExpr *E,
- bool isAddressOfOperand) {
+ ObjCImplicitSetterGetterRefExpr *E) {
// FIXME: Implement this!
assert(false && "Cannot transform Objective-C expressions yet");
return SemaRef.Owned(E->Retain());
@@ -5054,8 +5110,7 @@ TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr(
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E) {
// FIXME: Implement this!
assert(false && "Cannot transform Objective-C expressions yet");
return SemaRef.Owned(E->Retain());
@@ -5063,8 +5118,7 @@ TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) {
// FIXME: Implement this!
assert(false && "Cannot transform Objective-C expressions yet");
return SemaRef.Owned(E->Retain());
@@ -5072,8 +5126,7 @@ TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) {
bool ArgumentChanged = false;
ASTOwningVector<&ActionBase::DeleteExpr> SubExprs(SemaRef);
for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) {
@@ -5096,8 +5149,7 @@ TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
// FIXME: Implement this!
assert(false && "Cannot transform block expressions yet");
return SemaRef.Owned(E->Retain());
@@ -5105,8 +5157,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E,
- bool isAddressOfOperand) {
+TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) {
// FIXME: Implement this!
assert(false && "Cannot transform block-related expressions yet");
return SemaRef.Owned(E->Retain());
@@ -5282,6 +5333,30 @@ QualType TreeTransform<Derived>::RebuildFunctionNoProtoType(QualType T) {
}
template<typename Derived>
+QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(Decl *D) {
+ assert(D && "no decl found");
+ if (D->isInvalidDecl()) return QualType();
+
+ TypeDecl *Ty;
+ if (isa<UsingDecl>(D)) {
+ UsingDecl *Using = cast<UsingDecl>(D);
+ assert(Using->isTypeName() &&
+ "UnresolvedUsingTypenameDecl transformed to non-typename using");
+
+ // A valid resolved using typename decl points to exactly one type decl.
+ assert(++Using->shadow_begin() == Using->shadow_end());
+ Ty = cast<TypeDecl>((*Using->shadow_begin())->getTargetDecl());
+
+ } else {
+ assert(isa<UnresolvedUsingTypenameDecl>(D) &&
+ "UnresolvedUsingTypenameDecl transformed to non-using decl");
+ Ty = cast<UnresolvedUsingTypenameDecl>(D);
+ }
+
+ return SemaRef.Context.getTypeDeclType(Ty);
+}
+
+template<typename Derived>
QualType TreeTransform<Derived>::RebuildTypeOfExprType(ExprArg E) {
return SemaRef.BuildTypeofExprType(E.takeAs<Expr>());
}
@@ -5320,7 +5395,7 @@ TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
Range.getEnd(), II,
ObjectType,
FirstQualifierInScope,
- false));
+ false, false));
}
template<typename Derived>
OpenPOWER on IntegriCloud