summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2009-12-01 11:08:04 +0000
committerrdivacky <rdivacky@FreeBSD.org>2009-12-01 11:08:04 +0000
commit4b08eb6308ca90a6c08e2fc79d100821b1b1f6aa (patch)
tree867cbbe32a66fd7d62dd9ce9df23a23fefdb8290 /lib
parent6df2408694f81a03eb8b0e3b013272042233c061 (diff)
downloadFreeBSD-src-4b08eb6308ca90a6c08e2fc79d100821b1b1f6aa.zip
FreeBSD-src-4b08eb6308ca90a6c08e2fc79d100821b1b1f6aa.tar.gz
Update clang to r90226.
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/ASTContext.cpp113
-rw-r--r--lib/AST/Decl.cpp205
-rw-r--r--lib/AST/DeclBase.cpp15
-rw-r--r--lib/AST/DeclCXX.cpp46
-rw-r--r--lib/AST/DeclPrinter.cpp15
-rw-r--r--lib/AST/DeclTemplate.cpp7
-rw-r--r--lib/AST/DeclarationName.cpp44
-rw-r--r--lib/AST/Expr.cpp212
-rw-r--r--lib/AST/ExprCXX.cpp244
-rw-r--r--lib/AST/ExprConstant.cpp62
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp259
-rw-r--r--lib/AST/RecordLayoutBuilder.h20
-rw-r--r--lib/AST/Stmt.cpp6
-rw-r--r--lib/AST/StmtDumper.cpp3
-rw-r--r--lib/AST/StmtPrinter.cpp52
-rw-r--r--lib/AST/StmtProfile.cpp46
-rw-r--r--lib/AST/StmtViz.cpp5
-rw-r--r--lib/AST/TemplateBase.cpp14
-rw-r--r--lib/AST/Type.cpp6
-rw-r--r--lib/AST/TypePrinter.cpp10
-rw-r--r--lib/Analysis/AnalysisContext.cpp87
-rw-r--r--lib/Analysis/ArrayBoundChecker.cpp12
-rw-r--r--lib/Analysis/AttrNonNullChecker.cpp8
-rw-r--r--lib/Analysis/BadCallChecker.cpp57
-rw-r--r--lib/Analysis/BasicConstraintManager.cpp7
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.cpp73
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.h12
-rw-r--r--lib/Analysis/BasicStore.cpp5
-rw-r--r--lib/Analysis/BugReporter.cpp23
-rw-r--r--lib/Analysis/BugReporterVisitors.cpp4
-rw-r--r--lib/Analysis/CFG.cpp22
-rw-r--r--lib/Analysis/CFRefCount.cpp252
-rw-r--r--lib/Analysis/CMakeLists.txt7
-rw-r--r--lib/Analysis/CallAndMessageChecker.cpp267
-rw-r--r--lib/Analysis/CallGraph.cpp4
-rw-r--r--lib/Analysis/CallInliner.cpp2
-rw-r--r--lib/Analysis/CastToStructChecker.cpp4
-rw-r--r--lib/Analysis/CheckDeadStores.cpp18
-rw-r--r--lib/Analysis/CheckObjCDealloc.cpp7
-rw-r--r--lib/Analysis/CheckObjCInstMethSignature.cpp2
-rw-r--r--lib/Analysis/CheckObjCUnusedIVars.cpp36
-rw-r--r--lib/Analysis/CheckSecuritySyntaxOnly.cpp9
-rw-r--r--lib/Analysis/CheckSizeofPointer.cpp3
-rw-r--r--lib/Analysis/Checker.cpp35
-rw-r--r--lib/Analysis/DereferenceChecker.cpp68
-rw-r--r--lib/Analysis/DivZeroChecker.cpp7
-rw-r--r--lib/Analysis/Environment.cpp3
-rw-r--r--lib/Analysis/FixedAddressChecker.cpp4
-rw-r--r--lib/Analysis/GRCoreEngine.cpp7
-rw-r--r--lib/Analysis/GRExprEngine.cpp462
-rw-r--r--lib/Analysis/GRExprEngineExperimentalChecks.cpp2
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.cpp400
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.h6
-rw-r--r--lib/Analysis/GRState.cpp23
-rw-r--r--lib/Analysis/LiveVariables.cpp25
-rw-r--r--lib/Analysis/MallocChecker.cpp21
-rw-r--r--lib/Analysis/MemRegion.cpp132
-rw-r--r--lib/Analysis/NSAutoreleasePoolChecker.cpp6
-rw-r--r--lib/Analysis/NSErrorChecker.cpp7
-rw-r--r--lib/Analysis/PointerArithChecker.cpp4
-rw-r--r--lib/Analysis/PointerSubChecker.cpp4
-rw-r--r--lib/Analysis/PthreadLockChecker.cpp8
-rw-r--r--lib/Analysis/RangeConstraintManager.cpp11
-rw-r--r--lib/Analysis/RegionStore.cpp92
-rw-r--r--lib/Analysis/ReturnPointerRangeChecker.cpp5
-rw-r--r--lib/Analysis/ReturnStackAddressChecker.cpp13
-rw-r--r--lib/Analysis/ReturnUndefChecker.cpp4
-rw-r--r--lib/Analysis/SVals.cpp2
-rw-r--r--lib/Analysis/SimpleSValuator.cpp3
-rw-r--r--lib/Analysis/Store.cpp10
-rw-r--r--lib/Analysis/UndefBranchChecker.cpp117
-rw-r--r--lib/Analysis/UndefResultChecker.cpp86
-rw-r--r--lib/Analysis/UndefinedArgChecker.cpp56
-rw-r--r--lib/Analysis/UndefinedArraySubscriptChecker.cpp4
-rw-r--r--lib/Analysis/UndefinedAssignmentChecker.cpp22
-rw-r--r--lib/Analysis/UninitializedValues.cpp7
-rw-r--r--lib/Analysis/VLASizeChecker.cpp9
-rw-r--r--lib/Analysis/ValueManager.cpp11
-rw-r--r--lib/Basic/TargetInfo.cpp1
-rw-r--r--lib/Basic/Targets.cpp49
-rw-r--r--lib/Basic/TokenKinds.cpp55
-rw-r--r--lib/CodeGen/CGBlocks.cpp16
-rw-r--r--lib/CodeGen/CGBuiltin.cpp11
-rw-r--r--lib/CodeGen/CGCXX.cpp346
-rw-r--r--lib/CodeGen/CGCall.cpp62
-rw-r--r--lib/CodeGen/CGClass.cpp (renamed from lib/CodeGen/CGCXXClass.cpp)124
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp42
-rw-r--r--lib/CodeGen/CGDecl.cpp20
-rw-r--r--lib/CodeGen/CGException.cpp390
-rw-r--r--lib/CodeGen/CGExpr.cpp84
-rw-r--r--lib/CodeGen/CGExprAgg.cpp30
-rw-r--r--lib/CodeGen/CGExprCXX.cpp (renamed from lib/CodeGen/CGCXXExpr.cpp)59
-rw-r--r--lib/CodeGen/CGExprComplex.cpp31
-rw-r--r--lib/CodeGen/CGExprConstant.cpp13
-rw-r--r--lib/CodeGen/CGExprScalar.cpp181
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp13
-rw-r--r--lib/CodeGen/CGObjCMac.cpp21
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp34
-rw-r--r--lib/CodeGen/CGRtti.cpp45
-rw-r--r--lib/CodeGen/CGStmt.cpp136
-rw-r--r--lib/CodeGen/CGTemporaries.cpp (renamed from lib/CodeGen/CGCXXTemp.cpp)24
-rw-r--r--lib/CodeGen/CGVtable.cpp546
-rw-r--r--lib/CodeGen/CGVtable.h86
-rw-r--r--lib/CodeGen/CMakeLists.txt8
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp35
-rw-r--r--lib/CodeGen/CodeGenFunction.h178
-rw-r--r--lib/CodeGen/CodeGenModule.cpp182
-rw-r--r--lib/CodeGen/CodeGenModule.h18
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp9
-rw-r--r--lib/CodeGen/CodeGenTypes.h31
-rw-r--r--lib/CodeGen/Mangle.cpp816
-rw-r--r--lib/CodeGen/Mangle.h91
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp4
-rw-r--r--lib/CodeGen/TargetABIInfo.cpp28
-rw-r--r--lib/Driver/ArgList.cpp112
-rw-r--r--lib/Driver/CC1Options.cpp9
-rw-r--r--lib/Driver/Compilation.cpp7
-rw-r--r--lib/Driver/Driver.cpp7
-rw-r--r--lib/Driver/DriverOptions.cpp5
-rw-r--r--lib/Driver/Tools.cpp179
-rw-r--r--lib/Driver/Types.cpp1
-rw-r--r--lib/Frontend/ASTUnit.cpp102
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp32
-rw-r--r--lib/Frontend/Backend.cpp79
-rw-r--r--lib/Frontend/CMakeLists.txt1
-rw-r--r--lib/Frontend/CacheTokens.cpp14
-rw-r--r--lib/Frontend/CompilerInstance.cpp22
-rw-r--r--lib/Frontend/CompilerInvocation.cpp807
-rw-r--r--lib/Frontend/DependencyFile.cpp3
-rw-r--r--lib/Frontend/DiagChecker.cpp3
-rw-r--r--lib/Frontend/FrontendAction.cpp9
-rw-r--r--lib/Frontend/FrontendActions.cpp13
-rw-r--r--lib/Frontend/GeneratePCH.cpp7
-rw-r--r--lib/Frontend/HTMLDiagnostics.cpp3
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp157
-rw-r--r--lib/Frontend/InitPreprocessor.cpp7
-rw-r--r--lib/Frontend/LangStandards.cpp44
-rw-r--r--lib/Frontend/PCHReader.cpp22
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp4
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp4
-rw-r--r--lib/Frontend/PCHWriter.cpp24
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp4
-rw-r--r--lib/Frontend/PlistDiagnostics.cpp4
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp15
-rw-r--r--lib/Frontend/RewriteMacros.cpp3
-rw-r--r--lib/Frontend/RewriteObjC.cpp2
-rw-r--r--lib/Frontend/StmtXML.cpp5
-rw-r--r--lib/Frontend/TextDiagnosticBuffer.cpp21
-rw-r--r--lib/Frontend/VerifyDiagnosticsClient.cpp8
-rw-r--r--lib/Headers/stdint.h71
-rw-r--r--lib/Index/Analyzer.cpp9
-rw-r--r--lib/Index/DeclReferenceMap.cpp3
-rw-r--r--lib/Index/ResolveLocation.cpp7
-rw-r--r--lib/Index/SelectorMap.cpp3
-rw-r--r--lib/Lex/Lexer.cpp11
-rw-r--r--lib/Lex/LiteralSupport.cpp42
-rw-r--r--lib/Lex/PPDirectives.cpp5
-rw-r--r--lib/Lex/PPLexerChange.cpp20
-rw-r--r--lib/Lex/PTHLexer.cpp14
-rw-r--r--lib/Parse/AttributeList.cpp24
-rw-r--r--lib/Parse/MinimalAction.cpp2
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp3
-rw-r--r--lib/Parse/ParseDecl.cpp126
-rw-r--r--lib/Parse/ParseDeclCXX.cpp270
-rw-r--r--lib/Parse/ParseExpr.cpp29
-rw-r--r--lib/Parse/ParseExprCXX.cpp113
-rw-r--r--lib/Parse/ParseObjc.cpp8
-rw-r--r--lib/Parse/ParseStmt.cpp187
-rw-r--r--lib/Parse/ParseTemplate.cpp50
-rw-r--r--lib/Parse/ParseTentative.cpp88
-rw-r--r--lib/Parse/Parser.cpp27
-rw-r--r--lib/Rewrite/HTMLRewrite.cpp6
-rw-r--r--lib/Rewrite/TokenRewriter.cpp3
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp492
-rw-r--r--lib/Sema/Lookup.h46
-rw-r--r--lib/Sema/ParseAST.cpp3
-rw-r--r--lib/Sema/Sema.cpp15
-rw-r--r--lib/Sema/Sema.h354
-rw-r--r--lib/Sema/SemaCodeComplete.cpp103
-rw-r--r--lib/Sema/SemaDecl.cpp183
-rw-r--r--lib/Sema/SemaDeclAttr.cpp223
-rw-r--r--lib/Sema/SemaDeclCXX.cpp230
-rw-r--r--lib/Sema/SemaExpr.cpp1957
-rw-r--r--lib/Sema/SemaExprCXX.cpp210
-rw-r--r--lib/Sema/SemaInit.cpp45
-rw-r--r--lib/Sema/SemaLookup.cpp52
-rw-r--r--lib/Sema/SemaOverload.cpp556
-rw-r--r--lib/Sema/SemaStmt.cpp246
-rw-r--r--lib/Sema/SemaTemplate.cpp723
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp108
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp54
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp38
-rw-r--r--lib/Sema/SemaType.cpp1
-rw-r--r--lib/Sema/TreeTransform.h673
194 files changed, 10578 insertions, 6394 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index dc13e7f..6c9ecf0 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -48,6 +48,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {
ObjCIdRedefinitionType = QualType();
ObjCClassRedefinitionType = QualType();
+ ObjCSelRedefinitionType = QualType();
if (size_reserve > 0) Types.reserve(size_reserve);
TUDecl = TranslationUnitDecl::Create(*this);
InitBuiltinTypes();
@@ -220,10 +221,12 @@ void ASTContext::InitBuiltinTypes() {
// "Builtin" typedefs set by Sema::ActOnTranslationUnitScope().
ObjCIdTypedefType = QualType();
ObjCClassTypedefType = QualType();
+ ObjCSelTypedefType = QualType();
- // Builtin types for 'id' and 'Class'.
+ // Builtin types for 'id', 'Class', and 'SEL'.
InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId);
InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass);
+ InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel);
ObjCConstantStringType = QualType();
@@ -517,18 +520,23 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
/// getDeclAlignInBytes - Return a conservative estimate of the alignment of the
/// specified decl. Note that bitfields do not have a valid alignment, so
/// this method will assert on them.
-unsigned ASTContext::getDeclAlignInBytes(const Decl *D) {
+/// If @p RefAsPointee, references are treated like their underlying type
+/// (for alignof), else they're treated like pointers (for CodeGen).
+unsigned ASTContext::getDeclAlignInBytes(const Decl *D, bool RefAsPointee) {
unsigned Align = Target.getCharWidth();
if (const AlignedAttr* AA = D->getAttr<AlignedAttr>())
- Align = std::max(Align, AA->getAlignment());
+ Align = std::max(Align, AA->getMaxAlignment());
if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
QualType T = VD->getType();
if (const ReferenceType* RT = T->getAs<ReferenceType>()) {
- unsigned AS = RT->getPointeeType().getAddressSpace();
- Align = Target.getPointerAlign(AS);
- } else if (!T->isIncompleteType() && !T->isFunctionType()) {
+ if (RefAsPointee)
+ T = RT->getPointeeType();
+ else
+ T = getPointerType(RT->getPointeeType());
+ }
+ if (!T->isIncompleteType() && !T->isFunctionType()) {
// Incomplete or function types default to 1.
while (isa<VariableArrayType>(T) || isa<IncompleteArrayType>(T))
T = cast<ArrayType>(T)->getElementType();
@@ -687,19 +695,21 @@ ASTContext::getTypeInfo(const Type *T) {
Align = Target.getPointerAlign(AS);
break;
}
+ case Type::LValueReference:
+ case Type::RValueReference: {
+ // alignof and sizeof should never enter this code path here, so we go
+ // the pointer route.
+ unsigned AS = cast<ReferenceType>(T)->getPointeeType().getAddressSpace();
+ Width = Target.getPointerWidth(AS);
+ Align = Target.getPointerAlign(AS);
+ break;
+ }
case Type::Pointer: {
unsigned AS = cast<PointerType>(T)->getPointeeType().getAddressSpace();
Width = Target.getPointerWidth(AS);
Align = Target.getPointerAlign(AS);
break;
}
- case Type::LValueReference:
- case Type::RValueReference:
- // "When applied to a reference or a reference type, the result is the size
- // of the referenced type." C++98 5.3.3p2: expr.sizeof.
- // FIXME: This is wrong for struct layout: a reference in a struct has
- // pointer size.
- return getTypeInfo(cast<ReferenceType>(T)->getPointeeType());
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
@@ -761,7 +771,8 @@ ASTContext::getTypeInfo(const Type *T) {
case Type::Typedef: {
const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl();
if (const AlignedAttr *Aligned = Typedef->getAttr<AlignedAttr>()) {
- Align = Aligned->getAlignment();
+ Align = std::max(Aligned->getMaxAlignment(),
+ getTypeAlign(Typedef->getUnderlyingType().getTypePtr()));
Width = getTypeSize(Typedef->getUnderlyingType().getTypePtr());
} else
return getTypeInfo(Typedef->getUnderlyingType().getTypePtr());
@@ -1460,16 +1471,24 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy,
ArrayType::ArraySizeModifier ASM,
unsigned EltTypeQuals,
SourceRange Brackets) {
- assert((NumElts->isTypeDependent() || NumElts->isValueDependent()) &&
+ assert((!NumElts || NumElts->isTypeDependent() ||
+ NumElts->isValueDependent()) &&
"Size must be type- or value-dependent!");
- llvm::FoldingSetNodeID ID;
- DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM,
- EltTypeQuals, NumElts);
-
void *InsertPos = 0;
- DependentSizedArrayType *Canon
- = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
+ DependentSizedArrayType *Canon = 0;
+
+ if (NumElts) {
+ // Dependently-sized array types that do not have a specified
+ // number of elements will have their sizes deduced from an
+ // initializer.
+ llvm::FoldingSetNodeID ID;
+ DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM,
+ EltTypeQuals, NumElts);
+
+ Canon = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
+ }
+
DependentSizedArrayType *New;
if (Canon) {
// We already have a canonical version of this array type; use it as
@@ -1483,7 +1502,9 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy,
New = new (*this, TypeAlignment)
DependentSizedArrayType(*this, EltTy, QualType(),
NumElts, ASM, EltTypeQuals, Brackets);
- DependentSizedArrayTypes.InsertNode(New, InsertPos);
+
+ if (NumElts)
+ DependentSizedArrayTypes.InsertNode(New, InsertPos);
} else {
QualType Canon = getDependentSizedArrayType(CanonEltTy, NumElts,
ASM, EltTypeQuals,
@@ -1818,9 +1839,10 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
- const TemplateArgumentLoc *Args,
- unsigned NumArgs,
+ const TemplateArgumentListInfo &Args,
QualType Canon) {
+ unsigned NumArgs = Args.size();
+
llvm::SmallVector<TemplateArgument, 4> ArgVec;
ArgVec.reserve(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i)
@@ -2320,6 +2342,22 @@ CanQualType ASTContext::getCanonicalType(QualType T) {
VAT->getBracketsRange()));
}
+DeclarationName ASTContext::getNameForTemplate(TemplateName Name) {
+ if (TemplateDecl *TD = Name.getAsTemplateDecl())
+ return TD->getDeclName();
+
+ if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
+ if (DTN->isIdentifier()) {
+ return DeclarationNames.getIdentifier(DTN->getIdentifier());
+ } else {
+ return DeclarationNames.getCXXOperatorName(DTN->getOperator());
+ }
+ }
+
+ assert(Name.getAsOverloadedFunctionDecl());
+ return Name.getAsOverloadedFunctionDecl()->getDeclName();
+}
+
TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) {
// If this template name refers to a template, the canonical
// template name merely stores the template itself.
@@ -3374,9 +3412,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
false);
return;
}
-
+
if (const PointerType *PT = T->getAs<PointerType>()) {
+ if (PT->isObjCSelType()) {
+ S += ':';
+ return;
+ }
QualType PointeeTy = PT->getPointeeType();
+
bool isReadOnly = false;
// For historical/compatibility reasons, the read-only qualifier of the
// pointee gets emitted _before_ the '^'. The read-only qualifier of
@@ -3407,10 +3450,6 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
S.replace(S.end()-2, S.end(), replace);
}
}
- if (isObjCSelType(PointeeTy)) {
- S += ':';
- return;
- }
if (PointeeTy->isCharType()) {
// char pointer types should be encoded as '*' unless it is a
@@ -3633,21 +3672,7 @@ void ASTContext::setObjCIdType(QualType T) {
}
void ASTContext::setObjCSelType(QualType T) {
- ObjCSelType = T;
-
- const TypedefType *TT = T->getAs<TypedefType>();
- if (!TT)
- return;
- TypedefDecl *TD = TT->getDecl();
-
- // typedef struct objc_selector *SEL;
- const PointerType *ptr = TD->getUnderlyingType()->getAs<PointerType>();
- if (!ptr)
- return;
- const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
- if (!rec)
- return;
- SelStructType = rec;
+ ObjCSelTypedefType = T;
}
void ASTContext::setObjCProtoType(QualType QT) {
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index bdc8047..572d76f 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -211,6 +211,203 @@ FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
+static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
+ assert(D->getDeclContext()->getLookupContext()->isFileContext() &&
+ "Not a name having namespace scope");
+ ASTContext &Context = D->getASTContext();
+
+ // C++ [basic.link]p3:
+ // A name having namespace scope (3.3.6) has internal linkage if it
+ // is the name of
+ // - an object, reference, function or function template that is
+ // explicitly declared static; or,
+ // (This bullet corresponds to C99 6.2.2p3.)
+ if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ // Explicitly declared static.
+ if (Var->getStorageClass() == VarDecl::Static)
+ return NamedDecl::InternalLinkage;
+
+ // - an object or reference that is explicitly declared const
+ // and neither explicitly declared extern nor previously
+ // declared to have external linkage; or
+ // (there is no equivalent in C99)
+ if (Context.getLangOptions().CPlusPlus &&
+ Var->getType().isConstant(Context) &&
+ Var->getStorageClass() != VarDecl::Extern &&
+ Var->getStorageClass() != VarDecl::PrivateExtern) {
+ bool FoundExtern = false;
+ for (const VarDecl *PrevVar = Var->getPreviousDeclaration();
+ PrevVar && !FoundExtern;
+ PrevVar = PrevVar->getPreviousDeclaration())
+ if (PrevVar->getLinkage() == NamedDecl::ExternalLinkage)
+ FoundExtern = true;
+
+ if (!FoundExtern)
+ return NamedDecl::InternalLinkage;
+ }
+ } else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
+ const FunctionDecl *Function = 0;
+ if (const FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(D))
+ Function = FunTmpl->getTemplatedDecl();
+ else
+ Function = cast<FunctionDecl>(D);
+
+ // Explicitly declared static.
+ if (Function->getStorageClass() == FunctionDecl::Static)
+ return NamedDecl::InternalLinkage;
+ } else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
+ // - a data member of an anonymous union.
+ if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion())
+ return NamedDecl::InternalLinkage;
+ }
+
+ // C++ [basic.link]p4:
+
+ // A name having namespace scope has external linkage if it is the
+ // name of
+ //
+ // - an object or reference, unless it has internal linkage; or
+ if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ if (!Context.getLangOptions().CPlusPlus &&
+ (Var->getStorageClass() == VarDecl::Extern ||
+ Var->getStorageClass() == VarDecl::PrivateExtern)) {
+ // C99 6.2.2p4:
+ // For an identifier declared with the storage-class specifier
+ // extern in a scope in which a prior declaration of that
+ // identifier is visible, if the prior declaration specifies
+ // internal or external linkage, the linkage of the identifier
+ // at the later declaration is the same as the linkage
+ // specified at the prior declaration. If no prior declaration
+ // is visible, or if the prior declaration specifies no
+ // linkage, then the identifier has external linkage.
+ if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) {
+ if (NamedDecl::Linkage L = PrevVar->getLinkage())
+ return L;
+ }
+ }
+
+ // C99 6.2.2p5:
+ // If the declaration of an identifier for an object has file
+ // scope and no storage-class specifier, its linkage is
+ // external.
+ return NamedDecl::ExternalLinkage;
+ }
+
+ // - a function, unless it has internal linkage; or
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ // C99 6.2.2p5:
+ // If the declaration of an identifier for a function has no
+ // storage-class specifier, its linkage is determined exactly
+ // as if it were declared with the storage-class specifier
+ // extern.
+ if (!Context.getLangOptions().CPlusPlus &&
+ (Function->getStorageClass() == FunctionDecl::Extern ||
+ Function->getStorageClass() == FunctionDecl::PrivateExtern ||
+ Function->getStorageClass() == FunctionDecl::None)) {
+ // C99 6.2.2p4:
+ // For an identifier declared with the storage-class specifier
+ // extern in a scope in which a prior declaration of that
+ // identifier is visible, if the prior declaration specifies
+ // internal or external linkage, the linkage of the identifier
+ // at the later declaration is the same as the linkage
+ // specified at the prior declaration. If no prior declaration
+ // is visible, or if the prior declaration specifies no
+ // linkage, then the identifier has external linkage.
+ if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) {
+ if (NamedDecl::Linkage L = PrevFunc->getLinkage())
+ return L;
+ }
+ }
+
+ return NamedDecl::ExternalLinkage;
+ }
+
+ // - a named class (Clause 9), or an unnamed class defined in a
+ // typedef declaration in which the class has the typedef name
+ // for linkage purposes (7.1.3); or
+ // - a named enumeration (7.2), or an unnamed enumeration
+ // defined in a typedef declaration in which the enumeration
+ // has the typedef name for linkage purposes (7.1.3); or
+ if (const TagDecl *Tag = dyn_cast<TagDecl>(D))
+ if (Tag->getDeclName() || Tag->getTypedefForAnonDecl())
+ return NamedDecl::ExternalLinkage;
+
+ // - an enumerator belonging to an enumeration with external linkage;
+ if (isa<EnumConstantDecl>(D))
+ if (cast<NamedDecl>(D->getDeclContext())->getLinkage()
+ == NamedDecl::ExternalLinkage)
+ return NamedDecl::ExternalLinkage;
+
+ // - a template, unless it is a function template that has
+ // internal linkage (Clause 14);
+ if (isa<TemplateDecl>(D))
+ return NamedDecl::ExternalLinkage;
+
+ // - a namespace (7.3), unless it is declared within an unnamed
+ // namespace.
+ if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace())
+ return NamedDecl::ExternalLinkage;
+
+ return NamedDecl::NoLinkage;
+}
+
+NamedDecl::Linkage NamedDecl::getLinkage() const {
+ // Handle linkage for namespace-scope names.
+ if (getDeclContext()->getLookupContext()->isFileContext())
+ if (Linkage L = getLinkageForNamespaceScopeDecl(this))
+ return L;
+
+ // C++ [basic.link]p5:
+ // In addition, a member function, static data member, a named
+ // class or enumeration of class scope, or an unnamed class or
+ // enumeration defined in a class-scope typedef declaration such
+ // that the class or enumeration has the typedef name for linkage
+ // purposes (7.1.3), has external linkage if the name of the class
+ // has external linkage.
+ if (getDeclContext()->isRecord() &&
+ (isa<CXXMethodDecl>(this) || isa<VarDecl>(this) ||
+ (isa<TagDecl>(this) &&
+ (getDeclName() || cast<TagDecl>(this)->getTypedefForAnonDecl()))) &&
+ cast<RecordDecl>(getDeclContext())->getLinkage() == ExternalLinkage)
+ return ExternalLinkage;
+
+ // C++ [basic.link]p6:
+ // The name of a function declared in block scope and the name of
+ // an object declared by a block scope extern declaration have
+ // linkage. If there is a visible declaration of an entity with
+ // linkage having the same name and type, ignoring entities
+ // declared outside the innermost enclosing namespace scope, the
+ // block scope declaration declares that same entity and receives
+ // the linkage of the previous declaration. If there is more than
+ // one such matching entity, the program is ill-formed. Otherwise,
+ // if no matching entity is found, the block scope entity receives
+ // external linkage.
+ if (getLexicalDeclContext()->isFunctionOrMethod()) {
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) {
+ if (Function->getPreviousDeclaration())
+ if (Linkage L = Function->getPreviousDeclaration()->getLinkage())
+ return L;
+
+ return ExternalLinkage;
+ }
+
+ if (const VarDecl *Var = dyn_cast<VarDecl>(this))
+ if (Var->getStorageClass() == VarDecl::Extern ||
+ Var->getStorageClass() == VarDecl::PrivateExtern) {
+ if (Var->getPreviousDeclaration())
+ if (Linkage L = Var->getPreviousDeclaration()->getLinkage())
+ return L;
+
+ return ExternalLinkage;
+ }
+ }
+
+ // C++ [basic.link]p6:
+ // Names not covered by these rules have no linkage.
+ return NoLinkage;
+}
+
std::string NamedDecl::getQualifiedNameAsString() const {
return getQualifiedNameAsString(getASTContext().getLangOptions());
}
@@ -300,13 +497,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
}
bool NamedDecl::hasLinkage() const {
- if (const VarDecl *VD = dyn_cast<VarDecl>(this))
- return VD->hasExternalStorage() || VD->isFileVarDecl();
-
- if (isa<FunctionDecl>(this) && !isa<CXXMethodDecl>(this))
- return true;
-
- return false;
+ return getLinkage() != NoLinkage;
}
NamedDecl *NamedDecl::getUnderlyingDecl() {
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 831f552..2dcd80b 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -55,8 +55,7 @@ const char *DeclContext::getDeclKindName() const {
}
bool Decl::CollectingStats(bool Enable) {
- if (Enable)
- StatSwitch = true;
+ if (Enable) StatSwitch = true;
return StatSwitch;
}
@@ -119,7 +118,7 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const {
OS << Message;
- if (NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl))
+ if (const NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl))
OS << " '" << DN->getQualifiedNameAsString() << '\'';
OS << '\n';
}
@@ -130,9 +129,6 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const {
// Out-of-line virtual method providing a home for Decl.
Decl::~Decl() {
- if (isOutOfSemaDC())
- delete getMultipleDC();
-
assert(!HasAttrs && "attributes should have been freed by Destroy");
}
@@ -148,7 +144,7 @@ void Decl::setLexicalDeclContext(DeclContext *DC) {
return;
if (isInSemaDC()) {
- MultipleDC *MDC = new MultipleDC();
+ MultipleDC *MDC = new (getASTContext()) MultipleDC();
MDC->SemanticDC = getDeclContext();
MDC->LexicalDC = DC;
DeclCtx = MDC;
@@ -343,9 +339,12 @@ void Decl::Destroy(ASTContext &C) {
N = Tmp;
}
+ if (isOutOfSemaDC())
+ delete (C) getMultipleDC();
+
this->~Decl();
C.Deallocate((void *)this);
-#endif
+#endif
}
Decl *Decl::castFromDeclContext (const DeclContext *D) {
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index a21c93f..4001988 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -36,8 +36,6 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
HasTrivialDestructor(true), ComputedVisibleConversions(false),
Bases(0), NumBases(0), VBases(0), NumVBases(0),
- Conversions(DC, DeclarationName()),
- VisibleConversions(DC, DeclarationName()),
TemplateOrInstantiation() { }
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
@@ -299,14 +297,11 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
void
CXXRecordDecl::collectConversionFunctions(
- llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet)
+ llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const
{
- OverloadedFunctionDecl *TopConversions = getConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator
- TFunc = TopConversions->function_begin(),
- TFuncEnd = TopConversions->function_end();
- TFunc != TFuncEnd; ++TFunc) {
- NamedDecl *TopConv = TFunc->get();
+ const UnresolvedSet *Cs = getConversionFunctions();
+ for (UnresolvedSet::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) {
+ NamedDecl *TopConv = *I;
CanQualType TConvType;
if (FunctionTemplateDecl *TConversionTemplate =
dyn_cast<FunctionTemplateDecl>(TopConv))
@@ -336,14 +331,11 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
bool inTopClass = (RD == this);
QualType ClassType = getASTContext().getTypeDeclType(this);
if (const RecordType *Record = ClassType->getAs<RecordType>()) {
- OverloadedFunctionDecl *Conversions
+ const UnresolvedSet *Cs
= cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator
- Func = Conversions->function_begin(),
- FuncEnd = Conversions->function_end();
- Func != FuncEnd; ++Func) {
- NamedDecl *Conv = Func->get();
+ for (UnresolvedSet::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) {
+ NamedDecl *Conv = *I;
// Only those conversions not exact match of conversions in current
// class are candidateconversion routines.
CanQualType ConvType;
@@ -405,8 +397,7 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
/// getVisibleConversionFunctions - get all conversion functions visible
/// in current class; including conversion function templates.
-OverloadedFunctionDecl *
-CXXRecordDecl::getVisibleConversionFunctions() {
+const UnresolvedSet *CXXRecordDecl::getVisibleConversionFunctions() {
// If root class, all conversions are visible.
if (bases_begin() == bases_end())
return &Conversions;
@@ -425,26 +416,26 @@ void CXXRecordDecl::addVisibleConversionFunction(
CXXConversionDecl *ConvDecl) {
assert(!ConvDecl->getDescribedFunctionTemplate() &&
"Conversion function templates should cast to FunctionTemplateDecl.");
- VisibleConversions.addOverload(ConvDecl);
+ VisibleConversions.addDecl(ConvDecl);
}
void CXXRecordDecl::addVisibleConversionFunction(
FunctionTemplateDecl *ConvDecl) {
assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
"Function template is not a conversion function template");
- VisibleConversions.addOverload(ConvDecl);
+ VisibleConversions.addDecl(ConvDecl);
}
void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) {
assert(!ConvDecl->getDescribedFunctionTemplate() &&
"Conversion function templates should cast to FunctionTemplateDecl.");
- Conversions.addOverload(ConvDecl);
+ Conversions.addDecl(ConvDecl);
}
void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
"Function template is not a conversion function template");
- Conversions.addOverload(ConvDecl);
+ Conversions.addDecl(ConvDecl);
}
CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
@@ -895,12 +886,21 @@ UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
SourceRange QualifierRange,
NestedNameSpecifier *Qualifier,
SourceLocation IdentLoc,
- NamespaceDecl *Used,
+ NamedDecl *Used,
DeclContext *CommonAncestor) {
+ if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Used))
+ Used = NS->getOriginalNamespace();
return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierRange,
Qualifier, IdentLoc, Used, CommonAncestor);
}
+NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() {
+ if (NamespaceAliasDecl *NA =
+ dyn_cast_or_null<NamespaceAliasDecl>(NominatedNamespace))
+ return NA->getNamespace();
+ return cast_or_null<NamespaceDecl>(NominatedNamespace);
+}
+
NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
SourceLocation AliasLoc,
@@ -909,6 +909,8 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
NestedNameSpecifier *Qualifier,
SourceLocation IdentLoc,
NamedDecl *Namespace) {
+ if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Namespace))
+ Namespace = NS->getOriginalNamespace();
return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange,
Qualifier, IdentLoc, Namespace);
}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 131de8b..a5982cf 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -18,19 +18,18 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/PrettyPrinter.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace {
- class VISIBILITY_HIDDEN DeclPrinter : public DeclVisitor<DeclPrinter> {
+ class DeclPrinter : public DeclVisitor<DeclPrinter> {
llvm::raw_ostream &Out;
ASTContext &Context;
PrintingPolicy Policy;
unsigned Indentation;
- llvm::raw_ostream& Indent();
+ llvm::raw_ostream& Indent() { return Indent(Indentation); }
+ llvm::raw_ostream& Indent(unsigned Indentation);
void ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls);
void Print(AccessSpecifier AS);
@@ -154,8 +153,8 @@ void Decl::dump() const {
print(llvm::errs());
}
-llvm::raw_ostream& DeclPrinter::Indent() {
- for (unsigned i = 0; i < Indentation; ++i)
+llvm::raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
+ for (unsigned i = 0; i != Indentation; ++i)
Out << " ";
return Out;
}
@@ -205,6 +204,8 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
AccessSpecifier AS = D->getAccess();
if (AS != CurAS) {
+ if (Indent)
+ this->Indent(Indentation - Policy.Indentation);
Print(AS);
Out << ":\n";
CurAS = AS;
@@ -502,7 +503,7 @@ void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
Out << "using namespace ";
if (D->getQualifier())
D->getQualifier()->print(Out, Policy);
- Out << D->getNominatedNamespace()->getNameAsString();
+ Out << D->getNominatedNamespaceAsWritten()->getNameAsString();
}
void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 0c14714..902339e 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -214,9 +214,7 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) {
} else if (NonTypeTemplateParmDecl *NTTP =
dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(),
- NTTP->getLocation(),
- NTTP->getType()->isDependentType(),
- /*Value-dependent=*/true);
+ NTTP->getLocation());
TemplateArgs.push_back(TemplateArgument(E));
} else {
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
@@ -453,8 +451,9 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgumentListBuilder &Builder,
- TemplateArgumentLoc *ArgInfos, unsigned N,
+ const TemplateArgumentListInfo &ArgInfos,
ClassTemplatePartialSpecializationDecl *PrevDecl) {
+ unsigned N = ArgInfos.size();
TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N];
for (unsigned I = 0; I != N; ++I)
ClonedArgs[I] = ArgInfos[I];
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 1ff068c..3471657 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -50,6 +50,17 @@ public:
void *FETokenInfo;
};
+/// CXXLiberalOperatorName - Contains the actual identifier that makes up the
+/// name.
+///
+/// This identifier is stored here rather than directly in DeclarationName so as
+/// to allow Objective-C selectors, which are about a million times more common,
+/// to consume minimal memory.
+class CXXLiteralOperatorIdName : public DeclarationNameExtra {
+public:
+ IdentifierInfo *ID;
+};
+
bool operator<(DeclarationName LHS, DeclarationName RHS) {
if (LHS.getNameKind() != RHS.getNameKind())
return LHS.getNameKind() < RHS.getNameKind();
@@ -89,6 +100,10 @@ bool operator<(DeclarationName LHS, DeclarationName RHS) {
case DeclarationName::CXXOperatorName:
return LHS.getCXXOverloadedOperator() < RHS.getCXXOverloadedOperator();
+
+ case DeclarationName::CXXLiteralOperatorName:
+ return LHS.getCXXLiteralIdentifier()->getName() <
+ RHS.getCXXLiteralIdentifier()->getName();
case DeclarationName::CXXUsingDirective:
return false;
@@ -143,6 +158,9 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
case DeclarationNameExtra::CXXConversionFunction:
return CXXConversionFunctionName;
+ case DeclarationNameExtra::CXXLiteralOperator:
+ return CXXLiteralOperatorName;
+
case DeclarationNameExtra::CXXUsingDirective:
return CXXUsingDirective;
@@ -208,6 +226,10 @@ std::string DeclarationName::getAsString() const {
return Result;
}
+ case CXXLiteralOperatorName: {
+ return "operator \"\" " + std::string(getCXXLiteralIdentifier()->getName());
+ }
+
case CXXConversionFunctionName: {
std::string Result = "operator ";
QualType Type = getCXXNameType();
@@ -242,6 +264,13 @@ OverloadedOperatorKind DeclarationName::getCXXOverloadedOperator() const {
}
}
+IdentifierInfo *DeclarationName::getCXXLiteralIdentifier() const {
+ if (CXXLiteralOperatorIdName *CXXLit = getAsCXXLiteralOperatorIdName())
+ return CXXLit->ID;
+ else
+ return 0;
+}
+
Selector DeclarationName::getObjCSelector() const {
switch (getNameKind()) {
case ObjCZeroArgSelector:
@@ -273,6 +302,9 @@ void *DeclarationName::getFETokenInfoAsVoid() const {
case CXXOperatorName:
return getAsCXXOperatorIdName()->FETokenInfo;
+ case CXXLiteralOperatorName:
+ return getCXXLiteralIdentifier()->getFETokenInfo<void>();
+
default:
assert(false && "Declaration name has no FETokenInfo");
}
@@ -295,6 +327,10 @@ void DeclarationName::setFETokenInfo(void *T) {
getAsCXXOperatorIdName()->FETokenInfo = T;
break;
+ case CXXLiteralOperatorName:
+ getCXXLiteralIdentifier()->setFETokenInfo(T);
+ break;
+
default:
assert(false && "Declaration name has no FETokenInfo");
}
@@ -390,6 +426,14 @@ DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) {
return DeclarationName(&CXXOperatorNames[(unsigned)Op]);
}
+DeclarationName
+DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) {
+ CXXLiteralOperatorIdName *LiteralName = new CXXLiteralOperatorIdName;
+ LiteralName->ExtraKindOrNumArgs = DeclarationNameExtra::CXXLiteralOperator;
+ LiteralName->ID = II;
+ return DeclarationName(LiteralName);
+}
+
unsigned
llvm::DenseMapInfo<clang::DeclarationName>::
getHashValue(clang::DeclarationName N) {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 90b50c6..624a620 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -31,49 +31,104 @@ using namespace clang;
// Primary Expressions.
//===----------------------------------------------------------------------===//
+void ExplicitTemplateArgumentList::initializeFrom(
+ const TemplateArgumentListInfo &Info) {
+ LAngleLoc = Info.getLAngleLoc();
+ RAngleLoc = Info.getRAngleLoc();
+ NumTemplateArgs = Info.size();
+
+ TemplateArgumentLoc *ArgBuffer = getTemplateArgs();
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
+}
+
+void ExplicitTemplateArgumentList::copyInto(
+ TemplateArgumentListInfo &Info) const {
+ Info.setLAngleLoc(LAngleLoc);
+ Info.setRAngleLoc(RAngleLoc);
+ for (unsigned I = 0; I != NumTemplateArgs; ++I)
+ Info.addArgument(getTemplateArgs()[I]);
+}
+
+std::size_t ExplicitTemplateArgumentList::sizeFor(
+ const TemplateArgumentListInfo &Info) {
+ return sizeof(ExplicitTemplateArgumentList) +
+ sizeof(TemplateArgumentLoc) * Info.size();
+}
+
+void DeclRefExpr::computeDependence() {
+ TypeDependent = false;
+ ValueDependent = false;
+
+ NamedDecl *D = getDecl();
+
+ // (TD) C++ [temp.dep.expr]p3:
+ // An id-expression is type-dependent if it contains:
+ //
+ // and
+ //
+ // (VD) C++ [temp.dep.constexpr]p2:
+ // An identifier is value-dependent if it is:
+
+ // (TD) - an identifier that was declared with dependent type
+ // (VD) - a name declared with a dependent type,
+ if (getType()->isDependentType()) {
+ TypeDependent = true;
+ ValueDependent = true;
+ }
+ // (TD) - a conversion-function-id that specifies a dependent type
+ else if (D->getDeclName().getNameKind()
+ == DeclarationName::CXXConversionFunctionName &&
+ D->getDeclName().getCXXNameType()->isDependentType()) {
+ TypeDependent = true;
+ ValueDependent = true;
+ }
+ // (TD) - a template-id that is dependent,
+ else if (hasExplicitTemplateArgumentList() &&
+ TemplateSpecializationType::anyDependentTemplateArguments(
+ getTemplateArgs(),
+ getNumTemplateArgs())) {
+ TypeDependent = true;
+ ValueDependent = true;
+ }
+ // (VD) - the name of a non-type template parameter,
+ else if (isa<NonTypeTemplateParmDecl>(D))
+ ValueDependent = true;
+ // (VD) - a constant with integral or enumeration type and is
+ // initialized with an expression that is value-dependent.
+ else if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ if (Var->getType()->isIntegralType() &&
+ Var->getType().getCVRQualifiers() == Qualifiers::Const &&
+ Var->getInit() &&
+ Var->getInit()->isValueDependent())
+ ValueDependent = true;
+ }
+ // (TD) - a nested-name-specifier or a qualified-id that names a
+ // member of an unknown specialization.
+ // (handled by DependentScopeDeclRefExpr)
+}
+
DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
NamedDecl *D, SourceLocation NameLoc,
- bool HasExplicitTemplateArgumentList,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
- SourceLocation RAngleLoc,
- QualType T, bool TD, bool VD)
- : Expr(DeclRefExprClass, T, TD, VD),
+ const TemplateArgumentListInfo *TemplateArgs,
+ QualType T)
+ : Expr(DeclRefExprClass, T, false, false),
DecoratedD(D,
(Qualifier? HasQualifierFlag : 0) |
- (HasExplicitTemplateArgumentList?
- HasExplicitTemplateArgumentListFlag : 0)),
+ (TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)),
Loc(NameLoc) {
+ assert(!isa<OverloadedFunctionDecl>(D));
if (Qualifier) {
NameQualifier *NQ = getNameQualifier();
NQ->NNS = Qualifier;
NQ->Range = QualifierRange;
}
- if (HasExplicitTemplateArgumentList) {
- ExplicitTemplateArgumentList *ETemplateArgs
- = getExplicitTemplateArgumentList();
- ETemplateArgs->LAngleLoc = LAngleLoc;
- ETemplateArgs->RAngleLoc = RAngleLoc;
- ETemplateArgs->NumTemplateArgs = NumExplicitTemplateArgs;
-
- TemplateArgumentLoc *TemplateArgs = ETemplateArgs->getTemplateArgs();
- for (unsigned I = 0; I < NumExplicitTemplateArgs; ++I)
- new (TemplateArgs + I) TemplateArgumentLoc(ExplicitTemplateArgs[I]);
- }
-}
+ if (TemplateArgs)
+ getExplicitTemplateArgumentList()->initializeFrom(*TemplateArgs);
-DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- NamedDecl *D,
- SourceLocation NameLoc,
- QualType T, bool TD, bool VD) {
- return Create(Context, Qualifier, QualifierRange, D, NameLoc,
- false, SourceLocation(), 0, 0, SourceLocation(),
- T, TD, VD);
+ computeDependence();
}
DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
@@ -81,28 +136,18 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
SourceRange QualifierRange,
NamedDecl *D,
SourceLocation NameLoc,
- bool HasExplicitTemplateArgumentList,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
- SourceLocation RAngleLoc,
- QualType T, bool TD, bool VD) {
+ QualType T,
+ const TemplateArgumentListInfo *TemplateArgs) {
std::size_t Size = sizeof(DeclRefExpr);
if (Qualifier != 0)
Size += sizeof(NameQualifier);
- if (HasExplicitTemplateArgumentList)
- Size += sizeof(ExplicitTemplateArgumentList) +
- sizeof(TemplateArgumentLoc) * NumExplicitTemplateArgs;
+ if (TemplateArgs)
+ Size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
void *Mem = Context.Allocate(Size, llvm::alignof<DeclRefExpr>());
return new (Mem) DeclRefExpr(Qualifier, QualifierRange, D, NameLoc,
- HasExplicitTemplateArgumentList,
- LAngleLoc,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
- RAngleLoc,
- T, TD, VD);
+ TemplateArgs, T);
}
SourceRange DeclRefExpr::getSourceRange() const {
@@ -427,15 +472,13 @@ QualType CallExpr::getCallReturnType() const {
MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
SourceRange qualrange, NamedDecl *memberdecl,
- SourceLocation l, bool has_explicit,
- SourceLocation langle,
- const TemplateArgumentLoc *targs, unsigned numtargs,
- SourceLocation rangle, QualType ty)
+ SourceLocation l, const TemplateArgumentListInfo *targs,
+ QualType ty)
: Expr(MemberExprClass, ty,
base->isTypeDependent() || (qual && qual->isDependent()),
base->isValueDependent() || (qual && qual->isDependent())),
Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow),
- HasQualifier(qual != 0), HasExplicitTemplateArgumentList(has_explicit) {
+ HasQualifier(qual != 0), HasExplicitTemplateArgumentList(targs) {
// Initialize the qualifier, if any.
if (HasQualifier) {
NameQualifier *NQ = getMemberQualifier();
@@ -444,17 +487,8 @@ MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
}
// Initialize the explicit template argument list, if any.
- if (HasExplicitTemplateArgumentList) {
- ExplicitTemplateArgumentList *ETemplateArgs
- = getExplicitTemplateArgumentList();
- ETemplateArgs->LAngleLoc = langle;
- ETemplateArgs->RAngleLoc = rangle;
- ETemplateArgs->NumTemplateArgs = numtargs;
-
- TemplateArgumentLoc *TemplateArgs = ETemplateArgs->getTemplateArgs();
- for (unsigned I = 0; I < numtargs; ++I)
- new (TemplateArgs + I) TemplateArgumentLoc(targs[I]);
- }
+ if (targs)
+ getExplicitTemplateArgumentList()->initializeFrom(*targs);
}
MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
@@ -462,24 +496,18 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
SourceRange qualrange,
NamedDecl *memberdecl,
SourceLocation l,
- bool has_explicit,
- SourceLocation langle,
- const TemplateArgumentLoc *targs,
- unsigned numtargs,
- SourceLocation rangle,
+ const TemplateArgumentListInfo *targs,
QualType ty) {
std::size_t Size = sizeof(MemberExpr);
if (qual != 0)
Size += sizeof(NameQualifier);
- if (has_explicit)
- Size += sizeof(ExplicitTemplateArgumentList) +
- sizeof(TemplateArgumentLoc) * numtargs;
+ if (targs)
+ Size += ExplicitTemplateArgumentList::sizeFor(*targs);
void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>());
return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l,
- has_explicit, langle, targs, numtargs, rangle,
- ty);
+ targs, ty);
}
const char *CastExpr::getCastKindName() const {
@@ -528,6 +556,8 @@ const char *CastExpr::getCastKindName() const {
return "FloatingToIntegral";
case CastExpr::CK_FloatingCast:
return "FloatingCast";
+ case CastExpr::CK_MemberPointerToBoolean:
+ return "MemberPointerToBoolean";
}
assert(0 && "Unhandled cast kind!");
@@ -640,12 +670,17 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
InitListExpr::InitListExpr(SourceLocation lbraceloc,
Expr **initExprs, unsigned numInits,
SourceLocation rbraceloc)
- : Expr(InitListExprClass, QualType(),
- hasAnyTypeDependentArguments(initExprs, numInits),
- hasAnyValueDependentArguments(initExprs, numInits)),
+ : Expr(InitListExprClass, QualType(), false, false),
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0),
- UnionFieldInit(0), HadArrayRangeDesignator(false) {
-
+ UnionFieldInit(0), HadArrayRangeDesignator(false)
+{
+ for (unsigned I = 0; I != numInits; ++I) {
+ if (initExprs[I]->isTypeDependent())
+ TypeDependent = true;
+ if (initExprs[I]->isValueDependent())
+ ValueDependent = true;
+ }
+
InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits);
}
@@ -1091,10 +1126,10 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
return LV_Valid;
case PredefinedExprClass:
return LV_Valid;
+ case UnresolvedLookupExprClass:
+ return LV_Valid;
case CXXDefaultArgExprClass:
return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue(Ctx);
- case CXXConditionDeclExprClass:
- return LV_Valid;
case CStyleCastExprClass:
case CXXFunctionalCastExprClass:
case CXXStaticCastExprClass:
@@ -1141,18 +1176,6 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
return LV_Valid;
}
- case TemplateIdRefExprClass: {
- const TemplateIdRefExpr *TID = cast<TemplateIdRefExpr>(this);
- TemplateName Template = TID->getTemplateName();
- NamedDecl *ND = Template.getAsTemplateDecl();
- if (!ND)
- ND = Template.getAsOverloadedFunctionDecl();
- if (ND && DeclCanBeLvalue(ND, Ctx))
- return LV_Valid;
-
- break;
- }
-
default:
break;
}
@@ -1491,19 +1514,18 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::CXXNullPtrLiteralExprClass:
case Expr::CXXThisExprClass:
case Expr::CXXThrowExprClass:
- case Expr::CXXConditionDeclExprClass: // FIXME: is this correct?
case Expr::CXXNewExprClass:
case Expr::CXXDeleteExprClass:
case Expr::CXXPseudoDestructorExprClass:
- case Expr::UnresolvedFunctionNameExprClass:
- case Expr::UnresolvedDeclRefExprClass:
- case Expr::TemplateIdRefExprClass:
+ case Expr::UnresolvedLookupExprClass:
+ case Expr::DependentScopeDeclRefExprClass:
case Expr::CXXConstructExprClass:
case Expr::CXXBindTemporaryExprClass:
case Expr::CXXExprWithTemporariesClass:
case Expr::CXXTemporaryObjectExprClass:
case Expr::CXXUnresolvedConstructExprClass:
- case Expr::CXXUnresolvedMemberExprClass:
+ case Expr::CXXDependentScopeMemberExprClass:
+ case Expr::UnresolvedMemberExprClass:
case Expr::ObjCStringLiteralClass:
case Expr::ObjCEncodeExprClass:
case Expr::ObjCMessageExprClass:
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 0ba4608..d1a0390 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -72,14 +72,6 @@ Stmt::child_iterator CXXZeroInitValueExpr::child_end() {
return child_iterator();
}
-// CXXConditionDeclExpr
-Stmt::child_iterator CXXConditionDeclExpr::child_begin() {
- return getVarDecl();
-}
-Stmt::child_iterator CXXConditionDeclExpr::child_end() {
- return child_iterator();
-}
-
// CXXNewExpr
CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew,
Expr **placementArgs, unsigned numPlaceArgs,
@@ -121,11 +113,45 @@ Stmt::child_iterator CXXPseudoDestructorExpr::child_end() {
return &Base + 1;
}
-// UnresolvedFunctionNameExpr
-Stmt::child_iterator UnresolvedFunctionNameExpr::child_begin() {
+// UnresolvedLookupExpr
+UnresolvedLookupExpr *
+UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange, DeclarationName Name,
+ SourceLocation NameLoc, bool ADL,
+ const TemplateArgumentListInfo &Args)
+{
+ void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) +
+ ExplicitTemplateArgumentList::sizeFor(Args));
+ UnresolvedLookupExpr *ULE
+ = new (Mem) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy,
+ Dependent, Qualifier, QualifierRange,
+ Name, NameLoc, ADL,
+ /*Overload*/ true,
+ /*ExplicitTemplateArgs*/ true);
+
+ reinterpret_cast<ExplicitTemplateArgumentList*>(ULE+1)->initializeFrom(Args);
+
+ return ULE;
+}
+
+bool UnresolvedLookupExpr::ComputeDependence(NamedDecl * const *Begin,
+ NamedDecl * const *End,
+ const TemplateArgumentListInfo *Args) {
+ for (NamedDecl * const *I = Begin; I != End; ++I)
+ if ((*I)->getDeclContext()->isDependentContext())
+ return true;
+
+ if (Args && TemplateSpecializationType::anyDependentTemplateArguments(*Args))
+ return true;
+
+ return false;
+}
+
+Stmt::child_iterator UnresolvedLookupExpr::child_begin() {
return child_iterator();
}
-Stmt::child_iterator UnresolvedFunctionNameExpr::child_end() {
+Stmt::child_iterator UnresolvedLookupExpr::child_end() {
return child_iterator();
}
// UnaryTypeTraitExpr
@@ -136,72 +162,37 @@ Stmt::child_iterator UnaryTypeTraitExpr::child_end() {
return child_iterator();
}
-// UnresolvedDeclRefExpr
-StmtIterator UnresolvedDeclRefExpr::child_begin() {
- return child_iterator();
+// DependentScopeDeclRefExpr
+DependentScopeDeclRefExpr *
+DependentScopeDeclRefExpr::Create(ASTContext &C,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ DeclarationName Name,
+ SourceLocation NameLoc,
+ const TemplateArgumentListInfo *Args) {
+ std::size_t size = sizeof(DependentScopeDeclRefExpr);
+ if (Args) size += ExplicitTemplateArgumentList::sizeFor(*Args);
+ void *Mem = C.Allocate(size);
+
+ DependentScopeDeclRefExpr *DRE
+ = new (Mem) DependentScopeDeclRefExpr(C.DependentTy,
+ Qualifier, QualifierRange,
+ Name, NameLoc,
+ Args != 0);
+
+ if (Args)
+ reinterpret_cast<ExplicitTemplateArgumentList*>(DRE+1)
+ ->initializeFrom(*Args);
+
+ return DRE;
}
-StmtIterator UnresolvedDeclRefExpr::child_end() {
+StmtIterator DependentScopeDeclRefExpr::child_begin() {
return child_iterator();
}
-TemplateIdRefExpr::TemplateIdRefExpr(QualType T,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- TemplateName Template,
- SourceLocation TemplateNameLoc,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation RAngleLoc)
- : Expr(TemplateIdRefExprClass, T,
- (Template.isDependent() ||
- TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs, NumTemplateArgs)),
- (Template.isDependent() ||
- TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs, NumTemplateArgs))),
- Qualifier(Qualifier), QualifierRange(QualifierRange), Template(Template),
- TemplateNameLoc(TemplateNameLoc), LAngleLoc(LAngleLoc),
- RAngleLoc(RAngleLoc), NumTemplateArgs(NumTemplateArgs) {
- TemplateArgumentLoc *StoredTemplateArgs
- = reinterpret_cast<TemplateArgumentLoc *> (this+1);
- for (unsigned I = 0; I != NumTemplateArgs; ++I)
- new (StoredTemplateArgs + I) TemplateArgumentLoc(TemplateArgs[I]);
-}
-
-TemplateIdRefExpr *
-TemplateIdRefExpr::Create(ASTContext &Context, QualType T,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- TemplateName Template, SourceLocation TemplateNameLoc,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs, SourceLocation RAngleLoc) {
- void *Mem = Context.Allocate(sizeof(TemplateIdRefExpr) +
- sizeof(TemplateArgumentLoc) * NumTemplateArgs);
- return new (Mem) TemplateIdRefExpr(T, Qualifier, QualifierRange, Template,
- TemplateNameLoc, LAngleLoc, TemplateArgs,
- NumTemplateArgs, RAngleLoc);
-}
-
-void TemplateIdRefExpr::DoDestroy(ASTContext &Context) {
- const TemplateArgumentLoc *TemplateArgs = getTemplateArgs();
- for (unsigned I = 0; I != NumTemplateArgs; ++I)
- if (Expr *E = TemplateArgs[I].getArgument().getAsExpr())
- E->Destroy(Context);
- this->~TemplateIdRefExpr();
- Context.Deallocate(this);
-}
-
-Stmt::child_iterator TemplateIdRefExpr::child_begin() {
- // FIXME: Walk the expressions in the template arguments (?)
- return Stmt::child_iterator();
-}
-
-Stmt::child_iterator TemplateIdRefExpr::child_end() {
- // FIXME: Walk the expressions in the template arguments (?)
- return Stmt::child_iterator();
+StmtIterator DependentScopeDeclRefExpr::child_end() {
+ return child_iterator();
}
bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
@@ -526,7 +517,7 @@ Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() {
return child_iterator(reinterpret_cast<Stmt **>(this + 1) + NumArgs);
}
-CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C,
+CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
Expr *Base, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
@@ -534,33 +525,20 @@ CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C,
NamedDecl *FirstQualifierFoundInScope,
DeclarationName Member,
SourceLocation MemberLoc,
- bool HasExplicitTemplateArgs,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation RAngleLoc)
- : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true),
+ const TemplateArgumentListInfo *TemplateArgs)
+ : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true),
Base(Base), IsArrow(IsArrow),
- HasExplicitTemplateArgumentList(HasExplicitTemplateArgs),
+ HasExplicitTemplateArgumentList(TemplateArgs),
OperatorLoc(OperatorLoc),
Qualifier(Qualifier), QualifierRange(QualifierRange),
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
Member(Member), MemberLoc(MemberLoc) {
- if (HasExplicitTemplateArgumentList) {
- ExplicitTemplateArgumentList *ETemplateArgs
- = getExplicitTemplateArgumentList();
- ETemplateArgs->LAngleLoc = LAngleLoc;
- ETemplateArgs->RAngleLoc = RAngleLoc;
- ETemplateArgs->NumTemplateArgs = NumTemplateArgs;
-
- TemplateArgumentLoc *SavedTemplateArgs = ETemplateArgs->getTemplateArgs();
- for (unsigned I = 0; I < NumTemplateArgs; ++I)
- new (SavedTemplateArgs + I) TemplateArgumentLoc(TemplateArgs[I]);
- }
+ if (TemplateArgs)
+ getExplicitTemplateArgumentList()->initializeFrom(*TemplateArgs);
}
-CXXUnresolvedMemberExpr *
-CXXUnresolvedMemberExpr::Create(ASTContext &C,
+CXXDependentScopeMemberExpr *
+CXXDependentScopeMemberExpr::Create(ASTContext &C,
Expr *Base, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
@@ -568,37 +546,79 @@ CXXUnresolvedMemberExpr::Create(ASTContext &C,
NamedDecl *FirstQualifierFoundInScope,
DeclarationName Member,
SourceLocation MemberLoc,
- bool HasExplicitTemplateArgs,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation RAngleLoc) {
- if (!HasExplicitTemplateArgs)
- return new (C) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ if (!TemplateArgs)
+ return new (C) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc,
Qualifier, QualifierRange,
FirstQualifierFoundInScope,
Member, MemberLoc);
- void *Mem = C.Allocate(sizeof(CXXUnresolvedMemberExpr) +
- sizeof(ExplicitTemplateArgumentList) +
- sizeof(TemplateArgumentLoc) * NumTemplateArgs,
- llvm::alignof<CXXUnresolvedMemberExpr>());
- return new (Mem) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc,
+ 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,
- HasExplicitTemplateArgs,
- LAngleLoc,
- TemplateArgs,
- NumTemplateArgs,
- RAngleLoc);
+ TemplateArgs);
+}
+
+Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() {
+ return child_iterator(&Base);
}
-Stmt::child_iterator CXXUnresolvedMemberExpr::child_begin() {
+Stmt::child_iterator CXXDependentScopeMemberExpr::child_end() {
+ return child_iterator(&Base + 1);
+}
+
+UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent,
+ bool HasUnresolvedUsing,
+ Expr *Base, bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ DeclarationName MemberName,
+ SourceLocation MemberLoc,
+ const TemplateArgumentListInfo *TemplateArgs)
+ : Expr(UnresolvedMemberExprClass, T, Dependent, Dependent),
+ Base(Base), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing),
+ HasExplicitTemplateArgs(TemplateArgs != 0),
+ OperatorLoc(OperatorLoc),
+ Qualifier(Qualifier), QualifierRange(QualifierRange),
+ MemberName(MemberName), MemberLoc(MemberLoc) {
+ if (TemplateArgs)
+ getExplicitTemplateArgs()->initializeFrom(*TemplateArgs);
+}
+
+UnresolvedMemberExpr *
+UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent,
+ bool HasUnresolvedUsing,
+ Expr *Base, bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ DeclarationName Member,
+ SourceLocation MemberLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ std::size_t size = sizeof(UnresolvedMemberExpr);
+ if (TemplateArgs)
+ size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
+
+ void *Mem = C.Allocate(size, llvm::alignof<UnresolvedMemberExpr>());
+ return new (Mem) UnresolvedMemberExpr(
+ Dependent ? C.DependentTy : C.OverloadTy,
+ Dependent, HasUnresolvedUsing, Base, IsArrow,
+ OperatorLoc, Qualifier, QualifierRange,
+ Member, MemberLoc, TemplateArgs);
+}
+
+Stmt::child_iterator UnresolvedMemberExpr::child_begin() {
return child_iterator(&Base);
}
-Stmt::child_iterator CXXUnresolvedMemberExpr::child_end() {
+Stmt::child_iterator UnresolvedMemberExpr::child_end() {
return child_iterator(&Base + 1);
}
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 2689859..a20e1cc 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -19,7 +19,6 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/Compiler.h"
#include <cstring>
using namespace clang;
@@ -153,7 +152,7 @@ static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType,
}
namespace {
-class VISIBILITY_HIDDEN HasSideEffect
+class HasSideEffect
: public StmtVisitor<HasSideEffect, bool> {
EvalInfo &Info;
public:
@@ -210,7 +209,7 @@ public:
// LValue Evaluation
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN LValueExprEvaluator
+class LValueExprEvaluator
: public StmtVisitor<LValueExprEvaluator, APValue> {
EvalInfo &Info;
public:
@@ -353,7 +352,7 @@ APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN PointerExprEvaluator
+class PointerExprEvaluator
: public StmtVisitor<PointerExprEvaluator, APValue> {
EvalInfo &Info;
public:
@@ -508,7 +507,7 @@ APValue PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
- class VISIBILITY_HIDDEN VectorExprEvaluator
+ class VectorExprEvaluator
: public StmtVisitor<VectorExprEvaluator, APValue> {
EvalInfo &Info;
APValue GetZeroVector(QualType VecType);
@@ -702,7 +701,7 @@ APValue VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN IntExprEvaluator
+class IntExprEvaluator
: public StmtVisitor<IntExprEvaluator, bool> {
EvalInfo &Info;
APValue &Result;
@@ -776,7 +775,20 @@ public:
T1.getUnqualifiedType()),
E);
}
- bool VisitDeclRefExpr(const DeclRefExpr *E);
+
+ bool CheckReferencedDecl(const Expr *E, const Decl *D);
+ bool VisitDeclRefExpr(const DeclRefExpr *E) {
+ return CheckReferencedDecl(E, E->getDecl());
+ }
+ bool VisitMemberExpr(const MemberExpr *E) {
+ if (CheckReferencedDecl(E, E->getMemberDecl())) {
+ // Conservatively assume a MemberExpr will have side-effects
+ Info.EvalResult.HasSideEffects = true;
+ return true;
+ }
+ return false;
+ }
+
bool VisitCallExpr(const CallExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitUnaryOperator(const UnaryOperator *E);
@@ -834,12 +846,12 @@ static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) {
return true;
}
-bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
+bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
// Enums are integer constant exprs.
- if (const EnumConstantDecl *D = dyn_cast<EnumConstantDecl>(E->getDecl())) {
+ 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 = D->getInitVal();
+ 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.
@@ -851,15 +863,15 @@ bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
// In C, they can also be folded, although they are not ICEs.
if (Info.Ctx.getCanonicalType(E->getType()).getCVRQualifiers()
== Qualifiers::Const) {
- if (const VarDecl *D = dyn_cast<VarDecl>(E->getDecl())) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
const VarDecl *Def = 0;
- if (const Expr *Init = D->getDefinition(Def)) {
- if (APValue *V = D->getEvaluatedValue())
+ if (const Expr *Init = VD->getDefinition(Def)) {
+ if (APValue *V = VD->getEvaluatedValue())
return Success(V->getInt(), E);
if (Visit(const_cast<Expr*>(Init))) {
// Cache the evaluated value in the variable declaration.
- D->setEvaluatedValue(Info.Ctx, Result);
+ VD->setEvaluatedValue(Info.Ctx, Result);
return true;
}
@@ -1244,6 +1256,13 @@ bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
}
unsigned IntExprEvaluator::GetAlignOfType(QualType T) {
+ // C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
+ // the result is the size of the referenced type."
+ // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
+ // result shall be the alignment of the referenced type."
+ if (const ReferenceType *Ref = T->getAs<ReferenceType>())
+ T = Ref->getPointeeType();
+
// Get information about the alignment.
unsigned CharSize = Info.Ctx.Target.getCharWidth();
@@ -1257,10 +1276,11 @@ unsigned IntExprEvaluator::GetAlignOfExpr(const Expr *E) {
// alignof decl is always accepted, even if it doesn't make sense: we default
// to 1 in those cases.
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- return Info.Ctx.getDeclAlignInBytes(DRE->getDecl());
+ return Info.Ctx.getDeclAlignInBytes(DRE->getDecl(), /*RefAsPointee*/true);
if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
- return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl());
+ return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl(),
+ /*RefAsPointee*/true);
return GetAlignOfType(E->getType());
}
@@ -1280,6 +1300,12 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
}
QualType SrcTy = E->getTypeOfArgument();
+ // C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
+ // the result is the size of the referenced type."
+ // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
+ // result shall be the alignment of the referenced type."
+ if (const ReferenceType *Ref = SrcTy->getAs<ReferenceType>())
+ SrcTy = Ref->getPointeeType();
// sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
// extension.
@@ -1460,7 +1486,7 @@ bool IntExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN FloatExprEvaluator
+class FloatExprEvaluator
: public StmtVisitor<FloatExprEvaluator, bool> {
EvalInfo &Info;
APFloat &Result;
@@ -1652,7 +1678,7 @@ bool FloatExprEvaluator::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN ComplexExprEvaluator
+class ComplexExprEvaluator
: public StmtVisitor<ComplexExprEvaluator, APValue> {
EvalInfo &Info;
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index b9cfcfe..326a1dc 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -14,7 +14,6 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
#include <llvm/ADT/SmallSet.h>
#include <llvm/Support/MathExtras.h>
@@ -22,9 +21,9 @@
using namespace clang;
ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
- : Ctx(Ctx), Size(0), Alignment(8), Packed(false), MaxFieldAlignment(0),
- DataSize(0), IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8),
- PrimaryBase(0), PrimaryBaseWasVirtual(false) {}
+ : Ctx(Ctx), Size(0), Alignment(8), Packed(false), UnfilledBitsInLastByte(0),
+ MaxFieldAlignment(0), DataSize(0), IsUnion(false), NonVirtualSize(0),
+ NonVirtualAlignment(8) { }
/// LayoutVtable - Lay out the vtable and set PrimaryBase.
void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) {
@@ -34,7 +33,7 @@ void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) {
}
SelectPrimaryBase(RD);
- if (PrimaryBase == 0) {
+ if (!PrimaryBase.getBase()) {
int AS = 0;
UpdateAlignment(Ctx.Target.getPointerAlign(AS));
Size += Ctx.Target.getPointerWidth(AS);
@@ -52,7 +51,7 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
// Skip the PrimaryBase here, as it is laid down first.
- if (Base != PrimaryBase || PrimaryBaseWasVirtual)
+ if (Base != PrimaryBase.getBase() || PrimaryBase.isVirtual())
LayoutBaseNonVirtually(Base, false);
}
}
@@ -74,12 +73,13 @@ bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
}
void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+ const ASTRecordLayout::PrimaryBaseInfo &BaseInfo =
+ Ctx.getASTRecordLayout(RD).getPrimaryBaseInfo();
// If the record has a primary base class that is virtual, add it to the set
// of primary bases.
- if (Layout.getPrimaryBaseWasVirtual())
- IndirectPrimaryBases.insert(Layout.getPrimaryBase());
+ if (BaseInfo.isVirtual())
+ IndirectPrimaryBases.insert(BaseInfo.getBase());
// Now traverse all bases and find primary bases for them.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
@@ -107,7 +107,7 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD,
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
if (!i->isVirtual()) {
SelectPrimaryVBase(Base, FirstPrimary);
- if (PrimaryBase)
+ if (PrimaryBase.getBase())
return;
continue;
}
@@ -115,7 +115,7 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD,
if (FirstPrimary==0)
FirstPrimary = Base;
if (!IndirectPrimaryBases.count(Base)) {
- setPrimaryBase(Base, true);
+ setPrimaryBase(Base, /*IsVirtual=*/true);
return;
}
}
@@ -141,14 +141,17 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) {
// base class, if one exists.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
e = RD->bases_end(); i != e; ++i) {
- if (!i->isVirtual()) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (Base->isDynamicClass()) {
- // We found it.
- setPrimaryBase(Base, false);
- return;
- }
+ // Ignore virtual bases.
+ if (i->isVirtual())
+ continue;
+
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+
+ if (Base->isDynamicClass()) {
+ // We found it.
+ PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, /*IsVirtual=*/false);
+ return;
}
}
@@ -166,8 +169,8 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) {
// Otherwise if is the first nearly empty virtual base, if one exists,
// otherwise there is no primary base class.
- if (!PrimaryBase)
- setPrimaryBase(FirstPrimary, true);
+ if (!PrimaryBase.getBase())
+ setPrimaryBase(FirstPrimary, /*IsVirtual=*/true);
}
void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) {
@@ -232,9 +235,10 @@ void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *Class,
}
if (Base->getNumVBases()) {
- const ASTRecordLayout &L = Ctx.getASTRecordLayout(Base);
- const CXXRecordDecl *PB = L.getPrimaryBase();
- LayoutVirtualBases(Class, Base, PB, BaseOffset, mark, IndirectPrimary);
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Base);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBaseInfo().getBase();
+ LayoutVirtualBases(Class, Base, PrimaryBase, BaseOffset, mark,
+ IndirectPrimary);
}
}
}
@@ -448,17 +452,17 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
MaxFieldAlignment = PPA->getAlignment();
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- UpdateAlignment(AA->getAlignment());
+ UpdateAlignment(AA->getMaxAlignment());
// If this is a C++ class, lay out the vtable and the non-virtual bases.
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D);
if (RD) {
LayoutVtable(RD);
// PrimaryBase goes first.
- if (PrimaryBase) {
- if (PrimaryBaseWasVirtual)
- IndirectPrimaryBases.insert(PrimaryBase);
- LayoutBaseNonVirtually(PrimaryBase, PrimaryBaseWasVirtual);
+ if (PrimaryBase.getBase()) {
+ if (PrimaryBase.isVirtual())
+ IndirectPrimaryBases.insert(PrimaryBase.getBase());
+ LayoutBaseNonVirtually(PrimaryBase.getBase(), PrimaryBase.isVirtual());
}
LayoutNonVirtualBases(RD);
}
@@ -470,7 +474,8 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
if (RD) {
llvm::SmallSet<const CXXRecordDecl*, 32> mark;
- LayoutVirtualBases(RD, RD, PrimaryBase, 0, mark, IndirectPrimaryBases);
+ LayoutVirtualBases(RD, RD, PrimaryBase.getBase(),
+ 0, mark, IndirectPrimaryBases);
}
// Finally, round the size of the total struct up to the alignment of the
@@ -498,7 +503,7 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
MaxFieldAlignment = PPA->getAlignment();
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- UpdateAlignment(AA->getAlignment());
+ UpdateAlignment(AA->getMaxAlignment());
// Layout each ivar sequentially.
llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
@@ -519,84 +524,111 @@ void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
LayoutField(*Field);
}
+void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
+ bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
+ uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte);
+ uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Ctx).getZExtValue();
+
+ std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
+ uint64_t TypeSize = FieldInfo.first;
+ unsigned FieldAlign = FieldInfo.second;
+
+ if (FieldPacked)
+ FieldAlign = 1;
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ FieldAlign = std::max(FieldAlign, AA->getMaxAlignment());
+
+ // The maximum field alignment overrides the aligned attribute.
+ if (MaxFieldAlignment)
+ FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+
+ // Check if we need to add padding to give the field the correct
+ // alignment.
+ if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
+ FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
+
+ // Padding members don't affect overall alignment
+ if (!D->getIdentifier())
+ FieldAlign = 1;
+
+ // Place this field at the current location.
+ FieldOffsets.push_back(FieldOffset);
+
+ // Update DataSize to include the last byte containing (part of) the bitfield.
+ if (IsUnion) {
+ // FIXME: I think FieldSize should be TypeSize here.
+ DataSize = std::max(DataSize, FieldSize);
+ } else {
+ uint64_t NewSizeInBits = FieldOffset + FieldSize;
+
+ DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8);
+ UnfilledBitsInLastByte = DataSize - NewSizeInBits;
+ }
+
+ // Update the size.
+ Size = std::max(Size, DataSize);
+
+ // Remember max struct/class alignment.
+ UpdateAlignment(FieldAlign);
+}
+
void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
- bool FieldPacked = Packed;
+ if (D->isBitField()) {
+ LayoutBitField(D);
+ return;
+ }
+
+ // Reset the unfilled bits.
+ UnfilledBitsInLastByte = 0;
+
+ bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
uint64_t FieldOffset = IsUnion ? 0 : DataSize;
uint64_t FieldSize;
unsigned FieldAlign;
-
- FieldPacked |= D->hasAttr<PackedAttr>();
-
- if (const Expr *BitWidthExpr = D->getBitWidth()) {
- // TODO: Need to check this algorithm on other targets!
- // (tested on Linux-X86)
- FieldSize = BitWidthExpr->EvaluateAsInt(Ctx).getZExtValue();
-
+
+ if (D->getType()->isIncompleteArrayType()) {
+ // This is a flexible array member; we can't directly
+ // query getTypeInfo about these, so we figure it out here.
+ // Flexible array members don't have any size, but they
+ // have to be aligned appropriately for their element type.
+ FieldSize = 0;
+ const ArrayType* ATy = Ctx.getAsArrayType(D->getType());
+ FieldAlign = Ctx.getTypeAlign(ATy->getElementType());
+ } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
+ unsigned AS = RT->getPointeeType().getAddressSpace();
+ FieldSize = Ctx.Target.getPointerWidth(AS);
+ FieldAlign = Ctx.Target.getPointerAlign(AS);
+ } else {
std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
- uint64_t TypeSize = FieldInfo.first;
-
+ FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
+ }
- if (FieldPacked)
- FieldAlign = 1;
- if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- FieldAlign = std::max(FieldAlign, AA->getAlignment());
- // The maximum field alignment overrides the aligned attribute.
- if (MaxFieldAlignment)
- FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
-
- // Check if we need to add padding to give the field the correct
- // alignment.
- if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
- FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
-
- // Padding members don't affect overall alignment
- if (!D->getIdentifier())
- FieldAlign = 1;
- } else {
- if (D->getType()->isIncompleteArrayType()) {
- // This is a flexible array member; we can't directly
- // query getTypeInfo about these, so we figure it out here.
- // Flexible array members don't have any size, but they
- // have to be aligned appropriately for their element type.
- FieldSize = 0;
- const ArrayType* ATy = Ctx.getAsArrayType(D->getType());
- FieldAlign = Ctx.getTypeAlign(ATy->getElementType());
- } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
- unsigned AS = RT->getPointeeType().getAddressSpace();
- FieldSize = Ctx.Target.getPointerWidth(AS);
- FieldAlign = Ctx.Target.getPointerAlign(AS);
- } else {
- std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
- FieldSize = FieldInfo.first;
- FieldAlign = FieldInfo.second;
- }
+ if (FieldPacked)
+ FieldAlign = 8;
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ FieldAlign = std::max(FieldAlign, AA->getMaxAlignment());
- if (FieldPacked)
- FieldAlign = 8;
- if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- FieldAlign = std::max(FieldAlign, AA->getAlignment());
- // The maximum field alignment overrides the aligned attribute.
- if (MaxFieldAlignment)
- FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+ // The maximum field alignment overrides the aligned attribute.
+ if (MaxFieldAlignment)
+ FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
- // Round up the current record size to the field's alignment boundary.
- FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
-
- if (!IsUnion) {
- while (true) {
- // Check if we can place the field at this offset.
- if (canPlaceFieldAtOffset(D, FieldOffset))
- break;
-
- // We couldn't place the field at the offset. Try again at a new offset.
- FieldOffset += FieldAlign;
- }
+ // Round up the current record size to the field's alignment boundary.
+ FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+
+ if (!IsUnion) {
+ while (true) {
+ // Check if we can place the field at this offset.
+ if (canPlaceFieldAtOffset(D, FieldOffset))
+ break;
- UpdateEmptyClassOffsets(D, FieldOffset);
+ // We couldn't place the field at the offset. Try again at a new offset.
+ FieldOffset += FieldAlign;
}
+
+ UpdateEmptyClassOffsets(D, FieldOffset);
}
-
+
// Place this field at the current location.
FieldOffsets.push_back(FieldOffset);
@@ -619,7 +651,7 @@ void ASTRecordLayoutBuilder::FinishLayout() {
Size = 8;
// Finally, round the size of the record up to the alignment of the
// record itself.
- Size = (Size + (Alignment-1)) & ~(Alignment-1);
+ Size = llvm::RoundUpToAlignment(Size, Alignment);
}
void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
@@ -631,6 +663,31 @@ 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) {
@@ -654,17 +711,19 @@ 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(),
NonVirtualSize,
Builder.NonVirtualAlignment,
Builder.PrimaryBase,
- Builder.PrimaryBaseWasVirtual,
Builder.Bases.data(),
Builder.Bases.size(),
Builder.VBases.data(),
- Builder.VBases.size());
+ Builder.VBases.size(),
+ KeyFunction);
}
const ASTRecordLayout *
diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h
index 0770723..69e0498 100644
--- a/lib/AST/RecordLayoutBuilder.h
+++ b/lib/AST/RecordLayoutBuilder.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H
#define LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H
+#include "clang/AST/RecordLayout.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/System/DataTypes.h"
@@ -27,12 +28,21 @@ namespace clang {
class ASTRecordLayoutBuilder {
ASTContext &Ctx;
+ /// Size - The current size of the record layout.
uint64_t Size;
+
+ /// Alignment - The current alignment of the record layout.
unsigned Alignment;
+
llvm::SmallVector<uint64_t, 16> FieldOffsets;
/// Packed - Whether the record is packed or not.
bool Packed;
+
+ /// UnfilledBitsInLastByte - If the last field laid out was a bitfield,
+ /// this contains the number of bits in the last byte that can be used for
+ /// an adjacent bitfield if necessary.
+ unsigned char UnfilledBitsInLastByte;
/// MaxFieldAlignment - The maximum allowed field alignment. This is set by
/// #pragma pack.
@@ -45,8 +55,8 @@ class ASTRecordLayoutBuilder {
uint64_t NonVirtualSize;
unsigned NonVirtualAlignment;
- const CXXRecordDecl *PrimaryBase;
- bool PrimaryBaseWasVirtual;
+
+ ASTRecordLayout::PrimaryBaseInfo PrimaryBase;
typedef llvm::SmallVector<std::pair<const CXXRecordDecl *,
uint64_t>, 4> BaseOffsetsTy;
@@ -74,6 +84,7 @@ class ASTRecordLayoutBuilder {
void LayoutFields(const RecordDecl *D);
void LayoutField(const FieldDecl *D);
+ void LayoutBitField(const FieldDecl *D);
void SelectPrimaryBase(const CXXRecordDecl *RD);
void SelectPrimaryVBase(const CXXRecordDecl *RD,
@@ -84,9 +95,8 @@ class ASTRecordLayoutBuilder {
/// base class.
void IdentifyPrimaryBases(const CXXRecordDecl *RD);
- void setPrimaryBase(const CXXRecordDecl *PB, bool Virtual) {
- PrimaryBase = PB;
- PrimaryBaseWasVirtual = Virtual;
+ void setPrimaryBase(const CXXRecordDecl *Base, bool IsVirtual) {
+ PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, IsVirtual);
}
bool IsNearlyEmpty(const CXXRecordDecl *RD) const;
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 6e0da47..fad80ec 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -88,8 +88,8 @@ void Stmt::addStmtClass(StmtClass s) {
static bool StatSwitch = false;
-bool Stmt::CollectingStats(bool enable) {
- if (enable) StatSwitch = true;
+bool Stmt::CollectingStats(bool Enable) {
+ if (Enable) StatSwitch = true;
return StatSwitch;
}
@@ -559,7 +559,7 @@ Stmt::child_iterator CXXCatchStmt::child_end() {
return &HandlerBlock + 1;
}
-QualType CXXCatchStmt::getCaughtType() {
+QualType CXXCatchStmt::getCaughtType() const {
if (ExceptionDecl)
return ExceptionDecl->getType();
return QualType();
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index 93bf875..bbe6a71 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -17,7 +17,6 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/Support/Compiler.h"
#include <cstdio>
using namespace clang;
@@ -26,7 +25,7 @@ using namespace clang;
//===----------------------------------------------------------------------===//
namespace {
- class VISIBILITY_HIDDEN StmtDumper : public StmtVisitor<StmtDumper> {
+ class StmtDumper : public StmtVisitor<StmtDumper> {
SourceManager *SM;
FILE *F;
unsigned IndentLevel;
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 4bd7f96..205ea0d 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -16,7 +16,6 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/PrettyPrinter.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
using namespace clang;
@@ -25,7 +24,7 @@ using namespace clang;
//===----------------------------------------------------------------------===//
namespace {
- class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor<StmtPrinter> {
+ class StmtPrinter : public StmtVisitor<StmtPrinter> {
llvm::raw_ostream &OS;
ASTContext &Context;
unsigned IndentLevel;
@@ -483,19 +482,26 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
Policy);
}
-void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) {
+void StmtPrinter::VisitDependentScopeDeclRefExpr(
+ DependentScopeDeclRefExpr *Node) {
Node->getQualifier()->print(OS, Policy);
OS << Node->getDeclName().getAsString();
+ if (Node->hasExplicitTemplateArgs())
+ OS << TemplateSpecializationType::PrintTemplateArgumentList(
+ Node->getTemplateArgs(),
+ Node->getNumTemplateArgs(),
+ Policy);
}
-void StmtPrinter::VisitTemplateIdRefExpr(TemplateIdRefExpr *Node) {
+void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
if (Node->getQualifier())
Node->getQualifier()->print(OS, Policy);
- Node->getTemplateName().print(OS, Policy, true);
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
+ OS << Node->getName().getAsString();
+ if (Node->hasExplicitTemplateArgs())
+ OS << TemplateSpecializationType::PrintTemplateArgumentList(
+ Node->getTemplateArgs(),
Node->getNumTemplateArgs(),
- Policy);
+ Policy);
}
void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
@@ -1048,11 +1054,6 @@ void StmtPrinter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *Node) {
OS << Node->getType().getAsString() << "()";
}
-void
-StmtPrinter::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *E) {
- PrintRawDecl(E->getVarDecl());
-}
-
void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
if (E->isGlobalNew())
OS << "::";
@@ -1118,10 +1119,6 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
OS << TypeS;
}
-void StmtPrinter::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *E) {
- OS << E->getName().getAsString();
-}
-
void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
// Nothing to print.
}
@@ -1146,7 +1143,8 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr(
OS << ")";
}
-void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) {
+void StmtPrinter::VisitCXXDependentScopeMemberExpr(
+ CXXDependentScopeMemberExpr *Node) {
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->" : ".");
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
@@ -1165,6 +1163,24 @@ void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) {
}
}
+void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
+ PrintExpr(Node->getBase());
+ OS << (Node->isArrow() ? "->" : ".");
+ if (NestedNameSpecifier *Qualifier = Node->getQualifier())
+ Qualifier->print(OS, Policy);
+
+ // FIXME: this might originally have been written with 'template'
+
+ OS << Node->getMemberName().getAsString();
+
+ if (Node->hasExplicitTemplateArgs()) {
+ OS << TemplateSpecializationType::PrintTemplateArgumentList(
+ Node->getTemplateArgs(),
+ Node->getNumTemplateArgs(),
+ Policy);
+ }
+}
+
static const char *getTypeTraitName(UnaryTypeTrait UTT) {
switch (UTT) {
default: assert(false && "Unknown type trait");
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 4458c2b..d832a46 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -20,11 +20,10 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
namespace {
- class VISIBILITY_HIDDEN StmtProfiler : public StmtVisitor<StmtProfiler> {
+ class StmtProfiler : public StmtVisitor<StmtProfiler> {
llvm::FoldingSetNodeID &ID;
ASTContext &Context;
bool Canonical;
@@ -108,14 +107,17 @@ void StmtProfiler::VisitLabelStmt(LabelStmt *S) {
void StmtProfiler::VisitIfStmt(IfStmt *S) {
VisitStmt(S);
+ VisitDecl(S->getConditionVariable());
}
void StmtProfiler::VisitSwitchStmt(SwitchStmt *S) {
VisitStmt(S);
+ VisitDecl(S->getConditionVariable());
}
void StmtProfiler::VisitWhileStmt(WhileStmt *S) {
VisitStmt(S);
+ VisitDecl(S->getConditionVariable());
}
void StmtProfiler::VisitDoStmt(DoStmt *S) {
@@ -481,10 +483,6 @@ void StmtProfiler::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *S) {
- VisitDeclRefExpr(S);
-}
-
void StmtProfiler::VisitCXXDeleteExpr(CXXDeleteExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isGlobalDelete());
@@ -515,9 +513,13 @@ void StmtProfiler::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *S) {
}
void
-StmtProfiler::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *S) {
+StmtProfiler::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *S) {
VisitExpr(S);
+ VisitNestedNameSpecifier(S->getQualifier());
VisitName(S->getName());
+ ID.AddBoolean(S->hasExplicitTemplateArgs());
+ if (S->hasExplicitTemplateArgs())
+ VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
}
void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) {
@@ -526,18 +528,14 @@ void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) {
VisitType(S->getQueriedType());
}
-void StmtProfiler::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *S) {
+void
+StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) {
VisitExpr(S);
VisitName(S->getDeclName());
VisitNestedNameSpecifier(S->getQualifier());
- ID.AddBoolean(S->isAddressOfOperand());
-}
-
-void StmtProfiler::VisitTemplateIdRefExpr(TemplateIdRefExpr *S) {
- VisitExpr(S);
- VisitNestedNameSpecifier(S->getQualifier());
- VisitTemplateName(S->getTemplateName());
- VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
+ ID.AddBoolean(S->hasExplicitTemplateArgs());
+ if (S->hasExplicitTemplateArgs())
+ VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
}
void StmtProfiler::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *S) {
@@ -554,11 +552,25 @@ StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) {
VisitType(S->getTypeAsWritten());
}
-void StmtProfiler::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *S) {
+void
+StmtProfiler::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isArrow());
VisitNestedNameSpecifier(S->getQualifier());
VisitName(S->getMember());
+ ID.AddBoolean(S->hasExplicitTemplateArgumentList());
+ if (S->hasExplicitTemplateArgumentList())
+ VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
+}
+
+void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->isArrow());
+ VisitNestedNameSpecifier(S->getQualifier());
+ VisitName(S->getMemberName());
+ ID.AddBoolean(S->hasExplicitTemplateArgs());
+ if (S->hasExplicitTemplateArgs())
+ VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
}
void StmtProfiler::VisitObjCStringLiteral(ObjCStringLiteral *S) {
diff --git a/lib/AST/StmtViz.cpp b/lib/AST/StmtViz.cpp
index 61fd750..8be287e 100644
--- a/lib/AST/StmtViz.cpp
+++ b/lib/AST/StmtViz.cpp
@@ -30,8 +30,9 @@ void Stmt::viewAST() const {
namespace llvm {
template<>
struct DOTGraphTraits<const Stmt*> : public DefaultDOTGraphTraits {
- static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph,
- bool ShortNames) {
+ DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
+
+ static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph) {
#ifndef NDEBUG
std::string OutSStr;
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index ff02f9a..f341b45 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -15,6 +15,7 @@
#include "llvm/ADT/FoldingSet.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/TypeLoc.h"
@@ -59,8 +60,17 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
break;
case Template:
- ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate())
- .getAsVoidPointer());
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast_or_null<TemplateTemplateParmDecl>(
+ getAsTemplate().getAsTemplateDecl())) {
+ ID.AddBoolean(true);
+ ID.AddInteger(TTP->getDepth());
+ ID.AddInteger(TTP->getPosition());
+ } else {
+ ID.AddBoolean(false);
+ ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate())
+ .getAsVoidPointer());
+ }
break;
case Integral:
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 297534e..5a2434d 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -725,6 +725,7 @@ const char *BuiltinType::getName(const LangOptions &LO) const {
case UndeducedAuto: return "auto";
case ObjCId: return "id";
case ObjCClass: return "Class";
+ case ObjCSel: return "SEL";
}
}
@@ -866,6 +867,11 @@ static bool isDependent(const TemplateArgument &Arg) {
}
bool TemplateSpecializationType::
+anyDependentTemplateArguments(const TemplateArgumentListInfo &Args) {
+ return anyDependentTemplateArguments(Args.getArgumentArray(), Args.size());
+}
+
+bool TemplateSpecializationType::
anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N) {
for (unsigned i = 0; i != N; ++i)
if (isDependent(Args[i].getArgument()))
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index a482333..562e830 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -535,6 +535,8 @@ void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T,
ObjCQIString = "id";
else if (T->isObjCClassType() || T->isObjCQualifiedClassType())
ObjCQIString = "Class";
+ else if (T->isObjCSelType())
+ ObjCQIString = "SEL";
else
ObjCQIString = T->getInterfaceDecl()->getNameAsString();
@@ -599,6 +601,14 @@ static void PrintTemplateArgument(std::string &Buffer,
}
}
+std::string TemplateSpecializationType::
+ PrintTemplateArgumentList(const TemplateArgumentListInfo &Args,
+ const PrintingPolicy &Policy) {
+ return PrintTemplateArgumentList(Args.getArgumentArray(),
+ Args.size(),
+ Policy);
+}
+
std::string
TemplateSpecializationType::PrintTemplateArgumentList(
const TemplateArgument *Args,
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 640912a..339e2c9 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -18,21 +18,12 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ParentMap.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/Support/BumpVector.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
-AnalysisContext::~AnalysisContext() {
- delete cfg;
- delete liveness;
- delete PM;
-}
-
-AnalysisContextManager::~AnalysisContextManager() {
- for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
- delete I->second;
-}
-
void AnalysisContextManager::clear() {
for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
delete I->second;
@@ -73,7 +64,7 @@ LiveVariables *AnalysisContext::getLiveVariables() {
if (!c)
return 0;
- liveness = new LiveVariables(D->getASTContext(), *c);
+ liveness = new LiveVariables(*this);
liveness->runOnCFG(*c);
liveness->runOnAllBlocks(*c, 0, true);
}
@@ -157,3 +148,75 @@ ScopeContext *LocationContextManager::getScope(AnalysisContext *ctx,
}
return scope;
}
+
+//===----------------------------------------------------------------------===//
+// Lazily generated map to query the external variables referenced by a Block.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class FindBlockDeclRefExprsVals : public StmtVisitor<FindBlockDeclRefExprsVals>{
+ BumpVector<const VarDecl*> &BEVals;
+ BumpVectorContext &BC;
+public:
+ FindBlockDeclRefExprsVals(BumpVector<const VarDecl*> &bevals,
+ BumpVectorContext &bc)
+ : BEVals(bevals), BC(bc) {}
+
+ void VisitStmt(Stmt *S) {
+ for (Stmt::child_iterator I = S->child_begin(), E = S->child_end();I!=E;++I)
+ if (Stmt *child = *I)
+ Visit(child);
+ }
+
+ void VisitBlockDeclRefExpr(BlockDeclRefExpr *DR) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
+ BEVals.push_back(VD, BC);
+ }
+};
+} // end anonymous namespace
+
+typedef BumpVector<const VarDecl*> DeclVec;
+
+static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD,
+ void *&Vec,
+ llvm::BumpPtrAllocator &A) {
+ if (Vec)
+ return (DeclVec*) Vec;
+
+ BumpVectorContext BC(A);
+ DeclVec *BV = (DeclVec*) A.Allocate<DeclVec>();
+ new (BV) DeclVec(BC, 10);
+
+ // Find the referenced variables.
+ FindBlockDeclRefExprsVals F(*BV, BC);
+ F.Visit(BD->getBody());
+
+ Vec = BV;
+ return BV;
+}
+
+std::pair<AnalysisContext::referenced_decls_iterator,
+ AnalysisContext::referenced_decls_iterator>
+AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) {
+ if (!ReferencedBlockVars)
+ ReferencedBlockVars = new llvm::DenseMap<const BlockDecl*,void*>();
+
+ DeclVec *V = LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A);
+ return std::make_pair(V->begin(), V->end());
+}
+
+//===----------------------------------------------------------------------===//
+// Cleanup.
+//===----------------------------------------------------------------------===//
+
+AnalysisContext::~AnalysisContext() {
+ delete cfg;
+ delete liveness;
+ delete PM;
+ delete ReferencedBlockVars;
+}
+
+AnalysisContextManager::~AnalysisContextManager() {
+ for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
+ delete I->second;
+}
diff --git a/lib/Analysis/ArrayBoundChecker.cpp b/lib/Analysis/ArrayBoundChecker.cpp
index 549a22b..3d95ab1 100644
--- a/lib/Analysis/ArrayBoundChecker.cpp
+++ b/lib/Analysis/ArrayBoundChecker.cpp
@@ -20,7 +20,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN ArrayBoundChecker :
+class ArrayBoundChecker :
public CheckerVisitor<ArrayBoundChecker> {
BuiltinBug *BT;
public:
@@ -62,8 +62,7 @@ void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){
const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true);
const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false);
if (StOutBound && !StInBound) {
- ExplodedNode *N = C.GenerateNode(S, StOutBound, true);
-
+ ExplodedNode *N = C.GenerateSink(StOutBound);
if (!N)
return;
@@ -80,7 +79,12 @@ void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){
new RangedBugReport(*BT, BT->getDescription(), N);
report->addRange(S->getSourceRange());
-
C.EmitReport(report);
+ return;
}
+
+ // Array bound check succeeded. From this point forward the array bound
+ // should always succeed.
+ assert(StInBound);
+ C.addTransition(StInBound);
}
diff --git a/lib/Analysis/AttrNonNullChecker.cpp b/lib/Analysis/AttrNonNullChecker.cpp
index 01e1a1f..aa21700 100644
--- a/lib/Analysis/AttrNonNullChecker.cpp
+++ b/lib/Analysis/AttrNonNullChecker.cpp
@@ -19,7 +19,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN AttrNonNullChecker
+class AttrNonNullChecker
: public CheckerVisitor<AttrNonNullChecker> {
BugType *BT;
public:
@@ -39,7 +39,6 @@ void clang::RegisterAttrNonNullChecker(GRExprEngine &Eng) {
void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C,
const CallExpr *CE) {
const GRState *state = C.getState();
- const GRState *originalState = state;
// Check if the callee has a 'nonnull' attribute.
SVal X = state->getSVal(CE->getCallee());
@@ -74,7 +73,7 @@ void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C,
if (stateNull && !stateNotNull) {
// Generate an error node. Check for a null node in case
// we cache out.
- if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) {
+ if (ExplodedNode *errorNode = C.GenerateSink(stateNull)) {
// Lazily allocate the BugType object if it hasn't already been
// created. Ownership is transferred to the BugReporter object once
@@ -109,6 +108,5 @@ void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C,
// If we reach here all of the arguments passed the nonnull check.
// If 'state' has been updated generated a new node.
- if (state != originalState)
- C.addTransition(C.GenerateNode(CE, state));
+ C.addTransition(state);
}
diff --git a/lib/Analysis/BadCallChecker.cpp b/lib/Analysis/BadCallChecker.cpp
deleted file mode 100644
index 7a7ea18..0000000
--- a/lib/Analysis/BadCallChecker.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//===--- BadCallChecker.h - Bad call checker --------------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines BadCallChecker, a builtin check in GRExprEngine that performs
-// checks for bad callee at call sites.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "GRExprEngineInternalChecks.h"
-
-using namespace clang;
-
-namespace {
-class VISIBILITY_HIDDEN BadCallChecker : public CheckerVisitor<BadCallChecker> {
- BuiltinBug *BT;
-public:
- BadCallChecker() : BT(0) {}
- static void *getTag() {
- static int x = 0;
- return &x;
- }
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-};
-} // end anonymous namespace
-
-void clang::RegisterBadCallChecker(GRExprEngine &Eng) {
- Eng.registerCheck(new BadCallChecker());
-}
-
-void BadCallChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
- const Expr *Callee = CE->getCallee()->IgnoreParens();
- SVal L = C.getState()->getSVal(Callee);
-
- if (L.isUndef() || isa<loc::ConcreteInt>(L)) {
- if (ExplodedNode *N = C.GenerateNode(CE, true)) {
- if (!BT)
- BT = new BuiltinBug("Invalid function call",
- "Called function pointer is a null or undefined pointer value");
-
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getDescription(), N);
-
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetCalleeExpr(N));
-
- C.EmitReport(R);
- }
- }
-}
diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp
index d0b8289..6c3f7b2 100644
--- a/lib/Analysis/BasicConstraintManager.cpp
+++ b/lib/Analysis/BasicConstraintManager.cpp
@@ -16,14 +16,13 @@
#include "clang/Analysis/PathSensitive/GRState.h"
#include "clang/Analysis/PathSensitive/GRStateTrait.h"
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
-namespace { class VISIBILITY_HIDDEN ConstNotEq {}; }
-namespace { class VISIBILITY_HIDDEN ConstEq {}; }
+namespace { class ConstNotEq {}; }
+namespace { class ConstEq {}; }
typedef llvm::ImmutableMap<SymbolRef,GRState::IntSetTy> ConstNotEqTy;
typedef llvm::ImmutableMap<SymbolRef,const llvm::APSInt*> ConstEqTy;
@@ -46,7 +45,7 @@ struct GRStateTrait<ConstEq> : public GRStatePartialTrait<ConstEqTy> {
namespace {
// BasicConstraintManager only tracks equality and inequality constraints of
// constants and integer variables.
-class VISIBILITY_HIDDEN BasicConstraintManager
+class BasicConstraintManager
: public SimpleConstraintManager {
GRState::IntSetTy::Factory ISetFactory;
public:
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
index c2ecfa1..c913779 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -22,12 +22,12 @@
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/MemRegion.h"
#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
@@ -52,12 +52,12 @@ static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
namespace {
-class VISIBILITY_HIDDEN APIMisuse : public BugType {
+class APIMisuse : public BugType {
public:
APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
};
-class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
+class BasicObjCFoundationChecks : public GRSimpleAPICheck {
APIMisuse *BT;
BugReporter& BR;
ASTContext &Ctx;
@@ -87,7 +87,7 @@ private:
// by the BugReporter object 'BR' once we call BR.EmitWarning.
if (!BT) BT = new APIMisuse("nil argument");
- RangedBugReport *R = new RangedBugReport(*BT, os.str().c_str(), N);
+ RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
R->addRange(ME->getArg(Arg)->getSourceRange());
BR.EmitReport(R);
}
@@ -228,7 +228,7 @@ bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N,
namespace {
-class VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck {
+class AuditCFNumberCreate : public GRSimpleAPICheck {
APIMisuse* BT;
// FIXME: Either this should be refactored into GRSimpleAPICheck, or
@@ -435,7 +435,7 @@ void AuditCFNumberCreate::AddError(const TypedRegion* R, const Expr* Ex,
// Lazily create the BugType object. This will be owned
// by the BugReporter object 'BR' once we call BR.EmitWarning.
if (!BT) BT = new APIMisuse("Bad use of CFNumberCreate");
- RangedBugReport *report = new RangedBugReport(*BT, os.str().c_str(), N);
+ RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
report->addRange(Ex->getSourceRange());
BR.EmitReport(report);
}
@@ -450,7 +450,7 @@ clang::CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN AuditCFRetainRelease : public GRSimpleAPICheck {
+class AuditCFRetainRelease : public GRSimpleAPICheck {
APIMisuse *BT;
// FIXME: Either this should be refactored into GRSimpleAPICheck, or
@@ -522,6 +522,64 @@ clang::CreateAuditCFRetainRelease(ASTContext& Ctx, BugReporter& BR) {
}
//===----------------------------------------------------------------------===//
+// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class ClassReleaseChecker :
+ public CheckerVisitor<ClassReleaseChecker> {
+ Selector releaseS;
+ Selector retainS;
+ Selector autoreleaseS;
+ Selector drainS;
+ BugType *BT;
+public:
+ ClassReleaseChecker(ASTContext &Ctx)
+ : releaseS(GetNullarySelector("release", Ctx)),
+ retainS(GetNullarySelector("retain", Ctx)),
+ autoreleaseS(GetNullarySelector("autorelease", Ctx)),
+ drainS(GetNullarySelector("drain", Ctx)),
+ BT(0) {}
+
+ static void *getTag() { static int x = 0; return &x; }
+
+ void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+};
+}
+
+void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
+ const ObjCMessageExpr *ME) {
+
+ const IdentifierInfo *ClsName = ME->getClassName();
+ if (!ClsName)
+ return;
+
+ Selector S = ME->getSelector();
+ if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
+ return;
+
+ if (!BT)
+ BT = new APIMisuse("message incorrectly sent to class instead of class "
+ "instance");
+
+ ExplodedNode *N = C.GenerateNode();
+
+ if (!N)
+ return;
+
+ llvm::SmallString<200> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ os << "The '" << S.getAsString() << "' message should be sent to instances "
+ "of class '" << ClsName->getName()
+ << "' and not the class directly";
+
+ RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
+ report->addRange(ME->getSourceRange());
+ C.EmitReport(report);
+}
+
+//===----------------------------------------------------------------------===//
// Check registration.
//===----------------------------------------------------------------------===//
@@ -536,4 +594,5 @@ void clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) {
RegisterNSErrorChecks(BR, Eng, D);
RegisterNSAutoreleasePoolChecks(Eng);
+ Eng.registerCheck(new ClassReleaseChecker(Ctx));
}
diff --git a/lib/Analysis/BasicObjCFoundationChecks.h b/lib/Analysis/BasicObjCFoundationChecks.h
index ea4d3ec..679c6dc 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.h
+++ b/lib/Analysis/BasicObjCFoundationChecks.h
@@ -13,24 +13,16 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
-#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ASTContext.h"
-#include "llvm/Support/Compiler.h"
-
#ifndef LLVM_CLANG_ANALYSIS_BASICOBJCFOUNDATIONCHECKS
#define LLVM_CLANG_ANALYSIS_BASICOBJCFOUNDATIONCHECKS
namespace clang {
-class GRSimpleAPICheck;
class ASTContext;
-class GRStateManager;
class BugReporter;
+class Decl;
class GRExprEngine;
+class GRSimpleAPICheck;
GRSimpleAPICheck *CreateBasicObjCFoundationChecks(ASTContext& Ctx,
BugReporter& BR);
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp
index 800a76f..45fc11a 100644
--- a/lib/Analysis/BasicStore.cpp
+++ b/lib/Analysis/BasicStore.cpp
@@ -15,7 +15,6 @@
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "clang/Analysis/PathSensitive/GRState.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
@@ -24,7 +23,7 @@ typedef llvm::ImmutableMap<const MemRegion*,SVal> BindingsTy;
namespace {
-class VISIBILITY_HIDDEN BasicStoreSubRegionMap : public SubRegionMap {
+class BasicStoreSubRegionMap : public SubRegionMap {
public:
BasicStoreSubRegionMap() {}
@@ -33,7 +32,7 @@ public:
}
};
-class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager {
+class BasicStoreManager : public StoreManager {
BindingsTy::Factory VBFactory;
public:
BasicStoreManager(GRStateManager& mgr)
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index 8235f4a..c26a60a 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -119,7 +119,7 @@ typedef llvm::DenseMap<const ExplodedNode*,
const ExplodedNode*> NodeBackMap;
namespace {
-class VISIBILITY_HIDDEN NodeMapClosure : public BugReport::NodeResolver {
+class NodeMapClosure : public BugReport::NodeResolver {
NodeBackMap& M;
public:
NodeMapClosure(NodeBackMap *m) : M(*m) {}
@@ -131,7 +131,7 @@ public:
}
};
-class VISIBILITY_HIDDEN PathDiagnosticBuilder : public BugReporterContext {
+class PathDiagnosticBuilder : public BugReporterContext {
BugReport *R;
PathDiagnosticClient *PDC;
llvm::OwningPtr<ParentMap> PM;
@@ -358,7 +358,7 @@ GetMostRecentVarDeclBinding(const ExplodedNode* N,
}
namespace {
-class VISIBILITY_HIDDEN NotableSymbolHandler
+class NotableSymbolHandler
: public StoreManager::BindingsHandler {
SymbolRef Sym;
@@ -458,7 +458,7 @@ static void HandleNotableSymbol(const ExplodedNode* N,
}
namespace {
-class VISIBILITY_HIDDEN ScanNotableSymbols
+class ScanNotableSymbols
: public StoreManager::BindingsHandler {
llvm::SmallSet<SymbolRef, 10> AlreadyProcessed;
@@ -802,7 +802,7 @@ static bool IsControlFlowExpr(const Stmt *S) {
}
namespace {
-class VISIBILITY_HIDDEN ContextLocation : public PathDiagnosticLocation {
+class ContextLocation : public PathDiagnosticLocation {
bool IsDead;
public:
ContextLocation(const PathDiagnosticLocation &L, bool isdead = false)
@@ -812,7 +812,7 @@ public:
bool isDead() const { return IsDead; }
};
-class VISIBILITY_HIDDEN EdgeBuilder {
+class EdgeBuilder {
std::vector<ContextLocation> CLocs;
typedef std::vector<ContextLocation>::iterator iterator;
PathDiagnostic &PD;
@@ -1645,7 +1645,7 @@ void BugReporter::EmitReport(BugReport* R) {
//===----------------------------------------------------------------------===//
namespace {
-struct VISIBILITY_HIDDEN FRIEC_WLItem {
+struct FRIEC_WLItem {
const ExplodedNode *N;
ExplodedNode::const_succ_iterator I, E;
@@ -1738,7 +1738,7 @@ static BugReport *FindReportInEquivalenceClass(BugReportEquivClass& EQ) {
// uses global state, which eventually should go elsewhere.
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN DiagCacheItem : public llvm::FoldingSetNode {
+class DiagCacheItem : public llvm::FoldingSetNode {
llvm::FoldingSetNodeID ID;
public:
DiagCacheItem(BugReport *R, PathDiagnostic *PD) {
@@ -1835,14 +1835,15 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
PD->HandlePathDiagnostic(D.take());
}
-void BugReporter::EmitBasicReport(const char* name, const char* str,
+void BugReporter::EmitBasicReport(llvm::StringRef name, llvm::StringRef str,
SourceLocation Loc,
SourceRange* RBeg, unsigned NumRanges) {
EmitBasicReport(name, "", str, Loc, RBeg, NumRanges);
}
-void BugReporter::EmitBasicReport(const char* name, const char* category,
- const char* str, SourceLocation Loc,
+void BugReporter::EmitBasicReport(llvm::StringRef name,
+ llvm::StringRef category,
+ llvm::StringRef str, SourceLocation Loc,
SourceRange* RBeg, unsigned NumRanges) {
// 'BT' will be owned by BugReporter as soon as we call 'EmitReport'.
diff --git a/lib/Analysis/BugReporterVisitors.cpp b/lib/Analysis/BugReporterVisitors.cpp
index 89c9ca1..87de30a 100644
--- a/lib/Analysis/BugReporterVisitors.cpp
+++ b/lib/Analysis/BugReporterVisitors.cpp
@@ -83,7 +83,7 @@ clang::bugreporter::GetRetValExpr(const ExplodedNode *N) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN FindLastStoreBRVisitor : public BugReporterVisitor {
+class FindLastStoreBRVisitor : public BugReporterVisitor {
const MemRegion *R;
SVal V;
bool satisfied;
@@ -231,7 +231,7 @@ static void registerFindLastStore(BugReporterContext& BRC, const MemRegion *R,
BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
}
-class VISIBILITY_HIDDEN TrackConstraintBRVisitor : public BugReporterVisitor {
+class TrackConstraintBRVisitor : public BugReporterVisitor {
DefinedSVal Constraint;
const bool Assumption;
bool isSatisfied;
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 3141759..c97692f 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -17,7 +17,6 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/PrettyPrinter.h"
#include "llvm/Support/GraphWriter.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Format.h"
#include "llvm/ADT/DenseMap.h"
@@ -50,7 +49,7 @@ static SourceLocation GetEndLoc(Decl* D) {
/// constructed prior to its predecessor. This allows us to nicely capture
/// implicit fall-throughs without extra basic blocks.
///
-class VISIBILITY_HIDDEN CFGBuilder {
+class CFGBuilder {
ASTContext *Context;
llvm::OwningPtr<CFG> cfg;
@@ -461,9 +460,12 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd) {
return VisitStmt(B, alwaysAdd);
}
-CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr* E, bool alwaysAdd) {
- // FIXME
- return NYS();
+CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, bool alwaysAdd) {
+ if (alwaysAdd) {
+ autoCreateBlock();
+ AppendStmt(Block, E);
+ }
+ return Block;
}
CFGBlock *CFGBuilder::VisitBlockDeclRefExpr(BlockDeclRefExpr* E,
@@ -1624,7 +1626,7 @@ CFG::~CFG() {
namespace {
-class VISIBILITY_HIDDEN StmtPrinterHelper : public PrinterHelper {
+class StmtPrinterHelper : public PrinterHelper {
typedef llvm::DenseMap<Stmt*,std::pair<unsigned,unsigned> > StmtMapTy;
StmtMapTy StmtMap;
@@ -1668,7 +1670,7 @@ public:
namespace {
-class VISIBILITY_HIDDEN CFGBlockTerminatorPrint
+class CFGBlockTerminatorPrint
: public StmtVisitor<CFGBlockTerminatorPrint,void> {
llvm::raw_ostream& OS;
@@ -2047,8 +2049,10 @@ void CFG::viewCFG(const LangOptions &LO) const {
namespace llvm {
template<>
struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits {
- static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph,
- bool ShortNames) {
+
+ DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
+
+ static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph) {
#ifndef NDEBUG
std::string OutSStr;
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index 55e5f17..b95f981 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -22,13 +22,14 @@
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/SymbolManager.h"
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/StmtVisitor.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/ADT/STLExtras.h"
#include <stdarg.h>
@@ -168,7 +169,7 @@ ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) {
}
namespace {
-class VISIBILITY_HIDDEN GenericNodeBuilder {
+class GenericNodeBuilder {
GRStmtNodeBuilder *SNB;
Stmt *S;
const void *tag;
@@ -246,7 +247,7 @@ namespace {
/// RetEffect is used to summarize a function/method call's behavior with
/// respect to its return value.
-class VISIBILITY_HIDDEN RetEffect {
+class RetEffect {
public:
enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol,
NotOwnedSymbol, GCNotOwnedSymbol, ReceiverAlias,
@@ -312,7 +313,7 @@ public:
// Reference-counting logic (typestate + counts).
//===----------------------------------------------------------------------===//
-class VISIBILITY_HIDDEN RefVal {
+class RefVal {
public:
enum Kind {
Owned = 0, // Owning reference.
@@ -536,7 +537,7 @@ namespace clang {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN RetainSummary {
+class RetainSummary {
/// Args - an ordered vector of (index, ArgEffect) pairs, where index
/// specifies the argument (starting from 0). This can be sparsely
/// populated; arguments with no entry in Args use 'DefaultArgEffect'.
@@ -627,7 +628,7 @@ public:
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN ObjCSummaryKey {
+class ObjCSummaryKey {
IdentifierInfo* II;
Selector S;
public:
@@ -682,7 +683,7 @@ template <> struct DenseMapInfo<ObjCSummaryKey> {
} // end llvm namespace
namespace {
-class VISIBILITY_HIDDEN ObjCSummaryCache {
+class ObjCSummaryCache {
typedef llvm::DenseMap<ObjCSummaryKey, RetainSummary*> MapTy;
MapTy M;
public:
@@ -776,7 +777,7 @@ public:
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN RetainSummaryManager {
+class RetainSummaryManager {
//==-----------------------------------------------------------------==//
// Typedefs.
@@ -1865,8 +1866,8 @@ typedef llvm::ImmutableList<SymbolRef> ARStack;
static int AutoRCIndex = 0;
static int AutoRBIndex = 0;
-namespace { class VISIBILITY_HIDDEN AutoreleasePoolContents {}; }
-namespace { class VISIBILITY_HIDDEN AutoreleaseStack {}; }
+namespace { class AutoreleasePoolContents {}; }
+namespace { class AutoreleaseStack {}; }
namespace clang {
template<> struct GRStateTrait<AutoreleaseStack>
@@ -1908,7 +1909,7 @@ static const GRState * SendAutorelease(const GRState *state,
namespace {
-class VISIBILITY_HIDDEN CFRefCount : public GRTransferFuncs {
+class CFRefCount : public GRTransferFuncs {
public:
class BindingsPrinter : public GRState::Printer {
public:
@@ -2093,11 +2094,11 @@ namespace {
// Bug Descriptions. //
//===-------------===//
- class VISIBILITY_HIDDEN CFRefBug : public BugType {
+ class CFRefBug : public BugType {
protected:
CFRefCount& TF;
- CFRefBug(CFRefCount* tf, const char* name)
+ CFRefBug(CFRefCount* tf, llvm::StringRef name)
: BugType(name, "Memory (Core Foundation/Objective-C)"), TF(*tf) {}
public:
@@ -2110,7 +2111,7 @@ namespace {
virtual bool isLeak() const { return false; }
};
- class VISIBILITY_HIDDEN UseAfterRelease : public CFRefBug {
+ class UseAfterRelease : public CFRefBug {
public:
UseAfterRelease(CFRefCount* tf)
: CFRefBug(tf, "Use-after-release") {}
@@ -2120,7 +2121,7 @@ namespace {
}
};
- class VISIBILITY_HIDDEN BadRelease : public CFRefBug {
+ class BadRelease : public CFRefBug {
public:
BadRelease(CFRefCount* tf) : CFRefBug(tf, "Bad release") {}
@@ -2130,7 +2131,7 @@ namespace {
}
};
- class VISIBILITY_HIDDEN DeallocGC : public CFRefBug {
+ class DeallocGC : public CFRefBug {
public:
DeallocGC(CFRefCount *tf)
: CFRefBug(tf, "-dealloc called while using garbage collection") {}
@@ -2140,7 +2141,7 @@ namespace {
}
};
- class VISIBILITY_HIDDEN DeallocNotOwned : public CFRefBug {
+ class DeallocNotOwned : public CFRefBug {
public:
DeallocNotOwned(CFRefCount *tf)
: CFRefBug(tf, "-dealloc sent to non-exclusively owned object") {}
@@ -2150,7 +2151,7 @@ namespace {
}
};
- class VISIBILITY_HIDDEN OverAutorelease : public CFRefBug {
+ class OverAutorelease : public CFRefBug {
public:
OverAutorelease(CFRefCount *tf) :
CFRefBug(tf, "Object sent -autorelease too many times") {}
@@ -2160,7 +2161,7 @@ namespace {
}
};
- class VISIBILITY_HIDDEN ReturnedNotOwnedForOwned : public CFRefBug {
+ class ReturnedNotOwnedForOwned : public CFRefBug {
public:
ReturnedNotOwnedForOwned(CFRefCount *tf) :
CFRefBug(tf, "Method should return an owned object") {}
@@ -2171,10 +2172,10 @@ namespace {
}
};
- class VISIBILITY_HIDDEN Leak : public CFRefBug {
+ class Leak : public CFRefBug {
const bool isReturn;
protected:
- Leak(CFRefCount* tf, const char* name, bool isRet)
+ Leak(CFRefCount* tf, llvm::StringRef name, bool isRet)
: CFRefBug(tf, name), isReturn(isRet) {}
public:
@@ -2183,15 +2184,15 @@ namespace {
bool isLeak() const { return true; }
};
- class VISIBILITY_HIDDEN LeakAtReturn : public Leak {
+ class LeakAtReturn : public Leak {
public:
- LeakAtReturn(CFRefCount* tf, const char* name)
+ LeakAtReturn(CFRefCount* tf, llvm::StringRef name)
: Leak(tf, name, true) {}
};
- class VISIBILITY_HIDDEN LeakWithinFunction : public Leak {
+ class LeakWithinFunction : public Leak {
public:
- LeakWithinFunction(CFRefCount* tf, const char* name)
+ LeakWithinFunction(CFRefCount* tf, llvm::StringRef name)
: Leak(tf, name, false) {}
};
@@ -2199,7 +2200,7 @@ namespace {
// Bug Reports. //
//===---------===//
- class VISIBILITY_HIDDEN CFRefReport : public RangedBugReport {
+ class CFRefReport : public RangedBugReport {
protected:
SymbolRef Sym;
const CFRefCount &TF;
@@ -2209,7 +2210,7 @@ namespace {
: RangedBugReport(D, D.getDescription(), n), Sym(sym), TF(tf) {}
CFRefReport(CFRefBug& D, const CFRefCount &tf,
- ExplodedNode *n, SymbolRef sym, const char* endText)
+ ExplodedNode *n, SymbolRef sym, llvm::StringRef endText)
: RangedBugReport(D, D.getDescription(), endText, n), Sym(sym), TF(tf) {}
virtual ~CFRefReport() {}
@@ -2240,7 +2241,7 @@ namespace {
BugReporterContext& BRC);
};
- class VISIBILITY_HIDDEN CFRefLeakReport : public CFRefReport {
+ class CFRefLeakReport : public CFRefReport {
SourceLocation AllocSite;
const MemRegion* AllocBinding;
public:
@@ -2255,64 +2256,7 @@ namespace {
};
} // end anonymous namespace
-void CFRefCount::RegisterChecks(GRExprEngine& Eng) {
- BugReporter &BR = Eng.getBugReporter();
-
- useAfterRelease = new UseAfterRelease(this);
- BR.Register(useAfterRelease);
-
- releaseNotOwned = new BadRelease(this);
- BR.Register(releaseNotOwned);
-
- deallocGC = new DeallocGC(this);
- BR.Register(deallocGC);
-
- deallocNotOwned = new DeallocNotOwned(this);
- BR.Register(deallocNotOwned);
-
- overAutorelease = new OverAutorelease(this);
- BR.Register(overAutorelease);
-
- returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this);
- BR.Register(returnNotOwnedForOwned);
-
- // First register "return" leaks.
- const char* name = 0;
-
- if (isGCEnabled())
- name = "Leak of returned object when using garbage collection";
- else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
- name = "Leak of returned object when not using garbage collection (GC) in "
- "dual GC/non-GC code";
- else {
- assert(getLangOptions().getGCMode() == LangOptions::NonGC);
- name = "Leak of returned object";
- }
-
- // Leaks should not be reported if they are post-dominated by a sink.
- leakAtReturn = new LeakAtReturn(this, name);
- leakAtReturn->setSuppressOnSink(true);
- BR.Register(leakAtReturn);
-
- // Second, register leaks within a function/method.
- if (isGCEnabled())
- name = "Leak of object when using garbage collection";
- else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
- name = "Leak of object when not using garbage collection (GC) in "
- "dual GC/non-GC code";
- else {
- assert(getLangOptions().getGCMode() == LangOptions::NonGC);
- name = "Leak";
- }
-
- // Leaks should not be reported if they are post-dominated by sinks.
- leakWithinFunction = new LeakWithinFunction(this, name);
- leakWithinFunction->setSuppressOnSink(true);
- BR.Register(leakWithinFunction);
- // Save the reference to the BugReporter.
- this->BR = &BR;
-}
static const char* Msgs[] = {
// GC only
@@ -2603,7 +2547,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
}
namespace {
- class VISIBILITY_HIDDEN FindUniqueBinding :
+ class FindUniqueBinding :
public StoreManager::BindingsHandler {
SymbolRef Sym;
const MemRegion* Binding;
@@ -3052,9 +2996,20 @@ void CFRefCount::EvalCall(ExplodedNodeSet& Dst,
GRStmtNodeBuilder& Builder,
CallExpr* CE, SVal L,
ExplodedNode* Pred) {
- const FunctionDecl* FD = L.getAsFunctionDecl();
- RetainSummary* Summ = !FD ? Summaries.getDefaultSummary()
- : Summaries.getSummary(const_cast<FunctionDecl*>(FD));
+
+ RetainSummary *Summ = 0;
+
+ // FIXME: Better support for blocks. For now we stop tracking anything
+ // that is passed to blocks.
+ // FIXME: Need to handle variables that are "captured" by the block.
+ if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) {
+ Summ = Summaries.getPersistentStopSummary();
+ }
+ else {
+ const FunctionDecl* FD = L.getAsFunctionDecl();
+ Summ = !FD ? Summaries.getDefaultSummary() :
+ Summaries.getSummary(const_cast<FunctionDecl*>(FD));
+ }
assert(Summ);
EvalSummary(Dst, Eng, Builder, CE, 0, *Summ,
@@ -3066,6 +3021,16 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
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;
+ }
+ }
RetainSummary *Summ =
ME->getReceiver()
@@ -3079,7 +3044,7 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
}
namespace {
-class VISIBILITY_HIDDEN StopTrackingCallback : public SymbolVisitor {
+class StopTrackingCallback : public SymbolVisitor {
const GRState *state;
public:
StopTrackingCallback(const GRState *st) : state(st) {}
@@ -3501,7 +3466,7 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd
CFRefReport *report =
new CFRefReport(*static_cast<CFRefBug*>(overAutorelease),
- *this, N, Sym, os.str().c_str());
+ *this, N, Sym, os.str());
BR->EmitReport(report);
}
@@ -3670,9 +3635,114 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst,
}
//===----------------------------------------------------------------------===//
+// Pieces of the retain/release checker implemented using a CheckerVisitor.
+// More pieces of the retain/release checker will be migrated to this interface
+// (ideally, all of it some day).
+//===----------------------------------------------------------------------===//
+
+namespace {
+class RetainReleaseChecker
+ : public CheckerVisitor<RetainReleaseChecker> {
+ CFRefCount *TF;
+public:
+ RetainReleaseChecker(CFRefCount *tf) : TF(tf) {}
+ static void* getTag() { static int x = 0; return &x; }
+
+ void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE);
+};
+} // end anonymous namespace
+
+
+void RetainReleaseChecker::PostVisitBlockExpr(CheckerContext &C,
+ const BlockExpr *BE) {
+
+ // Scan the BlockDecRefExprs for any object the retain/release checker
+ // may be tracking.
+ if (!BE->hasBlockDeclRefExprs())
+ return;
+
+ const GRState *state = C.getState();
+ const BlockDataRegion *R =
+ cast<BlockDataRegion>(state->getSVal(BE).getAsRegion());
+
+ BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
+ E = R->referenced_vars_end();
+
+ if (I == E)
+ return;
+
+ state = state->scanReachableSymbols<StopTrackingCallback>(I, E).getState();
+ C.addTransition(state);
+}
+
+//===----------------------------------------------------------------------===//
// Transfer function creation for external clients.
//===----------------------------------------------------------------------===//
+void CFRefCount::RegisterChecks(GRExprEngine& Eng) {
+ BugReporter &BR = Eng.getBugReporter();
+
+ useAfterRelease = new UseAfterRelease(this);
+ BR.Register(useAfterRelease);
+
+ releaseNotOwned = new BadRelease(this);
+ BR.Register(releaseNotOwned);
+
+ deallocGC = new DeallocGC(this);
+ BR.Register(deallocGC);
+
+ deallocNotOwned = new DeallocNotOwned(this);
+ BR.Register(deallocNotOwned);
+
+ overAutorelease = new OverAutorelease(this);
+ BR.Register(overAutorelease);
+
+ returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this);
+ BR.Register(returnNotOwnedForOwned);
+
+ // First register "return" leaks.
+ const char* name = 0;
+
+ if (isGCEnabled())
+ name = "Leak of returned object when using garbage collection";
+ else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
+ name = "Leak of returned object when not using garbage collection (GC) in "
+ "dual GC/non-GC code";
+ else {
+ assert(getLangOptions().getGCMode() == LangOptions::NonGC);
+ name = "Leak of returned object";
+ }
+
+ // Leaks should not be reported if they are post-dominated by a sink.
+ leakAtReturn = new LeakAtReturn(this, name);
+ leakAtReturn->setSuppressOnSink(true);
+ BR.Register(leakAtReturn);
+
+ // Second, register leaks within a function/method.
+ if (isGCEnabled())
+ name = "Leak of object when using garbage collection";
+ else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
+ name = "Leak of object when not using garbage collection (GC) in "
+ "dual GC/non-GC code";
+ else {
+ assert(getLangOptions().getGCMode() == LangOptions::NonGC);
+ name = "Leak";
+ }
+
+ // Leaks should not be reported if they are post-dominated by sinks.
+ leakWithinFunction = new LeakWithinFunction(this, name);
+ leakWithinFunction->setSuppressOnSink(true);
+ BR.Register(leakWithinFunction);
+
+ // Save the reference to the BugReporter.
+ this->BR = &BR;
+
+ // Register the RetainReleaseChecker with the GRExprEngine object.
+ // Functionality in CFRefCount will be migrated to RetainReleaseChecker
+ // over time.
+ Eng.registerCheck(new RetainReleaseChecker(this));
+}
+
GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
const LangOptions& lopts) {
return new CFRefCount(Ctx, GCEnabled, lopts);
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index 8e8c1e7..409292d 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -4,7 +4,6 @@ add_clang_library(clangAnalysis
AnalysisContext.cpp
ArrayBoundChecker.cpp
AttrNonNullChecker.cpp
- BadCallChecker.cpp
BasicConstraintManager.cpp
BasicObjCFoundationChecks.cpp
BasicStore.cpp
@@ -13,6 +12,7 @@ add_clang_library(clangAnalysis
BugReporterVisitors.cpp
CFG.cpp
CFRefCount.cpp
+ CallAndMessageChecker.cpp
CallGraph.cpp
CallInliner.cpp
CastToStructChecker.cpp
@@ -22,6 +22,7 @@ add_clang_library(clangAnalysis
CheckObjCUnusedIVars.cpp
CheckSecuritySyntaxOnly.cpp
CheckSizeofPointer.cpp
+ Checker.cpp
DereferenceChecker.cpp
DivZeroChecker.cpp
Environment.cpp
@@ -31,7 +32,6 @@ add_clang_library(clangAnalysis
GRCoreEngine.cpp
GRExprEngine.cpp
GRExprEngineExperimentalChecks.cpp
- GRExprEngineInternalChecks.cpp
GRState.cpp
LiveVariables.cpp
MallocChecker.cpp
@@ -54,7 +54,8 @@ add_clang_library(clangAnalysis
SimpleSValuator.cpp
Store.cpp
SymbolManager.cpp
- UndefinedArgChecker.cpp
+ UndefBranchChecker.cpp
+ UndefResultChecker.cpp
UndefinedArraySubscriptChecker.cpp
UndefinedAssignmentChecker.cpp
UninitializedValues.cpp
diff --git a/lib/Analysis/CallAndMessageChecker.cpp b/lib/Analysis/CallAndMessageChecker.cpp
new file mode 100644
index 0000000..d8dd16c
--- /dev/null
+++ b/lib/Analysis/CallAndMessageChecker.cpp
@@ -0,0 +1,267 @@
+//===--- CallAndMessageChecker.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 CallAndMessageChecker, a builtin checker that checks for various
+// errors of call and objc message expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/AST/ParentMap.h"
+#include "GRExprEngineInternalChecks.h"
+
+using namespace clang;
+
+namespace {
+class CallAndMessageChecker
+ : public CheckerVisitor<CallAndMessageChecker> {
+ BugType *BT_call_null;
+ BugType *BT_call_undef;
+ BugType *BT_call_arg;
+ BugType *BT_msg_undef;
+ BugType *BT_msg_arg;
+ BugType *BT_msg_ret;
+public:
+ CallAndMessageChecker() :
+ BT_call_null(0), BT_call_undef(0), BT_call_arg(0),
+ BT_msg_undef(0), BT_msg_arg(0), BT_msg_ret(0) {}
+
+ static void *getTag() {
+ static int x = 0;
+ return &x;
+ }
+
+ void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+
+private:
+ void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
+ void EmitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
+ ExplodedNode *N);
+
+ void HandleNilReceiver(CheckerContext &C, const GRState *state,
+ const ObjCMessageExpr *ME);
+};
+} // end anonymous namespace
+
+void clang::RegisterCallAndMessageChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new CallAndMessageChecker());
+}
+
+void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
+ const CallExpr *CE) {
+ ExplodedNode *N = C.GenerateSink();
+ if (!N)
+ return;
+
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ bugreporter::GetCalleeExpr(N));
+ C.EmitReport(R);
+}
+
+void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
+ const CallExpr *CE){
+
+ const Expr *Callee = CE->getCallee()->IgnoreParens();
+ SVal L = C.getState()->getSVal(Callee);
+
+ if (L.isUndef()) {
+ if (!BT_call_undef)
+ BT_call_undef =
+ new BuiltinBug("Called function pointer is an undefined pointer value");
+ EmitBadCall(BT_call_undef, C, CE);
+ return;
+ }
+
+ if (isa<loc::ConcreteInt>(L)) {
+ if (!BT_call_null)
+ BT_call_null =
+ new BuiltinBug("Called function pointer is null (null dereference)");
+ EmitBadCall(BT_call_null, C, CE);
+ }
+
+ for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
+ I != E; ++I) {
+ if (C.getState()->getSVal(*I).isUndef()) {
+ if (ExplodedNode *N = C.GenerateSink()) {
+ if (!BT_call_arg)
+ BT_call_arg = new BuiltinBug("Pass-by-value argument in function call"
+ " is undefined");
+ // Generate a report for this bug.
+ EnhancedBugReport *R = new EnhancedBugReport(*BT_call_arg,
+ BT_call_arg->getName(), N);
+ R->addRange((*I)->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
+ C.EmitReport(R);
+ return;
+ }
+ }
+ }
+}
+
+void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
+ const ObjCMessageExpr *ME) {
+
+ const GRState *state = C.getState();
+
+ if (const Expr *receiver = ME->getReceiver())
+ if (state->getSVal(receiver).isUndef()) {
+ if (ExplodedNode *N = C.GenerateSink()) {
+ if (!BT_msg_undef)
+ BT_msg_undef =
+ new BuiltinBug("Receiver in message expression is a garbage value");
+ EnhancedBugReport *R =
+ new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N);
+ R->addRange(receiver->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ receiver);
+ C.EmitReport(R);
+ }
+ return;
+ }
+
+ // Check for any arguments that are uninitialized/undefined.
+ for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
+ E = ME->arg_end(); I != E; ++I) {
+ if (state->getSVal(*I).isUndef()) {
+ if (ExplodedNode *N = C.GenerateSink()) {
+ if (!BT_msg_arg)
+ BT_msg_arg =
+ new BuiltinBug("Pass-by-value argument in message expression"
+ " is undefined");
+ // Generate a report for this bug.
+ EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_arg,
+ BT_msg_arg->getName(), N);
+ R->addRange((*I)->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
+ C.EmitReport(R);
+ return;
+ }
+ }
+ }
+
+ // 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);
+}
+
+void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
+ const ObjCMessageExpr *ME,
+ ExplodedNode *N) {
+
+ if (!BT_msg_ret)
+ BT_msg_ret =
+ new BuiltinBug("Receiver in message expression is "
+ "'nil' and returns a garbage value");
+
+ llvm::SmallString<200> buf;
+ llvm::raw_svector_ostream os(buf);
+ os << "The receiver of message '" << ME->getSelector().getAsString()
+ << "' is nil and returns a value of type '"
+ << ME->getType().getAsString() << "' that will be garbage";
+
+ EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
+ const Expr *receiver = ME->getReceiver();
+ report->addRange(receiver->getSourceRange());
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ receiver);
+ C.EmitReport(report);
+}
+
+static bool SupportsNilWithFloatRet(const llvm::Triple &triple) {
+ return triple.getVendor() == llvm::Triple::Apple &&
+ triple.getDarwinMajorNumber() >= 9;
+}
+
+void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
+ const GRState *state,
+ const ObjCMessageExpr *ME) {
+
+ // Check the return type of the message expression. A message to nil will
+ // return different values depending on the return type and the architecture.
+ QualType RetTy = ME->getType();
+
+ ASTContext &Ctx = C.getASTContext();
+ CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
+
+ if (CanRetTy->isStructureType()) {
+ // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
+ // have the "use of undefined value" be smarter about where the
+ // undefined value came from.
+ if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
+ if (ExplodedNode* N = C.GenerateSink(state))
+ EmitNilReceiverBug(C, ME, N);
+ return;
+ }
+
+ // The result is not consumed by a surrounding expression. Just propagate
+ // the current state.
+ C.addTransition(state);
+ return;
+ }
+
+ // Other cases: check if the return type is smaller than void*.
+ if (CanRetTy != Ctx.VoidTy &&
+ C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
+ // Compute: sizeof(void *) and sizeof(return type)
+ const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
+ const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
+
+ if (voidPtrSize < returnTypeSize &&
+ !(SupportsNilWithFloatRet(Ctx.Target.getTriple()) &&
+ (Ctx.FloatTy == CanRetTy ||
+ Ctx.DoubleTy == CanRetTy ||
+ Ctx.LongDoubleTy == CanRetTy ||
+ Ctx.LongLongTy == CanRetTy))) {
+ if (ExplodedNode* N = C.GenerateSink(state))
+ EmitNilReceiverBug(C, ME, N);
+ return;
+ }
+
+ // Handle the safe cases where the return value is 0 if the
+ // receiver is nil.
+ //
+ // FIXME: For now take the conservative approach that we only
+ // return null values if we *know* that the receiver is nil.
+ // This is because we can have surprises like:
+ //
+ // ... = [[NSScreens screens] objectAtIndex:0];
+ //
+ // What can happen is that [... screens] could return nil, but
+ // it most likely isn't nil. We should assume the semantics
+ // of this case unless we have *a lot* more knowledge.
+ //
+ SVal V = C.getValueManager().makeZeroVal(ME->getType());
+ C.GenerateNode(state->BindExpr(ME, V));
+ return;
+ }
+
+ C.addTransition(state);
+}
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
index 06e3317..c1040f0 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Analysis/CallGraph.cpp
@@ -137,8 +137,10 @@ namespace llvm {
template <>
struct DOTGraphTraits<CallGraph> : public DefaultDOTGraphTraits {
+ DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
+
static std::string getNodeLabel(const CallGraphNode *Node,
- const CallGraph &CG, bool ShortNames) {
+ const CallGraph &CG) {
return Node->getName();
}
diff --git a/lib/Analysis/CallInliner.cpp b/lib/Analysis/CallInliner.cpp
index cca8584..43523c2 100644
--- a/lib/Analysis/CallInliner.cpp
+++ b/lib/Analysis/CallInliner.cpp
@@ -18,7 +18,7 @@ using namespace clang;
namespace {
-class VISIBILITY_HIDDEN CallInliner : public GRTransferFuncs {
+class CallInliner : public GRTransferFuncs {
ASTContext &Ctx;
public:
CallInliner(ASTContext &ctx) : Ctx(ctx) {}
diff --git a/lib/Analysis/CastToStructChecker.cpp b/lib/Analysis/CastToStructChecker.cpp
index ccd4a33..a366342 100644
--- a/lib/Analysis/CastToStructChecker.cpp
+++ b/lib/Analysis/CastToStructChecker.cpp
@@ -19,7 +19,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN CastToStructChecker
+class CastToStructChecker
: public CheckerVisitor<CastToStructChecker> {
BuiltinBug *BT;
public:
@@ -59,7 +59,7 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
// Now the cast-to-type is struct pointer, the original type is not void*.
if (!OrigPointeeTy->isRecordType()) {
- if (ExplodedNode *N = C.GenerateNode(CE)) {
+ if (ExplodedNode *N = C.GenerateNode()) {
if (!BT)
BT = new BuiltinBug("Cast from non-struct type to struct type",
"Casting a non-structure type to a structure type "
diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp
index d5cb7ca..ad63eb4 100644
--- a/lib/Analysis/CheckDeadStores.cpp
+++ b/lib/Analysis/CheckDeadStores.cpp
@@ -22,13 +22,12 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ParentMap.h"
#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN DeadStoreObs : public LiveVariables::ObserverTy {
+class DeadStoreObs : public LiveVariables::ObserverTy {
ASTContext &Ctx;
BugReporter& BR;
ParentMap& Parents;
@@ -77,7 +76,7 @@ public:
break;
}
- BR.EmitBasicReport(BugType, "Dead store", msg.c_str(), L, R);
+ BR.EmitBasicReport(BugType, "Dead store", msg, L, R);
}
void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val,
@@ -134,16 +133,15 @@ public:
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()))
if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- Expr* RHS = B->getRHS()->IgnoreParenCasts();
-
// Special case: check for assigning null to a pointer.
// This is a common form of defensive programming.
if (VD->getType()->isPointerType()) {
- if (IntegerLiteral* L = dyn_cast<IntegerLiteral>(RHS))
- // FIXME: Probably should have an Expr::isNullPointerConstant.
- if (L->getValue() == 0)
- return;
+ if (B->getRHS()->isNullPointerConstant(Ctx,
+ Expr::NPC_ValueDependentIsNull))
+ return;
}
+
+ Expr* RHS = B->getRHS()->IgnoreParenCasts();
// Special case: self-assignments. These are often used to shut up
// "unused variable" compiler warnings.
if (DeclRefExpr* RhsDR = dyn_cast<DeclRefExpr>(RHS))
@@ -226,7 +224,7 @@ public:
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{
+class FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{
CFG *cfg;
public:
FindEscaped(CFG *c) : cfg(c) {}
diff --git a/lib/Analysis/CheckObjCDealloc.cpp b/lib/Analysis/CheckObjCDealloc.cpp
index 92e3e11..87c1f27 100644
--- a/lib/Analysis/CheckObjCDealloc.cpp
+++ b/lib/Analysis/CheckObjCDealloc.cpp
@@ -169,7 +169,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
os << "Objective-C class '" << D->getNameAsString()
<< "' lacks a 'dealloc' instance method";
- BR.EmitBasicReport(name, os.str().c_str(), D->getLocStart());
+ BR.EmitBasicReport(name, os.str(), D->getLocStart());
return;
}
@@ -187,7 +187,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
<< "' does not send a 'dealloc' message to its super class"
" (missing [super dealloc])";
- BR.EmitBasicReport(name, os.str().c_str(), D->getLocStart());
+ BR.EmitBasicReport(name, os.str(), D->getLocStart());
return;
}
@@ -251,8 +251,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
"but was released in 'dealloc'";
}
- BR.EmitBasicReport(name, category,
- os.str().c_str(), (*I)->getLocation());
+ BR.EmitBasicReport(name, category, os.str(), (*I)->getLocation());
}
}
}
diff --git a/lib/Analysis/CheckObjCInstMethSignature.cpp b/lib/Analysis/CheckObjCInstMethSignature.cpp
index 8c0d396..10ba896 100644
--- a/lib/Analysis/CheckObjCInstMethSignature.cpp
+++ b/lib/Analysis/CheckObjCInstMethSignature.cpp
@@ -65,7 +65,7 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
"behavior for clients of these classes.";
BR.EmitBasicReport("Incompatible instance method return type",
- os.str().c_str(), MethDerived->getLocStart());
+ os.str(), MethDerived->getLocStart());
}
}
diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Analysis/CheckObjCUnusedIVars.cpp
index 2d9b531..d4067c9 100644
--- a/lib/Analysis/CheckObjCUnusedIVars.cpp
+++ b/lib/Analysis/CheckObjCUnusedIVars.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
using namespace clang;
@@ -85,6 +86,17 @@ static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) {
}
}
+static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID,
+ SourceManager &SM) {
+ for (DeclContext::decl_iterator I=C->decls_begin(), E=C->decls_end();
+ I!=E; ++I)
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
+ SourceLocation L = FD->getLocStart();
+ if (SM.getFileID(L) == FID)
+ Scan(M, FD->getBody());
+ }
+}
+
void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
BugReporter &BR) {
@@ -110,10 +122,30 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
if (M.empty())
return;
-
+
// Now scan the implementation declaration.
Scan(M, D);
+
+ // Any potentially unused ivars?
+ bool hasUnused = false;
+ for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
+ if (I->second == Unused) {
+ hasUnused = true;
+ break;
+ }
+
+ if (!hasUnused)
+ return;
+
+ // We found some potentially unused ivars. Scan the entire translation unit
+ // for functions inside the @implementation that reference these ivars.
+ // FIXME: In the future hopefully we can just use the lexical DeclContext
+ // to go from the ObjCImplementationDecl to the lexically "nested"
+ // C functions.
+ SourceManager &SM = BR.getSourceManager();
+ Scan(M, D->getDeclContext(), SM.getFileID(D->getLocation()), SM);
+
// Find ivars that are unused.
for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
if (I->second == Unused) {
@@ -125,6 +157,6 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
"(although it may be used by category methods).";
BR.EmitBasicReport("Unused instance variable", "Optimization",
- os.str().c_str(), I->first->getLocation());
+ os.str(), I->first->getLocation());
}
}
diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
index f1b9c21..e6ab17a 100644
--- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
@@ -14,13 +14,12 @@
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/AST/StmtVisitor.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> {
+class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
IdentifierInfo *II_gets;
IdentifierInfo *II_getpw;
@@ -210,7 +209,7 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
ranges.push_back(drInc->getSourceRange());
const char *bugType = "Floating point variable used as loop counter";
- BR.EmitBasicReport(bugType, "Security", os.str().c_str(),
+ BR.EmitBasicReport(bugType, "Security", os.str(),
FS->getLocStart(), ranges.data(), ranges.size());
}
@@ -347,7 +346,7 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
SourceRange R = CE->getCallee()->getSourceRange();
- BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(),
+ BR.EmitBasicReport(os1.str(), "Security", os2.str(),
CE->getLocStart(), &R, 1);
}
@@ -437,7 +436,7 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
SourceRange R = CE->getCallee()->getSourceRange();
- BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(),
+ BR.EmitBasicReport(os1.str(), "Security", os2.str(),
CE->getLocStart(), &R, 1);
}
diff --git a/lib/Analysis/CheckSizeofPointer.cpp b/lib/Analysis/CheckSizeofPointer.cpp
index 174beef..4f5da9f 100644
--- a/lib/Analysis/CheckSizeofPointer.cpp
+++ b/lib/Analysis/CheckSizeofPointer.cpp
@@ -15,12 +15,11 @@
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/LocalCheckers.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> {
+class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
public:
diff --git a/lib/Analysis/Checker.cpp b/lib/Analysis/Checker.cpp
new file mode 100644
index 0000000..0d907e5
--- /dev/null
+++ b/lib/Analysis/Checker.cpp
@@ -0,0 +1,35 @@
+//== Checker.h - Abstract interface for checkers -----------------*- 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 Checker and CheckerVisitor, classes used for creating
+// domain-specific checks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/Checker.h"
+using namespace clang;
+
+Checker::~Checker() {}
+
+CheckerContext::~CheckerContext() {
+ // Do we need to autotransition? 'Dst' can get populated in a variety of
+ // ways, including 'addTransition()' adding the predecessor node to Dst
+ // without actually generated a new node. We also shouldn't autotransition
+ // 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)) {
+ static int autoTransitionTag = 0;
+ B.Tag = &autoTransitionTag;
+ addTransition(state);
+ }
+ else
+ Dst.Add(Pred);
+ }
+}
diff --git a/lib/Analysis/DereferenceChecker.cpp b/lib/Analysis/DereferenceChecker.cpp
index c3aa8f3..9824387 100644
--- a/lib/Analysis/DereferenceChecker.cpp
+++ b/lib/Analysis/DereferenceChecker.cpp
@@ -21,7 +21,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN DereferenceChecker : public Checker {
+class DereferenceChecker : public Checker {
BuiltinBug *BT_null;
BuiltinBug *BT_undef;
llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes;
@@ -56,8 +56,7 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
SVal l) {
// Check for dereference of an undefined value.
if (l.isUndef()) {
- ExplodedNode *N = C.GenerateNode(S, true);
- if (N) {
+ if (ExplodedNode *N = C.GenerateSink()) {
if (!BT_undef)
BT_undef = new BuiltinBug("Dereference of undefined pointer value");
@@ -82,34 +81,55 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
// The explicit NULL case.
if (nullState) {
- // Generate an error node.
- ExplodedNode *N = C.GenerateNode(S, nullState, true);
- if (N) {
- if (!notNullState) {
- // We know that 'location' cannot be non-null. This is what
- // we call an "explicit" null dereference.
- if (!BT_null)
- BT_null = new BuiltinBug("Null pointer dereference",
- "Dereference of null pointer");
-
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT_null, BT_null->getDescription(), N);
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetDerefExpr(N));
-
- C.EmitReport(report);
+ if (!notNullState) {
+ // Generate an error node.
+ ExplodedNode *N = C.GenerateSink(nullState);
+ if (!N)
return;
+
+ // We know that 'location' cannot be non-null. This is what
+ // we call an "explicit" null dereference.
+ if (!BT_null)
+ BT_null = new BuiltinBug("Dereference of null pointer");
+
+ llvm::SmallString<100> buf;
+
+ switch (S->getStmtClass()) {
+ case Stmt::UnaryOperatorClass: {
+ const UnaryOperator *U = cast<UnaryOperator>(S);
+ const Expr *SU = U->getSubExpr()->IgnoreParens();
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SU)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ llvm::raw_svector_ostream os(buf);
+ os << "Dereference of null pointer loaded from variable '"
+ << VD->getName() << '\'';
+ }
+ }
+ }
+ default:
+ break;
}
+ EnhancedBugReport *report =
+ new EnhancedBugReport(*BT_null,
+ buf.empty() ? BT_null->getDescription():buf.str(),
+ N);
+
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ bugreporter::GetDerefExpr(N));
+
+ C.EmitReport(report);
+ return;
+ }
+ else {
// Otherwise, we have the case where the location could either be
// null or not-null. Record the error node as an "implicit" null
- // dereference.
- ImplicitNullDerefNodes.push_back(N);
+ // dereference.
+ if (ExplodedNode *N = C.GenerateSink(nullState))
+ ImplicitNullDerefNodes.push_back(N);
}
}
// From this point forward, we know that the location is not null.
- assert(notNullState);
- C.addTransition(state != nullState ? C.GenerateNode(S, notNullState) :
- C.getPredecessor());
+ C.addTransition(notNullState);
}
diff --git a/lib/Analysis/DivZeroChecker.cpp b/lib/Analysis/DivZeroChecker.cpp
index a8630f1..266c236 100644
--- a/lib/Analysis/DivZeroChecker.cpp
+++ b/lib/Analysis/DivZeroChecker.cpp
@@ -18,7 +18,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN DivZeroChecker : public CheckerVisitor<DivZeroChecker> {
+class DivZeroChecker : public CheckerVisitor<DivZeroChecker> {
BuiltinBug *BT;
public:
DivZeroChecker() : BT(0) {}
@@ -63,7 +63,7 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C,
llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(), *DV);
if (stateZero && !stateNotZero) {
- if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) {
+ if (ExplodedNode *N = C.GenerateSink(stateZero)) {
if (!BT)
BT = new BuiltinBug("Division by zero");
@@ -80,6 +80,5 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C,
// If we get here, then the denom should not be zero. We abandon the implicit
// zero denom case for now.
- if (stateNotZero != C.getState())
- C.addTransition(C.GenerateNode(B, stateNotZero));
+ C.addTransition(stateNotZero);
}
diff --git a/lib/Analysis/Environment.cpp b/lib/Analysis/Environment.cpp
index 1610ad4..dd2f08b 100644
--- a/lib/Analysis/Environment.cpp
+++ b/lib/Analysis/Environment.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/GRState.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
@@ -83,7 +82,7 @@ Environment EnvironmentManager::BindExpr(Environment Env, const Stmt *S,
}
namespace {
-class VISIBILITY_HIDDEN MarkLiveCallback : public SymbolVisitor {
+class MarkLiveCallback : public SymbolVisitor {
SymbolReaper &SymReaper;
public:
MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
diff --git a/lib/Analysis/FixedAddressChecker.cpp b/lib/Analysis/FixedAddressChecker.cpp
index 80096dc..031ca44 100644
--- a/lib/Analysis/FixedAddressChecker.cpp
+++ b/lib/Analysis/FixedAddressChecker.cpp
@@ -19,7 +19,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN FixedAddressChecker
+class FixedAddressChecker
: public CheckerVisitor<FixedAddressChecker> {
BuiltinBug *BT;
public:
@@ -53,7 +53,7 @@ void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C,
if (!RV.isConstant() || RV.isZeroConstant())
return;
- if (ExplodedNode *N = C.GenerateNode(B)) {
+ if (ExplodedNode *N = C.GenerateNode()) {
if (!BT)
BT = new BuiltinBug("Use fixed address",
"Using a fixed address is not portable because that "
diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Analysis/GRCoreEngine.cpp
index b99ba4f..644dd19 100644
--- a/lib/Analysis/GRCoreEngine.cpp
+++ b/lib/Analysis/GRCoreEngine.cpp
@@ -15,7 +15,6 @@
#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/AST/Expr.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/DenseMap.h"
#include <vector>
@@ -30,7 +29,7 @@ using namespace clang;
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN DFS : public GRWorkList {
+class DFS : public GRWorkList {
llvm::SmallVector<GRWorkListUnit,20> Stack;
public:
virtual bool hasWork() const {
@@ -49,7 +48,7 @@ public:
}
};
-class VISIBILITY_HIDDEN BFS : public GRWorkList {
+class BFS : public GRWorkList {
std::queue<GRWorkListUnit> Queue;
public:
virtual bool hasWork() const {
@@ -79,7 +78,7 @@ GRWorkList *GRWorkList::MakeDFS() { return new DFS(); }
GRWorkList *GRWorkList::MakeBFS() { return new BFS(); }
namespace {
- class VISIBILITY_HIDDEN BFSBlockDFSContents : public GRWorkList {
+ class BFSBlockDFSContents : public GRWorkList {
std::queue<GRWorkListUnit> Queue;
llvm::SmallVector<GRWorkListUnit,20> Stack;
public:
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 2633177..20820d4 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -13,6 +13,7 @@
//
//===----------------------------------------------------------------------===//
+#include "GRExprEngineInternalChecks.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
#include "clang/Analysis/PathSensitive/Checker.h"
@@ -22,7 +23,6 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/PrettyStackTrace.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/StringSwitch.h"
@@ -37,12 +37,21 @@ using llvm::cast;
using llvm::APSInt;
//===----------------------------------------------------------------------===//
+// Utility functions.
+//===----------------------------------------------------------------------===//
+
+static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
+ IdentifierInfo* II = &Ctx.Idents.get(name);
+ return Ctx.Selectors.getSelector(0, &II);
+}
+
+//===----------------------------------------------------------------------===//
// Batch auditor. DEPRECATED.
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN MappedBatchAuditor : public GRSimpleAPICheck {
+class MappedBatchAuditor : public GRSimpleAPICheck {
typedef llvm::ImmutableList<GRSimpleAPICheck*> Checks;
typedef llvm::DenseMap<void*,Checks> MapTy;
@@ -107,16 +116,17 @@ public:
// Checker worklist routines.
//===----------------------------------------------------------------------===//
-void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
+bool GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
ExplodedNodeSet &Src, bool isPrevisit) {
if (Checkers.empty()) {
- Dst = Src;
- return;
+ Dst.insert(Src);
+ return false;
}
ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
+ bool stopProcessingAfterCurrentChecker = false;
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
{
@@ -126,17 +136,33 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
CurrSet->clear();
void *tag = I->first;
Checker *checker = I->second;
-
+
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
- NI != NE; ++NI)
- checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit);
+ 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;
- // Update which NodeSet is the current one.
+ // Continue on to the next checker. Update the current NodeSet.
PrevSet = CurrSet;
}
// Don't autotransition. The CheckerContext objects should do this
// automatically.
+ return false;
}
// FIXME: This is largely copy-paste from CheckerVisit(). Need to
@@ -179,12 +205,30 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
// Engine construction and deletion.
//===----------------------------------------------------------------------===//
-static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
- IdentifierInfo* II = &Ctx.Idents.get(name);
- return Ctx.Selectors.getSelector(0, &II);
+static void RegisterInternalChecks(GRExprEngine &Eng) {
+ // Register internal "built-in" BugTypes with the BugReporter. These BugTypes
+ // are different than what probably many checks will do since they don't
+ // create BugReports on-the-fly but instead wait until GRExprEngine finishes
+ // analyzing a function. Generation of BugReport objects is done via a call
+ // to 'FlushReports' from BugReporter.
+ // The following checks do not need to have their associated BugTypes
+ // explicitly registered with the BugReporter. If they issue any BugReports,
+ // their associated BugType will get registered with the BugReporter
+ // automatically. Note that the check itself is owned by the GRExprEngine
+ // object.
+ RegisterAttrNonNullChecker(Eng);
+ RegisterCallAndMessageChecker(Eng);
+ RegisterDereferenceChecker(Eng);
+ RegisterVLASizeChecker(Eng);
+ RegisterDivZeroChecker(Eng);
+ RegisterReturnStackAddressChecker(Eng);
+ RegisterReturnUndefChecker(Eng);
+ RegisterUndefinedArraySubscriptChecker(Eng);
+ RegisterUndefinedAssignmentChecker(Eng);
+ RegisterUndefBranchChecker(Eng);
+ RegisterUndefResultChecker(Eng);
}
-
GRExprEngine::GRExprEngine(AnalysisManager &mgr)
: AMgr(mgr),
CoreEngine(mgr.getASTContext(), *this),
@@ -198,7 +242,11 @@ GRExprEngine::GRExprEngine(AnalysisManager &mgr)
CurrentStmt(NULL),
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
RaiseSel(GetNullarySelector("raise", G.getContext())),
- BR(mgr, *this) {}
+ BR(mgr, *this)
+{
+ // Register internal checks.
+ RegisterInternalChecks(*this);
+}
GRExprEngine::~GRExprEngine() {
BR.FlushReports();
@@ -211,7 +259,6 @@ GRExprEngine::~GRExprEngine() {
// Utility methods.
//===----------------------------------------------------------------------===//
-
void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) {
StateMgr.TF = tf;
tf->RegisterChecks(*this);
@@ -410,6 +457,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
break;
+ case Stmt::BlockExprClass:
+ VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
+ break;
+
case Stmt::BinaryOperatorClass: {
BinaryOperator* B = cast<BinaryOperator>(S);
@@ -771,55 +822,49 @@ void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term,
Condition->getLocStart(),
"Error evaluating branch");
- const GRState* PrevState = builder.getState();
- SVal X = PrevState->getSVal(Condition);
- DefinedSVal *V = NULL;
-
- while (true) {
- V = dyn_cast<DefinedSVal>(&X);
-
- if (!V) {
- if (X.isUnknown()) {
- if (const Expr *Ex = dyn_cast<Expr>(Condition)) {
- if (Ex->getType()->isIntegerType()) {
- // Try to recover some path-sensitivity. Right now casts of symbolic
- // integers that promote their values are currently not tracked well.
- // If 'Condition' is such an expression, try and recover the
- // underlying value and use that instead.
- SVal recovered = RecoverCastedSymbol(getStateManager(),
- builder.getState(), Condition,
- getContext());
-
- if (!recovered.isUnknown()) {
- X = recovered;
- continue;
- }
- }
- }
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
+ void *tag = I->first;
+ Checker *checker = I->second;
+ checker->VisitBranchCondition(builder, *this, Condition, tag);
+ }
- builder.generateNode(MarkBranch(PrevState, Term, true), true);
- builder.generateNode(MarkBranch(PrevState, Term, false), false);
- return;
- }
+ // If the branch condition is undefined, return;
+ if (!builder.isFeasible(true) && !builder.isFeasible(false))
+ return;
- assert(X.isUndef());
- ExplodedNode *N = builder.generateNode(PrevState, true);
+ const GRState* PrevState = builder.getState();
+ SVal X = PrevState->getSVal(Condition);
- if (N) {
- N->markAsSink();
- UndefBranches.insert(N);
+ if (X.isUnknown()) {
+ // Give it a chance to recover from unknown.
+ if (const Expr *Ex = dyn_cast<Expr>(Condition)) {
+ if (Ex->getType()->isIntegerType()) {
+ // Try to recover some path-sensitivity. Right now casts of symbolic
+ // integers that promote their values are currently not tracked well.
+ // If 'Condition' is such an expression, try and recover the
+ // underlying value and use that instead.
+ SVal recovered = RecoverCastedSymbol(getStateManager(),
+ builder.getState(), Condition,
+ getContext());
+
+ if (!recovered.isUnknown()) {
+ X = recovered;
+ }
}
-
- builder.markInfeasible(false);
+ }
+ // If the condition is still unknown, give up.
+ if (X.isUnknown()) {
+ builder.generateNode(MarkBranch(PrevState, Term, true), true);
+ builder.generateNode(MarkBranch(PrevState, Term, false), false);
return;
}
-
- break;
}
+ DefinedSVal V = cast<DefinedSVal>(X);
+
// Process the true branch.
if (builder.isFeasible(true)) {
- if (const GRState *state = PrevState->Assume(*V, true))
+ if (const GRState *state = PrevState->Assume(V, true))
builder.generateNode(MarkBranch(state, Term, true), true);
else
builder.markInfeasible(true);
@@ -827,7 +872,7 @@ void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term,
// Process the false branch.
if (builder.isFeasible(false)) {
- if (const GRState *state = PrevState->Assume(*V, false))
+ if (const GRState *state = PrevState->Assume(V, false))
builder.generateNode(MarkBranch(state, Term, false), false);
else
builder.markInfeasible(false);
@@ -866,8 +911,9 @@ void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) {
if (isa<loc::ConcreteInt>(V) || isa<UndefinedVal>(V)) {
// Dispatch to the first target and mark it as a sink.
- ExplodedNode* N = builder.generateNode(builder.begin(), state, true);
- UndefBranches.insert(N);
+ //ExplodedNode* N = builder.generateNode(builder.begin(), state, true);
+ // FIXME: add checker visit.
+ // UndefBranches.insert(N);
return;
}
@@ -918,8 +964,10 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
SVal CondV_untested = state->getSVal(CondE);
if (CondV_untested.isUndef()) {
- ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
- UndefBranches.insert(N);
+ //ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
+ // FIXME: add checker
+ //UndefBranches.insert(N);
+
return;
}
DefinedOrUnknownSVal CondV = cast<DefinedOrUnknownSVal>(CondV_untested);
@@ -1052,6 +1100,22 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred,
// Transfer functions: Loads and stores.
//===----------------------------------------------------------------------===//
+void GRExprEngine::VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+
+ ExplodedNodeSet Tmp;
+
+ CanQualType T = getContext().getCanonicalType(BE->getType());
+ SVal V = ValMgr.getBlockPointer(BE->getBlockDecl(), T,
+ Pred->getLocationContext());
+
+ MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V),
+ ProgramPoint::PostLValueKind);
+
+ // Post-visit the BlockExpr.
+ CheckerVisit(BE, Dst, Tmp, false);
+}
+
void GRExprEngine::VisitDeclRefExpr(DeclRefExpr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst, bool asLValue) {
@@ -1278,7 +1342,7 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
ExplodedNode* Pred,
const GRState* state, SVal location,
const void *tag, bool isLoad) {
-
+ // Early checks for performance reason.
if (location.isUnknown() || Checkers.empty()) {
Dst.Add(Pred);
return;
@@ -1298,9 +1362,13 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
Checker *checker = I->second;
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
- NI != NE; ++NI)
- checker->GR_VisitLocation(*CurrSet, *Builder, *this, S, *NI, state,
+ NI != NE; ++NI) {
+ // Use the 'state' argument only when the predecessor node is the
+ // same as Pred. This allows us to catch updates to the state.
+ checker->GR_VisitLocation(*CurrSet, *Builder, *this, S, *NI,
+ *NI == Pred ? state : GetState(*NI),
location, tag, isLoad);
+ }
// Update which NodeSet is the current one.
PrevSet = CurrSet;
@@ -1850,197 +1918,89 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
- // FIXME: More logic for the processing the method call.
-
- const GRState* state = GetState(Pred);
- bool RaisesException = false;
-
-
- if (Expr* Receiver = ME->getReceiver()) {
-
- SVal L_untested = state->getSVal(Receiver);
-
- // Check for undefined control-flow.
- if (L_untested.isUndef()) {
- ExplodedNode* N = Builder->generateNode(ME, state, Pred);
-
- if (N) {
- N->markAsSink();
- UndefReceivers.insert(N);
- }
-
- return;
- }
-
- // "Assume" that the receiver is not NULL.
- DefinedOrUnknownSVal L = cast<DefinedOrUnknownSVal>(L_untested);
- const GRState *StNotNull = state->Assume(L, true);
-
- // "Assume" that the receiver is NULL.
- const GRState *StNull = state->Assume(L, false);
-
- if (StNull) {
- QualType RetTy = ME->getType();
-
- // Check if the receiver was nil and the return value a struct.
- if (RetTy->isRecordType()) {
- if (Pred->getParentMap().isConsumedExpr(ME)) {
- // The [0 ...] expressions will return garbage. Flag either an
- // explicit or implicit error. Because of the structure of this
- // function we currently do not bifurfacte the state graph at
- // this point.
- // FIXME: We should bifurcate and fill the returned struct with
- // garbage.
- if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) {
- N->markAsSink();
- if (StNotNull)
- NilReceiverStructRetImplicit.insert(N);
- else
- NilReceiverStructRetExplicit.insert(N);
- }
- }
- }
- else {
- ASTContext& Ctx = getContext();
- if (RetTy != Ctx.VoidTy) {
- if (Pred->getParentMap().isConsumedExpr(ME)) {
- // sizeof(void *)
- const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
- // sizeof(return type)
- const uint64_t returnTypeSize = Ctx.getTypeSize(ME->getType());
-
- if (voidPtrSize < returnTypeSize) {
- if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) {
- N->markAsSink();
- if (StNotNull)
- NilReceiverLargerThanVoidPtrRetImplicit.insert(N);
- else
- NilReceiverLargerThanVoidPtrRetExplicit.insert(N);
- }
- }
- else if (!StNotNull) {
- // Handle the safe cases where the return value is 0 if the
- // receiver is nil.
- //
- // FIXME: For now take the conservative approach that we only
- // return null values if we *know* that the receiver is nil.
- // This is because we can have surprises like:
- //
- // ... = [[NSScreens screens] objectAtIndex:0];
- //
- // What can happen is that [... screens] could return nil, but
- // it most likely isn't nil. We should assume the semantics
- // of this case unless we have *a lot* more knowledge.
- //
- SVal V = ValMgr.makeZeroVal(ME->getType());
- MakeNode(Dst, ME, Pred, StNull->BindExpr(ME, V));
- return;
- }
- }
- }
- }
- // We have handled the cases where the receiver is nil. The remainder
- // of this method should assume that the receiver is not nil.
- if (!StNotNull)
- return;
-
- state = StNotNull;
- }
-
- // Check if the "raise" message was sent.
- if (ME->getSelector() == RaiseSel)
- RaisesException = true;
+ // Handle previsits checks.
+ ExplodedNodeSet Src, DstTmp;
+ Src.Add(Pred);
+
+ if (CheckerVisit(ME, DstTmp, Src, true)) {
+ Dst.insert(DstTmp);
+ return;
}
- else {
-
- IdentifierInfo* ClsName = ME->getClassName();
- Selector S = ME->getSelector();
-
- // Check for special instance methods.
+
+ unsigned size = Dst.size();
- if (!NSExceptionII) {
- ASTContext& Ctx = getContext();
+ for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
+ DI!=DE; ++DI) {
+ Pred = *DI;
+ bool RaisesException = false;
- NSExceptionII = &Ctx.Idents.get("NSException");
+ if (ME->getReceiver()) {
+ // Check if the "raise" message was sent.
+ if (ME->getSelector() == RaiseSel)
+ RaisesException = true;
}
+ else {
- if (ClsName == NSExceptionII) {
-
- enum { NUM_RAISE_SELECTORS = 2 };
-
- // Lazily create a cache of the selectors.
+ IdentifierInfo* ClsName = ME->getClassName();
+ Selector S = ME->getSelector();
- if (!NSExceptionInstanceRaiseSelectors) {
+ // Check for special instance methods.
+ if (!NSExceptionII) {
ASTContext& Ctx = getContext();
- NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS];
+ NSExceptionII = &Ctx.Idents.get("NSException");
+ }
- llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
- unsigned idx = 0;
+ if (ClsName == NSExceptionII) {
- // raise:format:
- II.push_back(&Ctx.Idents.get("raise"));
- II.push_back(&Ctx.Idents.get("format"));
- NSExceptionInstanceRaiseSelectors[idx++] =
- Ctx.Selectors.getSelector(II.size(), &II[0]);
+ enum { NUM_RAISE_SELECTORS = 2 };
- // raise:format::arguments:
- II.push_back(&Ctx.Idents.get("arguments"));
- NSExceptionInstanceRaiseSelectors[idx++] =
- Ctx.Selectors.getSelector(II.size(), &II[0]);
- }
+ // Lazily create a cache of the selectors.
- for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
- if (S == NSExceptionInstanceRaiseSelectors[i]) {
- RaisesException = true; break;
- }
- }
- }
+ if (!NSExceptionInstanceRaiseSelectors) {
- // Check for any arguments that are uninitialized/undefined.
+ ASTContext& Ctx = getContext();
- for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end();
- I != E; ++I) {
+ NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS];
- if (state->getSVal(*I).isUndef()) {
+ llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
+ unsigned idx = 0;
- // Generate an error node for passing an uninitialized/undefined value
- // as an argument to a message expression. This node is a sink.
- ExplodedNode* N = Builder->generateNode(ME, state, Pred);
+ // raise:format:
+ II.push_back(&Ctx.Idents.get("raise"));
+ II.push_back(&Ctx.Idents.get("format"));
+ NSExceptionInstanceRaiseSelectors[idx++] =
+ Ctx.Selectors.getSelector(II.size(), &II[0]);
- if (N) {
- N->markAsSink();
- MsgExprUndefArgs[N] = *I;
- }
+ // raise:format::arguments:
+ II.push_back(&Ctx.Idents.get("arguments"));
+ NSExceptionInstanceRaiseSelectors[idx++] =
+ Ctx.Selectors.getSelector(II.size(), &II[0]);
+ }
- return;
+ for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
+ if (S == NSExceptionInstanceRaiseSelectors[i]) {
+ RaisesException = true; break;
+ }
+ }
}
- }
- // Handle previsits checks.
- ExplodedNodeSet Src, DstTmp;
- Src.Add(Pred);
- CheckerVisit(ME, DstTmp, Src, 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;
+ // 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.
- unsigned size = Dst.size();
- SaveOr OldHasGen(Builder->HasGeneratedNode);
-
- for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
- DI!=DE; ++DI)
- EvalObjCMessageExpr(Dst, ME, *DI);
+ // Dispatch to plug-in transfer function.
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
+ EvalObjCMessageExpr(Dst, ME, Pred);
+ }
// Handle the case where no nodes where generated. Auto-generate that
// contains the updated state if we aren't generating sinks.
if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode)
- MakeNode(Dst, ME, Pred, state);
+ MakeNode(Dst, ME, Pred, GetState(Pred));
}
//===----------------------------------------------------------------------===//
@@ -2157,7 +2117,7 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
namespace {
// This class is used by VisitInitListExpr as an item in a worklist
// for processing the values contained in an InitListExpr.
-class VISIBILITY_HIDDEN InitListWLItem {
+class InitListWLItem {
public:
llvm::ImmutableList<SVal> Vals;
ExplodedNode* N;
@@ -2246,8 +2206,6 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred,
return;
}
-
- printf("InitListExpr type = %s\n", T.getAsString().c_str());
assert(0 && "unprocessed InitListExpr type");
}
@@ -2689,6 +2647,8 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
else
Visit(LHS, Pred, Tmp1);
+ ExplodedNodeSet Tmp3;
+
for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) {
SVal LeftV = (*I1)->getState()->getSVal(LHS);
ExplodedNodeSet Tmp2;
@@ -2723,7 +2683,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
// Simulate the effects of a "store": bind the value of the RHS
// to the L-Value represented by the LHS.
- EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV, RightV);
+ EvalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV, RightV);
continue;
}
@@ -2735,28 +2695,17 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
if (Result.isUnknown()) {
if (OldSt != state) {
// Generate a new node if we have already created a new state.
- MakeNode(Dst, B, *I2, state);
+ MakeNode(Tmp3, B, *I2, state);
}
else
- Dst.Add(*I2);
+ Tmp3.Add(*I2);
continue;
}
state = state->BindExpr(B, Result);
- if (Result.isUndef()) {
- // The operands were *not* undefined, but the result is undefined.
- // This is a special node that should be flagged as an error.
- if (ExplodedNode *UndefNode = Builder->generateNode(B, state, *I2)){
- UndefNode->markAsSink();
- UndefResults.insert(UndefNode);
- }
- continue;
- }
-
- // Otherwise, create a new node.
- MakeNode(Dst, B, *I2, state);
+ MakeNode(Tmp3, B, *I2, state);
continue;
}
@@ -2809,15 +2758,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
RightV, CTy),
state, B->getType(), CTy);
- if (Result.isUndef()) {
- // The operands were not undefined, but the result is undefined.
- if (ExplodedNode* UndefNode = Builder->generateNode(B, state, *I3)) {
- UndefNode->markAsSink();
- UndefResults.insert(UndefNode);
- }
- continue;
- }
-
// EXPERIMENTAL: "Conjured" symbols.
// FIXME: Handle structs.
@@ -2844,11 +2784,13 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
llvm::tie(state, LHSVal) = SVator.EvalCast(Result, state, LTy, CTy);
}
- EvalStore(Dst, B, LHS, *I3, state->BindExpr(B, Result),
+ EvalStore(Tmp3, B, LHS, *I3, state->BindExpr(B, Result),
location, LHSVal);
}
}
}
+
+ CheckerVisit(B, Dst, Tmp3, false);
}
//===----------------------------------------------------------------------===//
@@ -2870,8 +2812,11 @@ static SourceManager* GraphPrintSourceManager;
namespace llvm {
template<>
-struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
+struct DOTGraphTraits<ExplodedNode*> :
public DefaultDOTGraphTraits {
+
+ DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
+
// FIXME: Since we do not cache error nodes in GRExprEngine now, this does not
// work.
static std::string getNodeAttributes(const ExplodedNode* N, void*) {
@@ -2888,15 +2833,14 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
GraphPrintCheckerState->isBadCall(N) ||
GraphPrintCheckerState->isUndefArg(N))
return "color=\"red\",style=\"filled\"";
-#endif
if (GraphPrintCheckerState->isNoReturnCall(N))
return "color=\"blue\",style=\"filled\"";
-
+#endif
return "";
}
- static std::string getNodeLabel(const ExplodedNode* N, void*,bool ShortNames){
+ static std::string getNodeLabel(const ExplodedNode* N, void*){
std::string sbuf;
llvm::raw_string_ostream Out(sbuf);
diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.cpp b/lib/Analysis/GRExprEngineExperimentalChecks.cpp
index 2fb7e9f..33479b0 100644
--- a/lib/Analysis/GRExprEngineExperimentalChecks.cpp
+++ b/lib/Analysis/GRExprEngineExperimentalChecks.cpp
@@ -31,6 +31,8 @@ void clang::RegisterExperimentalInternalChecks(GRExprEngine &Eng) {
// Note that this must be registered after ReturnStackAddresEngsChecker.
RegisterReturnPointerRangeChecker(Eng);
+
+ RegisterFixedAddressChecker(Eng);
RegisterPointerSubChecker(Eng);
RegisterPointerArithChecker(Eng);
RegisterCastToStructChecker(Eng);
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp
deleted file mode 100644
index d0f60fd..0000000
--- a/lib/Analysis/GRExprEngineInternalChecks.cpp
+++ /dev/null
@@ -1,400 +0,0 @@
-//=-- GRExprEngineInternalChecks.cpp - Builtin GRExprEngine Checks---*- C++ -*-=
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the BugType classes used by GRExprEngine to report
-// bugs derived from builtin checks in the path-sensitive engine.
-//
-//===----------------------------------------------------------------------===//
-
-#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Basic/SourceManager.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang;
-using namespace clang::bugreporter;
-
-//===----------------------------------------------------------------------===//
-// Utility functions.
-//===----------------------------------------------------------------------===//
-
-template <typename ITERATOR> inline
-ExplodedNode* GetNode(ITERATOR I) {
- return *I;
-}
-
-template <> inline
-ExplodedNode* GetNode(GRExprEngine::undef_arg_iterator I) {
- return I->first;
-}
-
-//===----------------------------------------------------------------------===//
-// Bug Descriptions.
-//===----------------------------------------------------------------------===//
-namespace clang {
-class BuiltinBugReport : public RangedBugReport {
-public:
- BuiltinBugReport(BugType& bt, const char* desc,
- ExplodedNode *n)
- : RangedBugReport(bt, desc, n) {}
-
- BuiltinBugReport(BugType& bt, const char *shortDesc, const char *desc,
- ExplodedNode *n)
- : RangedBugReport(bt, shortDesc, desc, n) {}
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N);
-};
-
-void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N) {
- static_cast<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this);
-}
-
-template <typename ITER>
-void BuiltinBug::Emit(BugReporter& BR, ITER I, ITER E) {
- for (; I != E; ++I) BR.EmitReport(new BuiltinBugReport(*this, desc.c_str(),
- GetNode(I)));
-}
-
-class VISIBILITY_HIDDEN NilReceiverStructRet : public BuiltinBug {
-public:
- NilReceiverStructRet(GRExprEngine* eng) :
- BuiltinBug(eng, "'nil' receiver with struct return type") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- for (GRExprEngine::nil_receiver_struct_ret_iterator
- I=Eng.nil_receiver_struct_ret_begin(),
- E=Eng.nil_receiver_struct_ret_end(); I!=E; ++I) {
-
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
- PostStmt P = cast<PostStmt>((*I)->getLocation());
- const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt());
- os << "The receiver in the message expression is 'nil' and results in the"
- " returned value (of type '"
- << ME->getType().getAsString()
- << "') to be garbage or otherwise undefined";
-
- BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I);
- R->addRange(ME->getReceiver()->getSourceRange());
- BR.EmitReport(R);
- }
- }
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
- }
-};
-
-class VISIBILITY_HIDDEN NilReceiverLargerThanVoidPtrRet : public BuiltinBug {
-public:
- NilReceiverLargerThanVoidPtrRet(GRExprEngine* eng) :
- BuiltinBug(eng,
- "'nil' receiver with return type larger than sizeof(void *)") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- for (GRExprEngine::nil_receiver_larger_than_voidptr_ret_iterator
- I=Eng.nil_receiver_larger_than_voidptr_ret_begin(),
- E=Eng.nil_receiver_larger_than_voidptr_ret_end(); I!=E; ++I) {
-
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
- PostStmt P = cast<PostStmt>((*I)->getLocation());
- const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt());
- os << "The receiver in the message expression is 'nil' and results in the"
- " returned value (of type '"
- << ME->getType().getAsString()
- << "' and of size "
- << Eng.getContext().getTypeSize(ME->getType()) / 8
- << " bytes) to be garbage or otherwise undefined";
-
- BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I);
- R->addRange(ME->getReceiver()->getSourceRange());
- BR.EmitReport(R);
- }
- }
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
- }
-};
-
-class VISIBILITY_HIDDEN UndefResult : public BuiltinBug {
-public:
- UndefResult(GRExprEngine* eng)
- : BuiltinBug(eng,"Undefined or garbage result",
- "Result of operation is garbage or undefined") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- for (GRExprEngine::undef_result_iterator I=Eng.undef_results_begin(),
- E = Eng.undef_results_end(); I!=E; ++I) {
-
- ExplodedNode *N = *I;
- const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
- BuiltinBugReport *report = NULL;
-
- if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
- llvm::SmallString<256> sbuf;
- llvm::raw_svector_ostream OS(sbuf);
- const GRState *ST = N->getState();
- const Expr *Ex = NULL;
- bool isLeft = true;
-
- if (ST->getSVal(B->getLHS()).isUndef()) {
- Ex = B->getLHS()->IgnoreParenCasts();
- isLeft = true;
- }
- else if (ST->getSVal(B->getRHS()).isUndef()) {
- Ex = B->getRHS()->IgnoreParenCasts();
- isLeft = false;
- }
-
- if (Ex) {
- OS << "The " << (isLeft ? "left" : "right")
- << " operand of '"
- << BinaryOperator::getOpcodeStr(B->getOpcode())
- << "' is a garbage value";
- }
- else {
- // Neither operand was undefined, but the result is undefined.
- OS << "The result of the '"
- << BinaryOperator::getOpcodeStr(B->getOpcode())
- << "' expression is undefined";
- }
-
- // FIXME: Use StringRefs to pass string information.
- report = new BuiltinBugReport(*this, OS.str().str().c_str(), N);
- if (Ex) report->addRange(Ex->getSourceRange());
- }
- else {
- report = new BuiltinBugReport(*this,
- "Expression evaluates to an uninitialized"
- " or undefined value", N);
- }
-
- BR.EmitReport(report);
- }
- }
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
-
- const Stmt *S = N->getLocationAs<StmtPoint>()->getStmt();
- const Stmt *X = S;
-
- if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
- const GRState *ST = N->getState();
- if (ST->getSVal(B->getLHS()).isUndef())
- X = B->getLHS();
- else if (ST->getSVal(B->getRHS()).isUndef())
- X = B->getRHS();
- }
-
- registerTrackNullOrUndefValue(BRC, X, N);
- }
-};
-
-class VISIBILITY_HIDDEN ArgReport : public BuiltinBugReport {
- const Stmt *Arg;
-public:
- ArgReport(BugType& bt, const char* desc, ExplodedNode *n,
- const Stmt *arg)
- : BuiltinBugReport(bt, desc, n), Arg(arg) {}
-
- ArgReport(BugType& bt, const char *shortDesc, const char *desc,
- ExplodedNode *n, const Stmt *arg)
- : BuiltinBugReport(bt, shortDesc, desc, n), Arg(arg) {}
-
- const Stmt *getArg() const { return Arg; }
-};
-
-class VISIBILITY_HIDDEN BadArg : public BuiltinBug {
-public:
- BadArg(GRExprEngine* eng=0) : BuiltinBug(eng,"Uninitialized argument",
- "Pass-by-value argument in function call is undefined") {}
-
- BadArg(GRExprEngine* eng, const char* d)
- : BuiltinBug(eng,"Uninitialized argument", d) {}
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
- N);
- }
-};
-
-class VISIBILITY_HIDDEN BadMsgExprArg : public BadArg {
-public:
- BadMsgExprArg(GRExprEngine* eng)
- : BadArg(eng,"Pass-by-value argument in message expression is undefined"){}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- for (GRExprEngine::UndefArgsTy::iterator I=Eng.msg_expr_undef_arg_begin(),
- E = Eng.msg_expr_undef_arg_end(); I!=E; ++I) {
- // Generate a report for this bug.
- ArgReport *report = new ArgReport(*this, desc.c_str(), I->first,
- I->second);
- report->addRange(I->second->getSourceRange());
- BR.EmitReport(report);
- }
- }
-};
-
-class VISIBILITY_HIDDEN BadReceiver : public BuiltinBug {
-public:
- BadReceiver(GRExprEngine* eng)
- : BuiltinBug(eng,"Uninitialized receiver",
- "Receiver in message expression is an uninitialized value") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- for (GRExprEngine::ErrorNodes::iterator I=Eng.undef_receivers_begin(),
- End = Eng.undef_receivers_end(); I!=End; ++I) {
-
- // Generate a report for this bug.
- BuiltinBugReport *report = new BuiltinBugReport(*this, desc.c_str(), *I);
- ExplodedNode* N = *I;
- const Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
- const Expr* E = cast<ObjCMessageExpr>(S)->getReceiver();
- assert (E && "Receiver cannot be NULL");
- report->addRange(E->getSourceRange());
- BR.EmitReport(report);
- }
- }
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
- }
-};
-
-class VISIBILITY_HIDDEN UndefBranch : public BuiltinBug {
- struct VISIBILITY_HIDDEN FindUndefExpr {
- GRStateManager& VM;
- const GRState* St;
-
- FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {}
-
- Expr* FindExpr(Expr* Ex) {
- if (!MatchesCriteria(Ex))
- return 0;
-
- for (Stmt::child_iterator I=Ex->child_begin(), E=Ex->child_end();I!=E;++I)
- if (Expr* ExI = dyn_cast_or_null<Expr>(*I)) {
- Expr* E2 = FindExpr(ExI);
- if (E2) return E2;
- }
-
- return Ex;
- }
-
- bool MatchesCriteria(Expr* Ex) { return St->getSVal(Ex).isUndef(); }
- };
-
-public:
- UndefBranch(GRExprEngine *eng)
- : BuiltinBug(eng,"Use of garbage value",
- "Branch condition evaluates to an undefined or garbage value")
- {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- for (GRExprEngine::undef_branch_iterator I=Eng.undef_branches_begin(),
- E=Eng.undef_branches_end(); I!=E; ++I) {
-
- // What's going on here: we want to highlight the subexpression of the
- // condition that is the most likely source of the "uninitialized
- // branch condition." We do a recursive walk of the condition's
- // subexpressions and roughly look for the most nested subexpression
- // that binds to Undefined. We then highlight that expression's range.
- BlockEdge B = cast<BlockEdge>((*I)->getLocation());
- Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition());
- assert (Ex && "Block must have a terminator.");
-
- // Get the predecessor node and check if is a PostStmt with the Stmt
- // being the terminator condition. We want to inspect the state
- // of that node instead because it will contain main information about
- // the subexpressions.
- assert (!(*I)->pred_empty());
-
- // Note: any predecessor will do. They should have identical state,
- // since all the BlockEdge did was act as an error sink since the value
- // had to already be undefined.
- ExplodedNode *N = *(*I)->pred_begin();
- ProgramPoint P = N->getLocation();
- const GRState* St = (*I)->getState();
-
- if (PostStmt* PS = dyn_cast<PostStmt>(&P))
- if (PS->getStmt() == Ex)
- St = N->getState();
-
- FindUndefExpr FindIt(Eng.getStateManager(), St);
- Ex = FindIt.FindExpr(Ex);
-
- ArgReport *R = new ArgReport(*this, desc.c_str(), *I, Ex);
- R->addRange(Ex->getSourceRange());
- BR.EmitReport(R);
- }
- }
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
- N);
- }
-};
-
-} // end clang namespace
-
-//===----------------------------------------------------------------------===//
-// Check registration.
-//===----------------------------------------------------------------------===//
-
-void GRExprEngine::RegisterInternalChecks() {
- // Register internal "built-in" BugTypes with the BugReporter. These BugTypes
- // are different than what probably many checks will do since they don't
- // create BugReports on-the-fly but instead wait until GRExprEngine finishes
- // analyzing a function. Generation of BugReport objects is done via a call
- // to 'FlushReports' from BugReporter.
- BR.Register(new UndefBranch(this));
- BR.Register(new UndefResult(this));
- BR.Register(new BadMsgExprArg(this));
- BR.Register(new BadReceiver(this));
- BR.Register(new NilReceiverStructRet(this));
- BR.Register(new NilReceiverLargerThanVoidPtrRet(this));
-
- // The following checks do not need to have their associated BugTypes
- // explicitly registered with the BugReporter. If they issue any BugReports,
- // their associated BugType will get registered with the BugReporter
- // automatically. Note that the check itself is owned by the GRExprEngine
- // object.
- registerCheck(new UndefinedAssignmentChecker());
-
- RegisterAttrNonNullChecker(*this);
- RegisterUndefinedArgChecker(*this);
- RegisterBadCallChecker(*this);
- RegisterDereferenceChecker(*this);
- RegisterVLASizeChecker(*this);
- RegisterDivZeroChecker(*this);
- RegisterReturnStackAddressChecker(*this);
- RegisterReturnUndefChecker(*this);
- RegisterFixedAddressChecker(*this);
- RegisterUndefinedArraySubscriptChecker(*this);
-}
diff --git a/lib/Analysis/GRExprEngineInternalChecks.h b/lib/Analysis/GRExprEngineInternalChecks.h
index a9077bf..5b7a757 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.h
+++ b/lib/Analysis/GRExprEngineInternalChecks.h
@@ -20,7 +20,6 @@ namespace clang {
class GRExprEngine;
void RegisterAttrNonNullChecker(GRExprEngine &Eng);
-void RegisterBadCallChecker(GRExprEngine &Eng);
void RegisterDereferenceChecker(GRExprEngine &Eng);
void RegisterDivZeroChecker(GRExprEngine &Eng);
void RegisterReturnPointerRangeChecker(GRExprEngine &Eng);
@@ -31,9 +30,12 @@ void RegisterPointerSubChecker(GRExprEngine &Eng);
void RegisterPointerArithChecker(GRExprEngine &Eng);
void RegisterFixedAddressChecker(GRExprEngine &Eng);
void RegisterCastToStructChecker(GRExprEngine &Eng);
-void RegisterUndefinedArgChecker(GRExprEngine &Eng);
+void RegisterCallAndMessageChecker(GRExprEngine &Eng);
void RegisterArrayBoundChecker(GRExprEngine &Eng);
void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng);
+void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng);
+void RegisterUndefBranchChecker(GRExprEngine &Eng);
+void RegisterUndefResultChecker(GRExprEngine &Eng);
} // end clang namespace
#endif
diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp
index 23ee0b2..a56859d 100644
--- a/lib/Analysis/GRState.cpp
+++ b/lib/Analysis/GRState.cpp
@@ -232,7 +232,7 @@ const GRState* GRStateManager::addGDM(const GRState* St, void* Key, void* Data){
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN ScanReachableSymbols : public SubRegionMap::Visitor {
+class ScanReachableSymbols : public SubRegionMap::Visitor {
typedef llvm::DenseSet<const MemRegion*> VisitedRegionsTy;
VisitedRegionsTy visited;
@@ -308,6 +308,27 @@ bool GRState::scanReachableSymbols(SVal val, SymbolVisitor& visitor) const {
return S.scan(val);
}
+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;
+ }
+ return false;
+}
+
+bool GRState::scanReachableSymbols(const MemRegion * const *I,
+ const MemRegion * const *E,
+ SymbolVisitor &visitor) const {
+ ScanReachableSymbols S(this, visitor);
+ for ( ; I != E; ++I) {
+ if (S.scan(*I))
+ return true;
+ }
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Queries.
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index 2510445..84e268f 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -19,9 +19,9 @@
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
#include "clang/Analysis/Support/SaveAndRestore.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -38,7 +38,7 @@ static const bool Dead = false;
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN RegisterDecls
+class RegisterDecls
: public CFGRecStmtDeclVisitor<RegisterDecls> {
LiveVariables::AnalysisDataTy& AD;
@@ -77,10 +77,12 @@ public:
};
} // end anonymous namespace
-LiveVariables::LiveVariables(ASTContext& Ctx, CFG& cfg) {
+LiveVariables::LiveVariables(AnalysisContext &AC) {
// Register all referenced VarDecls.
+ CFG &cfg = *AC.getCFG();
getAnalysisData().setCFG(cfg);
- getAnalysisData().setContext(Ctx);
+ getAnalysisData().setContext(AC.getASTContext());
+ getAnalysisData().AC = &AC;
RegisterDecls R(getAnalysisData());
cfg.VisitBlockStmts(R);
@@ -92,7 +94,7 @@ LiveVariables::LiveVariables(ASTContext& Ctx, CFG& cfg) {
namespace {
-class VISIBILITY_HIDDEN TransferFuncs : public CFGRecStmtVisitor<TransferFuncs>{
+class TransferFuncs : public CFGRecStmtVisitor<TransferFuncs>{
LiveVariables::AnalysisDataTy& AD;
LiveVariables::ValTy LiveState;
public:
@@ -103,6 +105,7 @@ public:
void VisitDeclRefExpr(DeclRefExpr* DR);
void VisitBinaryOperator(BinaryOperator* B);
+ void VisitBlockExpr(BlockExpr *B);
void VisitAssign(BinaryOperator* B);
void VisitDeclStmt(DeclStmt* DS);
void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S);
@@ -153,7 +156,17 @@ void TransferFuncs::VisitTerminator(CFGBlock* B) {
void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
if (VarDecl* V = dyn_cast<VarDecl>(DR->getDecl()))
- LiveState(V,AD) = Alive;
+ LiveState(V, AD) = Alive;
+}
+
+void TransferFuncs::VisitBlockExpr(BlockExpr *BE) {
+ AnalysisContext::referenced_decls_iterator I, E;
+ llvm::tie(I, E) = AD.AC->getReferencedBlockVars(BE->getBlockDecl());
+ for ( ; I != E ; ++I) {
+ DeclBitVector_Types::Idx i = AD.getIdx(*I);
+ if (i.isValid())
+ LiveState.getBit(i) = Alive;
+ }
}
void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp
index 93e7083..204c7b3 100644
--- a/lib/Analysis/MallocChecker.cpp
+++ b/lib/Analysis/MallocChecker.cpp
@@ -46,9 +46,9 @@ struct RefState {
}
};
-class VISIBILITY_HIDDEN RegionState {};
+class RegionState {};
-class VISIBILITY_HIDDEN MallocChecker : public CheckerVisitor<MallocChecker> {
+class MallocChecker : public CheckerVisitor<MallocChecker> {
BuiltinBug *BT_DoubleFree;
BuiltinBug *BT_Leak;
IdentifierInfo *II_malloc;
@@ -65,7 +65,7 @@ private:
void MallocMem(CheckerContext &C, const CallExpr *CE);
void FreeMem(CheckerContext &C, const CallExpr *CE);
};
-}
+} // end anonymous namespace
namespace clang {
template <>
@@ -112,9 +112,7 @@ void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
SymbolRef Sym = CallVal.getAsLocSymbol();
assert(Sym);
// Set the symbol's state to Allocated.
- const GRState *AllocState
- = state->set<RegionState>(Sym, RefState::getAllocated(CE));
- C.addTransition(C.GenerateNode(CE, AllocState));
+ C.addTransition(state->set<RegionState>(Sym, RefState::getAllocated(CE)));
}
void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
@@ -128,7 +126,7 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
// Check double free.
if (RS->isReleased()) {
- ExplodedNode *N = C.GenerateNode(CE, true);
+ ExplodedNode *N = C.GenerateSink();
if (N) {
if (!BT_DoubleFree)
BT_DoubleFree = new BuiltinBug("Double free",
@@ -144,7 +142,7 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
// Normal free.
const GRState *FreedState
= state->set<RegionState>(Sym, RefState::getReleased(CE));
- C.addTransition(C.GenerateNode(CE, FreedState));
+ C.addTransition(FreedState);
}
void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
@@ -158,7 +156,7 @@ void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
return;
if (RS->isAllocated()) {
- ExplodedNode *N = C.GenerateNode(S, true);
+ ExplodedNode *N = C.GenerateSink();
if (N) {
if (!BT_Leak)
BT_Leak = new BuiltinBug("Memory leak",
@@ -173,6 +171,7 @@ void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
void MallocChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
GRExprEngine &Eng) {
+ SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
const GRState *state = B.getState();
typedef llvm::ImmutableMap<SymbolRef, RefState> SymMap;
SymMap M = state->get<RegionState>();
@@ -212,7 +211,5 @@ void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
if (RS->isAllocated())
state = state->set<RegionState>(Sym, RefState::getEscaped(S));
- ExplodedNode *N = C.GenerateNode(S, state);
- if (N)
- C.addTransition(N);
+ C.addTransition(state);
}
diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp
index 8c0b85c..af8bd16 100644
--- a/lib/Analysis/MemRegion.cpp
+++ b/lib/Analysis/MemRegion.cpp
@@ -17,15 +17,25 @@
#include "clang/Analysis/PathSensitive/MemRegion.h"
#include "clang/Analysis/PathSensitive/ValueManager.h"
#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/AST/StmtVisitor.h"
using namespace clang;
//===----------------------------------------------------------------------===//
-// Basic methods.
+// Object destruction.
//===----------------------------------------------------------------------===//
MemRegion::~MemRegion() {}
+MemRegionManager::~MemRegionManager() {
+ // All regions and their data are BumpPtrAllocated. No need to call
+ // their destructors.
+}
+
+//===----------------------------------------------------------------------===//
+// Basic methods.
+//===----------------------------------------------------------------------===//
+
bool SubRegion::isSubRegionOf(const MemRegion* R) const {
const MemRegion* r = getSuperRegion();
while (r != 0) {
@@ -126,15 +136,39 @@ void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const {
ElementRegion::ProfileRegion(ID, ElementType, Index, superRegion);
}
-void CodeTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const FunctionDecl *FD,
- const MemRegion*) {
- ID.AddInteger(MemRegion::CodeTextRegionKind);
+void FunctionTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const FunctionDecl *FD,
+ const MemRegion*) {
+ ID.AddInteger(MemRegion::FunctionTextRegionKind);
ID.AddPointer(FD);
}
-void CodeTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- CodeTextRegion::ProfileRegion(ID, FD, superRegion);
+void FunctionTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ FunctionTextRegion::ProfileRegion(ID, FD, superRegion);
+}
+
+void BlockTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const BlockDecl *BD, CanQualType,
+ const MemRegion*) {
+ ID.AddInteger(MemRegion::BlockTextRegionKind);
+ ID.AddPointer(BD);
+}
+
+void BlockTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ BlockTextRegion::ProfileRegion(ID, BD, locTy, superRegion);
+}
+
+void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const BlockTextRegion *BC,
+ const LocationContext *LC,
+ const MemRegion *) {
+ ID.AddInteger(MemRegion::BlockDataRegionKind);
+ ID.AddPointer(BC);
+ ID.AddPointer(LC);
+}
+
+void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ BlockDataRegion::ProfileRegion(ID, BC, LC, NULL);
}
//===----------------------------------------------------------------------===//
@@ -160,10 +194,19 @@ void AllocaRegion::dumpToStream(llvm::raw_ostream& os) const {
os << "alloca{" << (void*) Ex << ',' << Cnt << '}';
}
-void CodeTextRegion::dumpToStream(llvm::raw_ostream& os) const {
+void FunctionTextRegion::dumpToStream(llvm::raw_ostream& os) const {
os << "code{" << getDecl()->getDeclName().getAsString() << '}';
}
+void BlockTextRegion::dumpToStream(llvm::raw_ostream& os) const {
+ os << "block_code{" << (void*) this << '}';
+}
+
+void BlockDataRegion::dumpToStream(llvm::raw_ostream& os) const {
+ os << "block_data{" << BC << '}';
+}
+
+
void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const {
// FIXME: More elaborate pretty-printing.
os << "{ " << (void*) CL << " }";
@@ -259,6 +302,18 @@ VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
return getRegion<VarRegion>(D, LC);
}
+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();
+
+ return getSubRegion<BlockDataRegion>(BC, LC, getStackRegion());
+}
+
CompoundLiteralRegion*
MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) {
return getRegion<CompoundLiteralRegion>(CL);
@@ -287,10 +342,17 @@ MemRegionManager::getElementRegion(QualType elementType, SVal Idx,
return R;
}
-CodeTextRegion *MemRegionManager::getCodeTextRegion(const FunctionDecl *FD) {
- return getRegion<CodeTextRegion>(FD);
+FunctionTextRegion *
+MemRegionManager::getFunctionTextRegion(const FunctionDecl *FD) {
+ return getRegion<FunctionTextRegion>(FD);
+}
+
+BlockTextRegion *MemRegionManager::getBlockTextRegion(const BlockDecl *BD,
+ CanQualType locTy) {
+ return getRegion<BlockTextRegion>(BD, locTy);
}
+
/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
SymbolicRegion* MemRegionManager::getSymbolicRegion(SymbolRef sym) {
return getRegion<SymbolicRegion>(sym);
@@ -473,3 +535,53 @@ RegionRawOffset ElementRegion::getAsRawOffset() const {
return RegionRawOffset(superR, offset);
}
+//===----------------------------------------------------------------------===//
+// BlockDataRegion
+//===----------------------------------------------------------------------===//
+
+void BlockDataRegion::LazyInitializeReferencedVars() {
+ if (ReferencedVars)
+ return;
+
+ AnalysisContext *AC = LC->getAnalysisContext();
+ AnalysisContext::referenced_decls_iterator I, E;
+ llvm::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl());
+
+ if (I == E) {
+ ReferencedVars = (void*) 0x1;
+ return;
+ }
+
+ MemRegionManager &MemMgr = *getMemRegionManager();
+ llvm::BumpPtrAllocator &A = MemMgr.getAllocator();
+ BumpVectorContext BC(A);
+
+ typedef BumpVector<const MemRegion*> VarVec;
+ VarVec *BV = (VarVec*) A.Allocate<VarVec>();
+ new (BV) VarVec(BC, (E - I) / sizeof(*I));
+
+ for ( ; I != E; ++I)
+ BV->push_back(MemMgr.getVarRegion(*I, LC), BC);
+
+ ReferencedVars = BV;
+}
+
+BlockDataRegion::referenced_vars_iterator
+BlockDataRegion::referenced_vars_begin() const {
+ const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
+
+ BumpVector<const MemRegion*> *Vec =
+ static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
+
+ return Vec == (void*) 0x1 ? NULL : Vec->begin();
+}
+
+BlockDataRegion::referenced_vars_iterator
+BlockDataRegion::referenced_vars_end() const {
+ const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
+
+ BumpVector<const MemRegion*> *Vec =
+ static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
+
+ return Vec == (void*) 0x1 ? NULL : Vec->end();
+}
diff --git a/lib/Analysis/NSAutoreleasePoolChecker.cpp b/lib/Analysis/NSAutoreleasePoolChecker.cpp
index e0a8d0d..2ff0487 100644
--- a/lib/Analysis/NSAutoreleasePoolChecker.cpp
+++ b/lib/Analysis/NSAutoreleasePoolChecker.cpp
@@ -19,14 +19,13 @@
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "BasicObjCFoundationChecks.h"
-#include "llvm/Support/Compiler.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Decl.h"
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN NSAutoreleasePoolChecker
+class NSAutoreleasePoolChecker
: public CheckerVisitor<NSAutoreleasePoolChecker> {
Selector releaseS;
@@ -65,6 +64,9 @@ NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
// the type of the expression.
const ObjCObjectPointerType* PT =
receiver->getType()->getAs<ObjCObjectPointerType>();
+
+ if (!PT)
+ return;
const ObjCInterfaceDecl* OD = PT->getInterfaceDecl();
if (!OD)
return;
diff --git a/lib/Analysis/NSErrorChecker.cpp b/lib/Analysis/NSErrorChecker.cpp
index 93b617b..e3cf57f 100644
--- a/lib/Analysis/NSErrorChecker.cpp
+++ b/lib/Analysis/NSErrorChecker.cpp
@@ -20,7 +20,6 @@
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h"
#include "BasicObjCFoundationChecks.h"
-#include "llvm/Support/Compiler.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Decl.h"
#include "llvm/ADT/SmallVector.h"
@@ -28,7 +27,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN NSErrorChecker : public BugType {
+class NSErrorChecker : public BugType {
const Decl &CodeDecl;
const bool isNSErrorWarning;
IdentifierInfo * const II;
@@ -117,7 +116,7 @@ void NSErrorChecker::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) {
BR.EmitBasicReport(isNSErrorWarning
? "Bad return type when passing NSError**"
: "Bad return type when passing CFError*",
- getCategory().c_str(), os.str().c_str(),
+ getCategory(), os.str(),
CodeDecl.getLocation());
}
@@ -229,7 +228,7 @@ void NSErrorChecker::CheckParamDeref(const VarDecl *Param,
os << Param->getNameAsString() << "' may be null.";
- BugReport *report = new BugReport(*this, os.str().c_str(), *I);
+ BugReport *report = new BugReport(*this, os.str(), *I);
// FIXME: Notable symbols are now part of the report. We should
// add support for notable symbols in BugReport.
// BR.addNotableSymbol(SV->getSymbol());
diff --git a/lib/Analysis/PointerArithChecker.cpp b/lib/Analysis/PointerArithChecker.cpp
index 9382348..370233c 100644
--- a/lib/Analysis/PointerArithChecker.cpp
+++ b/lib/Analysis/PointerArithChecker.cpp
@@ -18,7 +18,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN PointerArithChecker
+class PointerArithChecker
: public CheckerVisitor<PointerArithChecker> {
BuiltinBug *BT;
public:
@@ -53,7 +53,7 @@ void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C,
if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) ||
isa<CompoundLiteralRegion>(LR)) {
- if (ExplodedNode *N = C.GenerateNode(B)) {
+ if (ExplodedNode *N = C.GenerateNode()) {
if (!BT)
BT = new BuiltinBug("Dangerous pointer arithmetic",
"Pointer arithmetic done on non-array variables "
diff --git a/lib/Analysis/PointerSubChecker.cpp b/lib/Analysis/PointerSubChecker.cpp
index 4c7906f..c597a25 100644
--- a/lib/Analysis/PointerSubChecker.cpp
+++ b/lib/Analysis/PointerSubChecker.cpp
@@ -19,7 +19,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN PointerSubChecker
+class PointerSubChecker
: public CheckerVisitor<PointerSubChecker> {
BuiltinBug *BT;
public:
@@ -61,7 +61,7 @@ void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C,
if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
return;
- if (ExplodedNode *N = C.GenerateNode(B)) {
+ if (ExplodedNode *N = C.GenerateNode()) {
if (!BT)
BT = new BuiltinBug("Pointer subtraction",
"Subtraction of two pointers that do not point to "
diff --git a/lib/Analysis/PthreadLockChecker.cpp b/lib/Analysis/PthreadLockChecker.cpp
index 6620661..e95095c 100644
--- a/lib/Analysis/PthreadLockChecker.cpp
+++ b/lib/Analysis/PthreadLockChecker.cpp
@@ -21,7 +21,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN PthreadLockChecker
+class PthreadLockChecker
: public CheckerVisitor<PthreadLockChecker> {
BugType *BT;
public:
@@ -42,7 +42,7 @@ public:
} // end anonymous namespace
// GDM Entry for tracking lock state.
-namespace { class VISIBILITY_HIDDEN LockSet {}; }
+namespace { class LockSet {}; }
namespace clang {
template <> struct GRStateTrait<LockSet> :
public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
@@ -59,8 +59,8 @@ void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
const CallExpr *CE) {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
- const CodeTextRegion *R =
- dyn_cast_or_null<CodeTextRegion>(state->getSVal(Callee).getAsRegion());
+ const FunctionTextRegion *R =
+ dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
if (!R)
return;
diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp
index f5cae69..7330b62 100644
--- a/lib/Analysis/RangeConstraintManager.cpp
+++ b/lib/Analysis/RangeConstraintManager.cpp
@@ -17,7 +17,6 @@
#include "clang/Analysis/PathSensitive/GRStateTrait.h"
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
#include "clang/Analysis/ManagerRegistry.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableSet.h"
@@ -25,14 +24,14 @@
using namespace clang;
-namespace { class VISIBILITY_HIDDEN ConstraintRange {}; }
+namespace { class ConstraintRange {}; }
static int ConstraintRangeIndex = 0;
/// A Range represents the closed range [from, to]. The caller must
/// guarantee that from <= to. Note that Range is immutable, so as not
/// to subvert RangeSet's immutability.
namespace {
-class VISIBILITY_HIDDEN Range : public std::pair<const llvm::APSInt*,
+class Range : public std::pair<const llvm::APSInt*,
const llvm::APSInt*> {
public:
Range(const llvm::APSInt &from, const llvm::APSInt &to)
@@ -59,7 +58,7 @@ public:
};
-class VISIBILITY_HIDDEN RangeTrait : public llvm::ImutContainerInfo<Range> {
+class RangeTrait : public llvm::ImutContainerInfo<Range> {
public:
// When comparing if one Range is less than another, we should compare
// the actual APSInt values instead of their pointers. This keeps the order
@@ -74,7 +73,7 @@ public:
/// RangeSet contains a set of ranges. If the set is empty, then
/// there the value of a symbol is overly constrained and there are no
/// possible values for that symbol.
-class VISIBILITY_HIDDEN RangeSet {
+class RangeSet {
typedef llvm::ImmutableSet<Range, RangeTrait> PrimRangeSet;
PrimRangeSet ranges; // no need to make const, since it is an
// ImmutableSet - this allows default operator=
@@ -232,7 +231,7 @@ struct GRStateTrait<ConstraintRange>
}
namespace {
-class VISIBILITY_HIDDEN RangeConstraintManager : public SimpleConstraintManager{
+class RangeConstraintManager : public SimpleConstraintManager{
RangeSet GetRange(const GRState *state, SymbolRef sym);
public:
RangeConstraintManager() {}
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index ae3fa14..e645172 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -25,7 +25,6 @@
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
@@ -86,10 +85,10 @@ typedef llvm::ImmutableMap<const MemRegion*, BindingVal> RegionBindings;
//===----------------------------------------------------------------------===//
namespace {
-struct VISIBILITY_HIDDEN minimal_features_tag {};
-struct VISIBILITY_HIDDEN maximal_features_tag {};
+struct minimal_features_tag {};
+struct maximal_features_tag {};
-class VISIBILITY_HIDDEN RegionStoreFeatures {
+class RegionStoreFeatures {
bool SupportsFields;
bool SupportsRemaining;
@@ -114,7 +113,7 @@ public:
// MemRegions represent chunks of memory with a size (their "extent"). This
// GDM entry tracks the extents for regions. Extents are in bytes.
//
-namespace { class VISIBILITY_HIDDEN RegionExtents {}; }
+namespace { class RegionExtents {}; }
static int RegionExtentsIndex = 0;
namespace clang {
template<> struct GRStateTrait<RegionExtents>
@@ -141,7 +140,7 @@ static bool IsAnyPointerOrIntptr(QualType ty, ASTContext &Ctx) {
namespace {
-class VISIBILITY_HIDDEN RegionStoreSubRegionMap : public SubRegionMap {
+class RegionStoreSubRegionMap : public SubRegionMap {
typedef llvm::ImmutableSet<const MemRegion*> SetTy;
typedef llvm::DenseMap<const MemRegion*, SetTy> Map;
SetTy::Factory F;
@@ -188,7 +187,7 @@ public:
}
};
-class VISIBILITY_HIDDEN RegionStoreManager : public StoreManager {
+class RegionStoreManager : public StoreManager {
const RegionStoreFeatures Features;
RegionBindings::Factory RBFactory;
@@ -215,6 +214,13 @@ public:
/// getDefaultBinding - Returns an SVal* representing an optional default
/// binding associated with a region and its subregions.
Optional<SVal> getDefaultBinding(RegionBindings B, const MemRegion *R);
+
+ /// setImplicitDefaultValue - Set the default binding for the provided
+ /// MemRegion to the value implicitly defined for compound literals when
+ /// the value is not specified.
+ const GRState *setImplicitDefaultValue(const GRState *state,
+ const MemRegion *R,
+ QualType T);
/// getLValueString - Returns an SVal representing the lvalue of a
/// StringLiteral. Within RegionStore a StringLiteral has an
@@ -705,7 +711,9 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
assert(0 && "Cannot index into a MemSpace");
return UnknownVal();
- case MemRegion::CodeTextRegionKind:
+ case MemRegion::FunctionTextRegionKind:
+ case MemRegion::BlockTextRegionKind:
+ case MemRegion::BlockDataRegionKind:
// Technically this can happen if people do funny things with casts.
return UnknownVal();
@@ -850,7 +858,9 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
case MemRegion::ObjCIvarRegionKind:
return UnknownVal();
- case MemRegion::CodeTextRegionKind:
+ case MemRegion::FunctionTextRegionKind:
+ case MemRegion::BlockTextRegionKind:
+ case MemRegion::BlockDataRegionKind:
// Technically this can happen if people do funny things with casts.
return UnknownVal();
@@ -1437,6 +1447,30 @@ RegionStoreManager::BindCompoundLiteral(const GRState *state,
return Bind(state, loc::MemRegionVal(R), V);
}
+const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state,
+ const MemRegion *R,
+ QualType T) {
+ Store store = state->getStore();
+ RegionBindings B = GetRegionBindings(store);
+ SVal V;
+
+ if (Loc::IsLocType(T))
+ V = ValMgr.makeNull();
+ else if (T->isIntegerType())
+ V = ValMgr.makeZeroVal(T);
+ else if (T->isStructureType() || T->isArrayType()) {
+ // Set the default value to a zero constant when it is a structure
+ // or array. The type doesn't really matter.
+ V = ValMgr.makeZeroVal(ValMgr.getContext().IntTy);
+ }
+ else {
+ return state;
+ }
+
+ B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ return state->makeWithStore(B.getRoot());
+}
+
const GRState *RegionStoreManager::BindArray(const GRState *state,
const TypedRegion* R,
SVal Init) {
@@ -1478,6 +1512,10 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
return CopyLazyBindings(*LCV, state, R);
// Remaining case: explicit compound values.
+
+ if (Init.isUnknown())
+ return setImplicitDefaultValue(state, R, ElementTy);
+
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(Init);
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
uint64_t i = 0;
@@ -1497,17 +1535,10 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
state = Bind(state, ValMgr.makeLoc(ER), *VI);
}
- // If the init list is shorter than the array length, set the array default
- // value.
- if (i < size) {
- if (ElementTy->isIntegerType()) {
- SVal V = ValMgr.makeZeroVal(ElementTy);
- Store store = state->getStore();
- RegionBindings B = GetRegionBindings(store);
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
- state = state->makeWithStore(B.getRoot());
- }
- }
+ // If the init list is shorter than the array length, set the
+ // array default value.
+ if (i < size)
+ state = setImplicitDefaultValue(state, R, ElementTy);
return state;
}
@@ -1619,9 +1650,9 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
llvm::OwningPtr<RegionStoreSubRegionMap>
SubRegions(getRegionStoreSubRegionMap(store));
- // Do a pass over the regions in the store. For VarRegions we check if
- // the variable is still live and if so add it to the list of live roots.
- // For other regions we populate our region backmap.
+ // Do a pass over the regions in the store. For VarRegions we check if
+ // the variable is still live and if so add it to the list of live roots.
+ // For other regions we populate our region backmap.
llvm::SmallVector<const MemRegion*, 10> IntermediateRoots;
// Scan the direct bindings for "intermediate" roots.
@@ -1719,8 +1750,21 @@ tryAgain:
// Mark the symbol for any live SymbolicRegion as "live". This means we
// should continue to track that symbol.
- if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
+ if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
SymReaper.markLive(SymR->getSymbol());
+
+ // For BlockDataRegions, enqueue all VarRegions for that are referenced
+ // 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));
+
+ // No possible data bindings on a BlockDataRegion. Continue to the
+ // next region in the worklist.
+ continue;
+ }
Store store_N = state_N->getStore();
RegionBindings B_N = GetRegionBindings(store_N);
diff --git a/lib/Analysis/ReturnPointerRangeChecker.cpp b/lib/Analysis/ReturnPointerRangeChecker.cpp
index 44887b2..ab0fcab 100644
--- a/lib/Analysis/ReturnPointerRangeChecker.cpp
+++ b/lib/Analysis/ReturnPointerRangeChecker.cpp
@@ -20,7 +20,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN ReturnPointerRangeChecker :
+class ReturnPointerRangeChecker :
public CheckerVisitor<ReturnPointerRangeChecker> {
BuiltinBug *BT;
public:
@@ -70,7 +70,7 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true);
const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false);
if (StOutBound && !StInBound) {
- ExplodedNode *N = C.GenerateNode(RS, StOutBound, true);
+ ExplodedNode *N = C.GenerateSink(StOutBound);
if (!N)
return;
@@ -91,7 +91,6 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
new RangedBugReport(*BT, BT->getDescription(), N);
report->addRange(RetE->getSourceRange());
-
C.EmitReport(report);
}
}
diff --git a/lib/Analysis/ReturnStackAddressChecker.cpp b/lib/Analysis/ReturnStackAddressChecker.cpp
index e4be871..3a6d8a4 100644
--- a/lib/Analysis/ReturnStackAddressChecker.cpp
+++ b/lib/Analysis/ReturnStackAddressChecker.cpp
@@ -17,12 +17,13 @@
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN ReturnStackAddressChecker :
+class ReturnStackAddressChecker :
public CheckerVisitor<ReturnStackAddressChecker> {
BuiltinBug *BT;
public:
@@ -53,7 +54,7 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
if (!R || !R->hasStackStorage())
return;
- ExplodedNode *N = C.GenerateNode(RS, C.getState(), true);
+ ExplodedNode *N = C.GenerateSink();
if (!N)
return;
@@ -83,6 +84,14 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
<< C.getSourceManager().getInstantiationLineNumber(L)
<< " returned to caller";
}
+ else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
+ const BlockDecl *BD = BR->getCodeRegion()->getDecl();
+ SourceLocation L = BD->getLocStart();
+ range = BD->getSourceRange();
+ os << "Address of stack-allocated block declared on line "
+ << C.getSourceManager().getInstantiationLineNumber(L)
+ << " returned to caller";
+ }
else {
os << "Address of stack memory associated with local variable '"
<< R->getString() << "' returned.";
diff --git a/lib/Analysis/ReturnUndefChecker.cpp b/lib/Analysis/ReturnUndefChecker.cpp
index 796c760..7cd7126 100644
--- a/lib/Analysis/ReturnUndefChecker.cpp
+++ b/lib/Analysis/ReturnUndefChecker.cpp
@@ -22,7 +22,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN ReturnUndefChecker :
+class ReturnUndefChecker :
public CheckerVisitor<ReturnUndefChecker> {
BuiltinBug *BT;
public:
@@ -50,7 +50,7 @@ void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C,
if (!C.getState()->getSVal(RetE).isUndef())
return;
- ExplodedNode *N = C.GenerateNode(RS, C.getState(), true);
+ ExplodedNode *N = C.GenerateSink();
if (!N)
return;
diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp
index d5d36e3..9163b27 100644
--- a/lib/Analysis/SVals.cpp
+++ b/lib/Analysis/SVals.cpp
@@ -51,7 +51,7 @@ bool SVal::hasConjuredSymbol() const {
const FunctionDecl *SVal::getAsFunctionDecl() const {
if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(this)) {
const MemRegion* R = X->getRegion();
- if (const CodeTextRegion *CTR = R->getAs<CodeTextRegion>())
+ if (const FunctionTextRegion *CTR = R->getAs<FunctionTextRegion>())
return CTR->getDecl();
}
diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp
index 4487aa9..2afcd3e 100644
--- a/lib/Analysis/SimpleSValuator.cpp
+++ b/lib/Analysis/SimpleSValuator.cpp
@@ -13,12 +13,11 @@
#include "clang/Analysis/PathSensitive/SValuator.h"
#include "clang/Analysis/PathSensitive/GRState.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN SimpleSValuator : public SValuator {
+class SimpleSValuator : public SValuator {
protected:
virtual SVal EvalCastNL(NonLoc val, QualType castTy);
virtual SVal EvalCastL(Loc val, QualType castTy);
diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp
index 2fd72ac..2fd573c 100644
--- a/lib/Analysis/Store.cpp
+++ b/lib/Analysis/Store.cpp
@@ -85,7 +85,10 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
assert(0 && "Invalid region cast");
break;
}
- case MemRegion::CodeTextRegionKind: {
+
+ case MemRegion::FunctionTextRegionKind:
+ case MemRegion::BlockTextRegionKind:
+ case MemRegion::BlockDataRegionKind: {
// CodeTextRegion should be cast to only a function or block pointer type,
// although they can in practice be casted to anything, e.g, void*, char*,
// etc.
@@ -194,12 +197,11 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
/// as another region.
SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
QualType castTy) {
- ASTContext &Ctx = ValMgr.getContext();
-
if (castTy.isNull())
return V;
- assert(Ctx.hasSameUnqualifiedType(castTy, R->getValueType(Ctx)));
+ assert(ValMgr.getContext().hasSameUnqualifiedType(castTy,
+ R->getValueType(ValMgr.getContext())));
return V;
}
diff --git a/lib/Analysis/UndefBranchChecker.cpp b/lib/Analysis/UndefBranchChecker.cpp
new file mode 100644
index 0000000..c739d1a
--- /dev/null
+++ b/lib/Analysis/UndefBranchChecker.cpp
@@ -0,0 +1,117 @@
+//=== UndefBranchChecker.cpp -----------------------------------*- 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 UndefBranchChecker, which checks for undefined branch
+// condition.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/Checker.h"
+
+using namespace clang;
+
+namespace {
+
+class UndefBranchChecker : public Checker {
+ BuiltinBug *BT;
+
+ struct FindUndefExpr {
+ GRStateManager& VM;
+ const GRState* St;
+
+ FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {}
+
+ Expr* FindExpr(Expr* Ex) {
+ if (!MatchesCriteria(Ex))
+ return 0;
+
+ for (Stmt::child_iterator I=Ex->child_begin(), E=Ex->child_end();I!=E;++I)
+ if (Expr* ExI = dyn_cast_or_null<Expr>(*I)) {
+ Expr* E2 = FindExpr(ExI);
+ if (E2) return E2;
+ }
+
+ return Ex;
+ }
+
+ bool MatchesCriteria(Expr* Ex) { return St->getSVal(Ex).isUndef(); }
+ };
+
+public:
+ UndefBranchChecker() : BT(0) {}
+ static void *getTag();
+ void VisitBranchCondition(GRBranchNodeBuilder &Builder, GRExprEngine &Eng,
+ Stmt *Condition, void *tag);
+};
+
+}
+
+void clang::RegisterUndefBranchChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new UndefBranchChecker());
+}
+
+void *UndefBranchChecker::getTag() {
+ static int x;
+ return &x;
+}
+
+void UndefBranchChecker::VisitBranchCondition(GRBranchNodeBuilder &Builder,
+ GRExprEngine &Eng,
+ Stmt *Condition, void *tag) {
+ const GRState *state = Builder.getState();
+ SVal X = state->getSVal(Condition);
+ if (X.isUndef()) {
+ ExplodedNode *N = Builder.generateNode(state, true);
+ if (N) {
+ N->markAsSink();
+ if (!BT)
+ BT = new BuiltinBug("Branch condition evaluates to a garbage value");
+
+ // What's going on here: we want to highlight the subexpression of the
+ // condition that is the most likely source of the "uninitialized
+ // branch condition." We do a recursive walk of the condition's
+ // subexpressions and roughly look for the most nested subexpression
+ // that binds to Undefined. We then highlight that expression's range.
+ BlockEdge B = cast<BlockEdge>(N->getLocation());
+ Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition());
+ assert (Ex && "Block must have a terminator.");
+
+ // Get the predecessor node and check if is a PostStmt with the Stmt
+ // being the terminator condition. We want to inspect the state
+ // of that node instead because it will contain main information about
+ // the subexpressions.
+ assert (!N->pred_empty());
+
+ // Note: any predecessor will do. They should have identical state,
+ // since all the BlockEdge did was act as an error sink since the value
+ // had to already be undefined.
+ ExplodedNode *PrevN = *N->pred_begin();
+ ProgramPoint P = PrevN->getLocation();
+ const GRState* St = N->getState();
+
+ if (PostStmt* PS = dyn_cast<PostStmt>(&P))
+ if (PS->getStmt() == Ex)
+ St = PrevN->getState();
+
+ FindUndefExpr FindIt(Eng.getStateManager(), St);
+ Ex = FindIt.FindExpr(Ex);
+
+ // Emit the bug report.
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getDescription(),N);
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+ R->addRange(Ex->getSourceRange());
+
+ Eng.getBugReporter().EmitReport(R);
+ }
+
+ Builder.markInfeasible(true);
+ Builder.markInfeasible(false);
+ }
+}
diff --git a/lib/Analysis/UndefResultChecker.cpp b/lib/Analysis/UndefResultChecker.cpp
new file mode 100644
index 0000000..acc86dd
--- /dev/null
+++ b/lib/Analysis/UndefResultChecker.cpp
@@ -0,0 +1,86 @@
+//=== UndefResultChecker.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 UndefResultChecker, a builtin check in GRExprEngine that
+// performs checks for undefined results of non-assignment binary operators.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+
+using namespace clang;
+
+namespace {
+class UndefResultChecker
+ : public CheckerVisitor<UndefResultChecker> {
+
+ BugType *BT;
+
+public:
+ UndefResultChecker() : BT(0) {}
+ static void *getTag() { static int tag = 0; return &tag; }
+ void PostVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};
+} // end anonymous namespace
+
+void clang::RegisterUndefResultChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new UndefResultChecker());
+}
+
+void UndefResultChecker::PostVisitBinaryOperator(CheckerContext &C,
+ const BinaryOperator *B) {
+ const GRState *state = C.getState();
+ if (state->getSVal(B).isUndef()) {
+ // Generate an error node.
+ ExplodedNode *N = C.GenerateSink();
+ if (!N)
+ return;
+
+ if (!BT)
+ BT = new BuiltinBug("Result of operation is garbage or undefined");
+
+ llvm::SmallString<256> sbuf;
+ llvm::raw_svector_ostream OS(sbuf);
+ const Expr *Ex = NULL;
+ bool isLeft = true;
+
+ if (state->getSVal(B->getLHS()).isUndef()) {
+ Ex = B->getLHS()->IgnoreParenCasts();
+ isLeft = true;
+ }
+ else if (state->getSVal(B->getRHS()).isUndef()) {
+ Ex = B->getRHS()->IgnoreParenCasts();
+ isLeft = false;
+ }
+
+ if (Ex) {
+ OS << "The " << (isLeft ? "left" : "right")
+ << " operand of '"
+ << BinaryOperator::getOpcodeStr(B->getOpcode())
+ << "' is a garbage value";
+ }
+ else {
+ // Neither operand was undefined, but the result is undefined.
+ OS << "The result of the '"
+ << BinaryOperator::getOpcodeStr(B->getOpcode())
+ << "' expression is undefined";
+ }
+ EnhancedBugReport *report = new EnhancedBugReport(*BT, OS.str(), N);
+ if (Ex) {
+ report->addRange(Ex->getSourceRange());
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+ }
+ else
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, B);
+ C.EmitReport(report);
+ }
+}
diff --git a/lib/Analysis/UndefinedArgChecker.cpp b/lib/Analysis/UndefinedArgChecker.cpp
deleted file mode 100644
index 923a7e1..0000000
--- a/lib/Analysis/UndefinedArgChecker.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-//===--- UndefinedArgChecker.h - Undefined arguments checker ----*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines BadCallChecker, a builtin check in GRExprEngine that performs
-// checks for undefined arguments.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "GRExprEngineInternalChecks.h"
-
-using namespace clang;
-
-namespace {
-class VISIBILITY_HIDDEN UndefinedArgChecker
- : public CheckerVisitor<UndefinedArgChecker> {
- BugType *BT;
-public:
- UndefinedArgChecker() : BT(0) {}
- static void *getTag() {
- static int x = 0;
- return &x;
- }
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-};
-} // end anonymous namespace
-
-void clang::RegisterUndefinedArgChecker(GRExprEngine &Eng) {
- Eng.registerCheck(new UndefinedArgChecker());
-}
-
-void UndefinedArgChecker::PreVisitCallExpr(CheckerContext &C,
- const CallExpr *CE){
- for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
- I != E; ++I) {
- if (C.getState()->getSVal(*I).isUndef()) {
- if (ExplodedNode *N = C.GenerateNode(CE, true)) {
- if (!BT)
- BT = new BuiltinBug("Pass-by-value argument in function call is "
- "undefined");
- // Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
- R->addRange((*I)->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
- C.EmitReport(R);
- }
- }
- }
-}
diff --git a/lib/Analysis/UndefinedArraySubscriptChecker.cpp b/lib/Analysis/UndefinedArraySubscriptChecker.cpp
index 887c775..d6aacaf 100644
--- a/lib/Analysis/UndefinedArraySubscriptChecker.cpp
+++ b/lib/Analysis/UndefinedArraySubscriptChecker.cpp
@@ -19,7 +19,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN UndefinedArraySubscriptChecker
+class UndefinedArraySubscriptChecker
: public CheckerVisitor<UndefinedArraySubscriptChecker> {
BugType *BT;
public:
@@ -41,7 +41,7 @@ void
UndefinedArraySubscriptChecker::PreVisitArraySubscriptExpr(CheckerContext &C,
const ArraySubscriptExpr *A) {
if (C.getState()->getSVal(A->getIdx()).isUndef()) {
- if (ExplodedNode *N = C.GenerateNode(A, true)) {
+ if (ExplodedNode *N = C.GenerateSink()) {
if (!BT)
BT = new BuiltinBug("Array subscript is undefined");
diff --git a/lib/Analysis/UndefinedAssignmentChecker.cpp b/lib/Analysis/UndefinedAssignmentChecker.cpp
index b8062f3..4630b82 100644
--- a/lib/Analysis/UndefinedAssignmentChecker.cpp
+++ b/lib/Analysis/UndefinedAssignmentChecker.cpp
@@ -12,11 +12,29 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h"
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
using namespace clang;
+namespace {
+class UndefinedAssignmentChecker
+ : public CheckerVisitor<UndefinedAssignmentChecker> {
+ BugType *BT;
+public:
+ UndefinedAssignmentChecker() : BT(0) {}
+ static void *getTag();
+ virtual void PreVisitBind(CheckerContext &C, const Stmt *AssignE,
+ const Stmt *StoreE, SVal location,
+ SVal val);
+};
+}
+
+void clang::RegisterUndefinedAssignmentChecker(GRExprEngine &Eng){
+ Eng.registerCheck(new UndefinedAssignmentChecker());
+}
+
void *UndefinedAssignmentChecker::getTag() {
static int x = 0;
return &x;
@@ -30,7 +48,7 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C,
if (!val.isUndef())
return;
- ExplodedNode *N = C.GenerateNode(StoreE, true);
+ ExplodedNode *N = C.GenerateSink();
if (!N)
return;
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 8e7b158..6fa4b53 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -17,7 +17,6 @@
#include "clang/Analysis/AnalysisDiagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -29,7 +28,7 @@ using namespace clang;
namespace {
-class VISIBILITY_HIDDEN RegisterDecls
+class RegisterDecls
: public CFGRecStmtDeclVisitor<RegisterDecls> {
UninitializedValues::AnalysisDataTy& AD;
@@ -52,7 +51,7 @@ void UninitializedValues::InitializeValues(const CFG& cfg) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN TransferFuncs
+class TransferFuncs
: public CFGStmtVisitor<TransferFuncs,bool> {
UninitializedValues::ValTy V;
@@ -269,7 +268,7 @@ namespace {
UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {}
namespace {
-class VISIBILITY_HIDDEN UninitializedValuesChecker
+class UninitializedValuesChecker
: public UninitializedValues::ObserverTy {
ASTContext &Ctx;
diff --git a/lib/Analysis/VLASizeChecker.cpp b/lib/Analysis/VLASizeChecker.cpp
index 799a73e..2690d6f 100644
--- a/lib/Analysis/VLASizeChecker.cpp
+++ b/lib/Analysis/VLASizeChecker.cpp
@@ -20,7 +20,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN VLASizeChecker : public CheckerVisitor<VLASizeChecker> {
+class VLASizeChecker : public CheckerVisitor<VLASizeChecker> {
BugType *BT_zero;
BugType *BT_undef;
@@ -55,7 +55,7 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
if (sizeV.isUndef()) {
// Generate an error node.
- ExplodedNode *N = C.GenerateNode(DS, true);
+ ExplodedNode *N = C.GenerateSink();
if (!N)
return;
@@ -78,7 +78,7 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
llvm::tie(stateNotZero, stateZero) = state->Assume(sizeD);
if (stateZero && !stateNotZero) {
- ExplodedNode* N = C.GenerateNode(DS, stateZero, true);
+ ExplodedNode* N = C.GenerateSink(stateZero);
if (!BT_zero)
BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero "
"size");
@@ -92,6 +92,5 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
}
// From this point on, assume that the size is not zero.
- if (state != stateNotZero)
- C.addTransition(C.GenerateNode(DS, stateNotZero));
+ C.addTransition(stateNotZero);
}
diff --git a/lib/Analysis/ValueManager.cpp b/lib/Analysis/ValueManager.cpp
index fe670e7..22a8211 100644
--- a/lib/Analysis/ValueManager.cpp
+++ b/lib/Analysis/ValueManager.cpp
@@ -138,6 +138,15 @@ ValueManager::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
}
DefinedSVal ValueManager::getFunctionPointer(const FunctionDecl* FD) {
- CodeTextRegion *R = MemMgr.getCodeTextRegion(FD);
+ CodeTextRegion *R = MemMgr.getFunctionTextRegion(FD);
return loc::MemRegionVal(R);
}
+
+DefinedSVal ValueManager::getBlockPointer(const BlockDecl *D,
+ CanQualType locTy,
+ const LocationContext *LC) {
+ BlockTextRegion *BC = MemMgr.getBlockTextRegion(D, locTy);
+ BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, LC);
+ return loc::MemRegionVal(BD);
+}
+
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index b6c4df8..a1f97f4 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -44,6 +44,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
Char16Type = UnsignedShort;
Char32Type = UnsignedInt;
Int64Type = SignedLongLong;
+ SigAtomicType = SignedInt;
FloatFormat = &llvm::APFloat::IEEEsingle;
DoubleFormat = &llvm::APFloat::IEEEdouble;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 07c2bb9..e5a4c43 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -313,6 +313,42 @@ public:
}
};
+// PS3 PPU Target
+template<typename Target>
+class PS3PPUTargetInfo : public OSTargetInfo<Target> {
+protected:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ std::vector<char> &Defs) const {
+ // PS3 PPU defines.
+ Define(Defs, "__PPU__", "1");
+ Define(Defs, "__CELLOS_LV2__", "1");
+ Define(Defs, "__ELF__", "1");
+ }
+public:
+ PS3PPUTargetInfo(const std::string& triple)
+ : OSTargetInfo<Target>(triple) {
+ this->UserLabelPrefix = "";
+ }
+};
+
+// FIXME: Need a real SPU target.
+// PS3 SPU Target
+template<typename Target>
+class PS3SPUTargetInfo : public OSTargetInfo<Target> {
+protected:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ std::vector<char> &Defs) const {
+ // PS3 PPU defines.
+ Define(Defs, "__SPU__", "1");
+ Define(Defs, "__ELF__", "1");
+ }
+public:
+ PS3SPUTargetInfo(const std::string& triple)
+ : OSTargetInfo<Target>(triple) {
+ this->UserLabelPrefix = "";
+ }
+};
+
// AuroraUX target
template<typename Target>
class AuroraUXTargetInfo : public OSTargetInfo<Target> {
@@ -445,6 +481,11 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
// FIXME: Should be controlled by command line option.
Define(Defs, "__LONG_DOUBLE_128__");
+
+ if (Opts.AltiVec) {
+ Define(Defs, "__VEC__", "10206");
+ Define(Defs, "__ALTIVEC__", "1");
+ }
}
@@ -1492,6 +1533,7 @@ namespace {
UIntMaxType = UnsignedLong;
IntPtrType = SignedShort;
PtrDiffType = SignedInt;
+ SigAtomicType = SignedLong;
FloatWidth = 32;
FloatAlign = 32;
DoubleWidth = 32;
@@ -1559,6 +1601,7 @@ namespace {
UIntMaxType = UnsignedLong;
IntPtrType = SignedShort;
PtrDiffType = SignedInt;
+ SigAtomicType = SignedLong;
DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-n8:16";
}
virtual void getTargetDefines(const LangOptions &Opts,
@@ -1990,6 +2033,8 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::ppc64:
if (os == llvm::Triple::Darwin)
return new DarwinTargetInfo<PPC64TargetInfo>(T);
+ else if (os == llvm::Triple::Lv2)
+ return new PS3PPUTargetInfo<PPC64TargetInfo>(T);
return new PPC64TargetInfo(T);
case llvm::Triple::sparc:
@@ -1999,6 +2044,10 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new SolarisSparcV8TargetInfo(T);
return new SparcV8TargetInfo(T);
+ // FIXME: Need a real SPU target.
+ case llvm::Triple::cellspu:
+ return new PS3SPUTargetInfo<PPC64TargetInfo>(T);
+
case llvm::Triple::systemz:
return new SystemZTargetInfo(T);
diff --git a/lib/Basic/TokenKinds.cpp b/lib/Basic/TokenKinds.cpp
index 4afeaf0..8cdc1e3 100644
--- a/lib/Basic/TokenKinds.cpp
+++ b/lib/Basic/TokenKinds.cpp
@@ -30,59 +30,8 @@ const char *tok::getTokenName(enum TokenKind Kind) {
const char *tok::getTokenSimpleSpelling(enum TokenKind Kind) {
switch (Kind) {
- case tok::l_square: return "[";
- case tok::r_square: return "]";
- case tok::l_paren: return "(";
- case tok::r_paren: return ")";
- case tok::l_brace: return "{";
- case tok::r_brace: return "}";
- case tok::period: return ".";
- case tok::ellipsis: return "...";
- case tok::amp: return "&";
- case tok::ampamp: return "&&";
- case tok::ampequal: return "&=";
- case tok::star: return "*";
- case tok::starequal: return "*=";
- case tok::plus: return "+";
- case tok::plusplus: return "++";
- case tok::plusequal: return "+=";
- case tok::minus: return "-";
- case tok::arrow: return "->";
- case tok::minusminus: return "--";
- case tok::minusequal: return "-=";
- case tok::tilde: return "~";
- case tok::exclaim: return "!";
- case tok::exclaimequal: return "!=";
- case tok::slash: return "/";
- case tok::slashequal: return "/=";
- case tok::percent: return "%";
- case tok::percentequal: return "%=";
- case tok::less: return "<";
- case tok::lessless: return "<<";
- case tok::lessequal: return "<=";
- case tok::lesslessequal: return "<<=";
- case tok::greater: return ">";
- case tok::greatergreater: return ">>";
- case tok::greaterequal: return ">=";
- case tok::greatergreaterequal: return ">>=";
- case tok::caret: return "^";
- case tok::caretequal: return "^=";
- case tok::pipe: return "|";
- case tok::pipepipe: return "||";
- case tok::pipeequal: return "|=";
- case tok::question: return "?";
- case tok::colon: return ":";
- case tok::semi: return ";";
- case tok::equal: return "=";
- case tok::equalequal: return "==";
- case tok::comma: return ",";
- case tok::hash: return "#";
- case tok::hashhash: return "##";
- case tok::hashat: return "#@";
- case tok::periodstar: return ".*";
- case tok::arrowstar: return "->*";
- case tok::coloncolon: return "::";
- case tok::at: return "@";
+#define PUNCTUATOR(X,Y) case X: return Y;
+#include "clang/Basic/TokenKinds.def"
default: break;
}
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index bc9eb67..2df779c 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -291,14 +291,14 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
(VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0);
llvm::Value *Loc = LocalDeclMap[VD];
Loc = Builder.CreateStructGEP(Loc, 1, "forwarding");
- Loc = Builder.CreateLoad(Loc, false);
+ Loc = Builder.CreateLoad(Loc);
Builder.CreateStore(Loc, Addr);
++helpersize;
continue;
} else
E = new (getContext()) DeclRefExpr (cast<NamedDecl>(VD),
- VD->getType(), SourceLocation(),
- false, false);
+ VD->getType(),
+ SourceLocation());
}
if (BDRE->isByRef()) {
NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF |
@@ -331,7 +331,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
"block.literal");
Ty = llvm::PointerType::get(Ty, 0);
Loc = Builder.CreateBitCast(Loc, Ty);
- Loc = Builder.CreateLoad(Loc, false);
+ Loc = Builder.CreateLoad(Loc);
// Loc = Builder.CreateBitCast(Loc, Ty);
}
Builder.CreateStore(Loc, Addr);
@@ -494,7 +494,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) {
E->arg_begin(), E->arg_end());
// Load the function.
- llvm::Value *Func = Builder.CreateLoad(FuncPtr, false, "tmp");
+ llvm::Value *Func = Builder.CreateLoad(FuncPtr, "tmp");
QualType ResultType = FnType->getAs<FunctionType>()->getResultType();
@@ -551,9 +551,9 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
const llvm::Type *Ty = PtrStructTy;
Ty = llvm::PointerType::get(Ty, 0);
V = Builder.CreateBitCast(V, Ty);
- V = Builder.CreateLoad(V, false);
+ V = Builder.CreateLoad(V);
V = Builder.CreateStructGEP(V, 1, "forwarding");
- V = Builder.CreateLoad(V, false);
+ V = Builder.CreateLoad(V);
V = Builder.CreateBitCast(V, PtrStructTy);
V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD),
VD->getNameAsString());
@@ -836,7 +836,7 @@ uint64_t BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
0, QualType(PadTy), 0, VarDecl::None);
Expr *E;
E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(),
- SourceLocation(), false, false);
+ SourceLocation());
BlockDeclRefDecls.push_back(E);
}
BlockDeclRefDecls.push_back(BDRE);
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 399b873..be4c27c 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -530,7 +530,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *Ptr = EmitScalarExpr(E->getArg(0));
const llvm::Type *ElTy =
cast<llvm::PointerType>(Ptr->getType())->getElementType();
- Builder.CreateStore(llvm::Constant::getNullValue(ElTy), Ptr, true);
+ llvm::StoreInst *Store =
+ Builder.CreateStore(llvm::Constant::getNullValue(ElTy), Ptr);
+ Store->setVolatile(true);
return RValue::get(0);
}
@@ -813,6 +815,13 @@ 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);
+ return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size());
+ }
}
}
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index b1d30a6..34d1c8d 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -151,8 +151,7 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
"thread safe statics are currently not supported!");
llvm::SmallString<256> GuardVName;
- llvm::raw_svector_ostream GuardVOut(GuardVName);
- mangleGuardVariable(CGM.getMangleContext(), &D, GuardVOut);
+ CGM.getMangleContext().mangleGuardVariable(&D, GuardVName);
// Create the guard variable.
llvm::GlobalValue *GuardV =
@@ -197,11 +196,6 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
assert(MD->isInstance() &&
"Trying to emit a member call expr on a static method!");
- // A call to a trivial destructor requires no code generation.
- if (const CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(MD))
- if (Destructor->isTrivial())
- return RValue::get(0);
-
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
CallArgList Args;
@@ -275,6 +269,14 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
This = BaseLV.getAddress();
}
+ if (MD->isCopyAssignment() && MD->isTrivial()) {
+ // We don't like to generate the trivial copy assignment operator when
+ // it isn't necessary; just produce the proper effect here.
+ llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress();
+ EmitAggregateCopy(This, RHS, CE->getType());
+ return RValue::get(This);
+ }
+
// C++ [class.virtual]p12:
// Explicit qualification with the scope operator (5.1) suppresses the
// virtual call mechanism.
@@ -284,6 +286,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
llvm::Value *Callee;
if (const CXXDestructorDecl *Destructor
= dyn_cast<CXXDestructorDecl>(MD)) {
+ if (Destructor->isTrivial())
+ return RValue::get(0);
if (MD->isVirtual() && !ME->hasQualifier() &&
!canDevirtualizeMemberFunctionCalls(ME->getBase())) {
Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty);
@@ -464,26 +468,31 @@ llvm::Value *CodeGenFunction::LoadCXXThis() {
/// It is assumed that all relevant checks have been made by the caller.
void
CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
- const ConstantArrayType *ArrayTy,
- llvm::Value *ArrayPtr) {
+ const ConstantArrayType *ArrayTy,
+ llvm::Value *ArrayPtr,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) {
+
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
llvm::Value * NumElements =
llvm::ConstantInt::get(SizeTy,
getContext().getConstantArrayElementCount(ArrayTy));
- EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr);
+ EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr, ArgBeg, ArgEnd);
}
void
CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
- llvm::Value *NumElements,
- llvm::Value *ArrayPtr) {
+ llvm::Value *NumElements,
+ llvm::Value *ArrayPtr,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) {
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
// Create a temporary for the loop index and initialize it with 0.
llvm::Value *IndexPtr = CreateTempAlloca(SizeTy, "loop.index");
llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy);
- Builder.CreateStore(Zero, IndexPtr, false);
+ Builder.CreateStore(Zero, IndexPtr);
// Start the loop with a block that tests the condition.
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
@@ -507,15 +516,31 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
Counter = Builder.CreateLoad(IndexPtr);
llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter,
"arrayidx");
- EmitCXXConstructorCall(D, Ctor_Complete, Address, 0, 0);
+ // C++ [class.temporary]p4:
+ // There are two contexts in which temporaries are destroyed at a different
+ // point than the end of the full- expression. The first context is when a
+ // default constructor is called to initialize an element of an array.
+ // If the constructor has one or more default arguments, the destruction of
+ // every temporary created in a default argument expression is sequenced
+ // before the construction of the next array element, if any.
+
+ // Keep track of the current number of live temporaries.
+ unsigned OldNumLiveTemporaries = LiveTemporaries.size();
+
+ EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd);
+
+ // Pop temporaries.
+ while (LiveTemporaries.size() > OldNumLiveTemporaries)
+ PopCXXTemporary();
+
EmitBlock(ContinueBlock);
// Emit the increment of the loop counter.
llvm::Value *NextVal = llvm::ConstantInt::get(SizeTy, 1);
Counter = Builder.CreateLoad(IndexPtr);
NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
- Builder.CreateStore(NextVal, IndexPtr, false);
+ Builder.CreateStore(NextVal, IndexPtr);
// Finally, branch back up to the condition for the next iteration.
EmitBranch(CondBlock);
@@ -551,7 +576,7 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
"loop.index");
// Index = ElementCount;
- Builder.CreateStore(UpperCount, IndexPtr, false);
+ Builder.CreateStore(UpperCount, IndexPtr);
// Start the loop with a block that tests the condition.
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
@@ -578,23 +603,14 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
Counter = Builder.CreateLoad(IndexPtr);
Counter = Builder.CreateSub(Counter, One);
llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx");
- if (D->isVirtual()) {
- const llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(D),
- /*isVariadic=*/false);
-
- llvm::Value *Callee = BuildVirtualCall(D, Dtor_Deleting, Address, Ty);
- EmitCXXMemberCall(D, Callee, Address, 0, 0);
- }
- else
- EmitCXXDestructorCall(D, Dtor_Complete, Address);
+ EmitCXXDestructorCall(D, Dtor_Complete, Address);
EmitBlock(ContinueBlock);
// Emit the decrement of the loop counter.
Counter = Builder.CreateLoad(IndexPtr);
Counter = Builder.CreateSub(Counter, One, "dec");
- Builder.CreateStore(Counter, IndexPtr, false);
+ Builder.CreateStore(Counter, IndexPtr);
// Finally, branch back up to the condition for the next iteration.
EmitBranch(CondBlock);
@@ -664,6 +680,10 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
EmitAggregateCopy(This, Src, Ty);
return;
}
+ } else if (D->isTrivial()) {
+ // FIXME: Track down why we're trying to generate calls to the trivial
+ // default constructor!
+ return;
}
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
@@ -674,6 +694,15 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *D,
CXXDtorType Type,
llvm::Value *This) {
+ if (D->isVirtual()) {
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(D),
+ /*isVariadic=*/false);
+
+ llvm::Value *Callee = BuildVirtualCall(D, Dtor_Deleting, This, Ty);
+ EmitCXXMemberCall(D, Callee, This, 0, 0);
+ return;
+ }
llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(D, Type);
EmitCXXMemberCall(D, Callee, This, 0, 0);
@@ -715,7 +744,8 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr =
Builder.CreateBitCast(Dest, BasePtr);
- EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr);
+ EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
+ E->arg_begin(), E->arg_end());
}
else
// Call the constructor.
@@ -744,7 +774,7 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
CXXCtorType Type) {
const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>();
const llvm::FunctionType *FTy =
- getTypes().GetFunctionType(getTypes().getFunctionInfo(D),
+ getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type),
FPT->isVariadic());
const char *Name = getMangledCXXCtorName(D, Type);
@@ -755,8 +785,7 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D,
CXXCtorType Type) {
llvm::SmallString<256> Name;
- llvm::raw_svector_ostream Out(Name);
- mangleCXXCtor(getMangleContext(), D, Type, Out);
+ getMangleContext().mangleCXXCtor(D, Type, Name);
Name += '\0';
return UniqueMangledName(Name.begin(), Name.end());
@@ -764,9 +793,9 @@ const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D,
void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) {
if (D->isVirtual())
- EmitCXXDestructor(D, Dtor_Deleting);
- EmitCXXDestructor(D, Dtor_Complete);
- EmitCXXDestructor(D, Dtor_Base);
+ EmitGlobalDefinition(GlobalDecl(D, Dtor_Deleting));
+ EmitGlobalDefinition(GlobalDecl(D, Dtor_Complete));
+ EmitGlobalDefinition(GlobalDecl(D, Dtor_Base));
}
void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D,
@@ -783,7 +812,7 @@ llvm::Function *
CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D,
CXXDtorType Type) {
const llvm::FunctionType *FTy =
- getTypes().GetFunctionType(getTypes().getFunctionInfo(D), false);
+ getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type), false);
const char *Name = getMangledCXXDtorName(D, Type);
return cast<llvm::Function>(
@@ -793,59 +822,61 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D,
const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D,
CXXDtorType Type) {
llvm::SmallString<256> Name;
- llvm::raw_svector_ostream Out(Name);
- mangleCXXDtor(getMangleContext(), D, Type, Out);
+ getMangleContext().mangleCXXDtor(D, Type, Name);
Name += '\0';
return UniqueMangledName(Name.begin(), Name.end());
}
-llvm::Constant *CodeGenFunction::GenerateThunk(llvm::Function *Fn,
- const CXXMethodDecl *MD,
- bool Extern, int64_t nv,
- int64_t v) {
- return GenerateCovariantThunk(Fn, MD, Extern, nv, v, 0, 0);
+llvm::Constant *
+CodeGenFunction::GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD,
+ bool Extern,
+ const ThunkAdjustment &ThisAdjustment) {
+ return GenerateCovariantThunk(Fn, MD, Extern,
+ CovariantThunkAdjustment(ThisAdjustment,
+ ThunkAdjustment()));
}
-llvm::Value *CodeGenFunction::DynamicTypeAdjust(llvm::Value *V, int64_t nv,
- int64_t v) {
- llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),
- 0);
+llvm::Value *
+CodeGenFunction::DynamicTypeAdjust(llvm::Value *V,
+ const ThunkAdjustment &Adjustment) {
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+
const llvm::Type *OrigTy = V->getType();
- if (nv) {
+ if (Adjustment.NonVirtual) {
// Do the non-virtual adjustment
- V = Builder.CreateBitCast(V, Ptr8Ty);
- V = Builder.CreateConstInBoundsGEP1_64(V, nv);
- V = Builder.CreateBitCast(V, OrigTy);
- }
- if (v) {
- // Do the virtual this adjustment
- const llvm::Type *PtrDiffTy =
- ConvertType(getContext().getPointerDiffType());
- llvm::Type *PtrPtr8Ty, *PtrPtrDiffTy;
- PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0);
- PtrPtrDiffTy = llvm::PointerType::get(PtrDiffTy, 0);
- llvm::Value *ThisVal = Builder.CreateBitCast(V, Ptr8Ty);
- V = Builder.CreateBitCast(V, PtrPtrDiffTy->getPointerTo());
- V = Builder.CreateLoad(V, "vtable");
- llvm::Value *VTablePtr = V;
- assert(v % (LLVMPointerWidth/8) == 0 && "vtable entry unaligned");
- v /= LLVMPointerWidth/8;
- V = Builder.CreateConstInBoundsGEP1_64(VTablePtr, v);
- V = Builder.CreateLoad(V);
- V = Builder.CreateGEP(ThisVal, V);
+ V = Builder.CreateBitCast(V, Int8PtrTy);
+ V = Builder.CreateConstInBoundsGEP1_64(V, Adjustment.NonVirtual);
V = Builder.CreateBitCast(V, OrigTy);
}
- return V;
+
+ if (!Adjustment.Virtual)
+ return V;
+
+ assert(Adjustment.Virtual % (LLVMPointerWidth / 8) == 0 &&
+ "vtable entry unaligned");
+
+ // Do the virtual this adjustment
+ const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
+ const llvm::Type *PtrDiffPtrTy = PtrDiffTy->getPointerTo();
+
+ llvm::Value *ThisVal = Builder.CreateBitCast(V, Int8PtrTy);
+ V = Builder.CreateBitCast(V, PtrDiffPtrTy->getPointerTo());
+ V = Builder.CreateLoad(V, "vtable");
+
+ llvm::Value *VTablePtr = V;
+ uint64_t VirtualAdjustment = Adjustment.Virtual / (LLVMPointerWidth / 8);
+ V = Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment);
+ V = Builder.CreateLoad(V);
+ V = Builder.CreateGEP(ThisVal, V);
+
+ return Builder.CreateBitCast(V, OrigTy);
}
-llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
- const CXXMethodDecl *MD,
- bool Extern,
- int64_t nv_t,
- int64_t v_t,
- int64_t nv_r,
- int64_t v_r) {
+llvm::Constant *
+CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
+ const CXXMethodDecl *MD, bool Extern,
+ const CovariantThunkAdjustment &Adjustment) {
QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
FunctionArgList Args;
@@ -878,16 +909,23 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
llvm::Value *Callee = CGM.GetAddrOfFunction(MD, Ty);
CallArgList CallArgs;
+ bool ShouldAdjustReturnPointer = true;
QualType ArgType = MD->getThisType(getContext());
llvm::Value *Arg = Builder.CreateLoad(LocalDeclMap[ThisDecl], "this");
- if (nv_t || v_t) {
+ if (!Adjustment.ThisAdjustment.isEmpty()) {
// Do the this adjustment.
const llvm::Type *OrigTy = Callee->getType();
- Arg = DynamicTypeAdjust(Arg, nv_t, v_t);
- if (nv_r || v_r) {
- Callee = CGM.BuildCovariantThunk(MD, Extern, 0, 0, nv_r, v_r);
+ Arg = DynamicTypeAdjust(Arg, Adjustment.ThisAdjustment);
+
+ if (!Adjustment.ReturnAdjustment.isEmpty()) {
+ const CovariantThunkAdjustment &ReturnAdjustment =
+ CovariantThunkAdjustment(ThunkAdjustment(),
+ Adjustment.ReturnAdjustment);
+
+ Callee = CGM.BuildCovariantThunk(MD, Extern, ReturnAdjustment);
+
Callee = Builder.CreateBitCast(Callee, OrigTy);
- nv_r = v_r = 0;
+ ShouldAdjustReturnPointer = false;
}
}
@@ -906,7 +944,7 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
Callee, CallArgs, MD);
- if (nv_r || v_r) {
+ if (ShouldAdjustReturnPointer && !Adjustment.ReturnAdjustment.isEmpty()) {
bool CanBeZero = !(ResultType->isReferenceType()
// FIXME: attr nonnull can't be zero either
/* || ResultType->hasAttr<NonNullAttr>() */ );
@@ -921,7 +959,8 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
Builder.CreateCondBr(Builder.CreateICmpNE(RV.getScalarVal(), Zero),
NonZeroBlock, ZeroBlock);
EmitBlock(NonZeroBlock);
- llvm::Value *NZ = DynamicTypeAdjust(RV.getScalarVal(), nv_r, v_r);
+ llvm::Value *NZ =
+ DynamicTypeAdjust(RV.getScalarVal(), Adjustment.ReturnAdjustment);
EmitBranch(ContBlock);
EmitBlock(ZeroBlock);
llvm::Value *Z = RV.getScalarVal();
@@ -932,7 +971,8 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
RVOrZero->addIncoming(Z, ZeroBlock);
RV = RValue::get(RVOrZero);
} else
- RV = RValue::get(DynamicTypeAdjust(RV.getScalarVal(), nv_r, v_r));
+ RV = RValue::get(DynamicTypeAdjust(RV.getScalarVal(),
+ Adjustment.ReturnAdjustment));
}
if (!ResultType->isVoidType())
@@ -942,11 +982,13 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
return Fn;
}
-llvm::Constant *CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern,
- int64_t nv, int64_t v) {
+llvm::Constant *
+CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern,
+ const ThunkAdjustment &ThisAdjustment) {
+
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleThunk(getMangleContext(), MD, nv, v, Out);
+ getMangleContext().mangleThunk(MD, ThisAdjustment, OutName);
+
llvm::GlobalVariable::LinkageTypes linktype;
linktype = llvm::GlobalValue::WeakAnyLinkage;
if (!Extern)
@@ -957,20 +999,18 @@ llvm::Constant *CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern,
getTypes().GetFunctionType(getTypes().getFunctionInfo(MD),
FPT->isVariadic());
- llvm::Function *Fn = llvm::Function::Create(FTy, linktype, Out.str(),
+ llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(),
&getModule());
- CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, nv, v);
+ CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, ThisAdjustment);
llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
return m;
}
-llvm::Constant *CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD,
- bool Extern, int64_t nv_t,
- int64_t v_t, int64_t nv_r,
- int64_t v_r) {
+llvm::Constant *
+CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern,
+ const CovariantThunkAdjustment &Adjustment) {
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCovariantThunk(getMangleContext(), MD, nv_t, v_t, nv_r, v_r, Out);
+ getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName);
llvm::GlobalVariable::LinkageTypes linktype;
linktype = llvm::GlobalValue::WeakAnyLinkage;
if (!Extern)
@@ -981,10 +1021,9 @@ llvm::Constant *CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD,
getTypes().GetFunctionType(getTypes().getFunctionInfo(MD),
FPT->isVariadic());
- llvm::Function *Fn = llvm::Function::Create(FTy, linktype, Out.str(),
+ llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(),
&getModule());
- CodeGenFunction(*this).GenerateCovariantThunk(Fn, MD, Extern, nv_t, v_t, nv_r,
- v_r);
+ CodeGenFunction(*this).GenerateCovariantThunk(Fn, MD, Extern, Adjustment);
llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
return m;
}
@@ -1016,7 +1055,7 @@ CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This,
return VBaseOffset;
}
-static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, int64_t VtableIndex,
+static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex,
llvm::Value *This, const llvm::Type *Ty) {
Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo();
@@ -1032,7 +1071,7 @@ llvm::Value *
CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
const llvm::Type *Ty) {
MD = MD->getCanonicalDecl();
- int64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD);
+ uint64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD);
return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
}
@@ -1041,7 +1080,7 @@ llvm::Value *
CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
llvm::Value *&This, const llvm::Type *Ty) {
DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl());
- int64_t VtableIndex =
+ uint64_t VtableIndex =
CGM.getVtableInfo().getMethodVtableIndex(GlobalDecl(DD, Type));
return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
@@ -1065,7 +1104,7 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
"loop.index");
llvm::Value* zeroConstant =
llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
- Builder.CreateStore(zeroConstant, IndexPtr, false);
+ Builder.CreateStore(zeroConstant, IndexPtr);
// Start the loop with a block that tests the condition.
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
@@ -1115,7 +1154,7 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
Counter = Builder.CreateLoad(IndexPtr);
NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
- Builder.CreateStore(NextVal, IndexPtr, false);
+ Builder.CreateStore(NextVal, IndexPtr);
// Finally, branch back up to the condition for the next iteration.
EmitBranch(CondBlock);
@@ -1142,7 +1181,7 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
"loop.index");
llvm::Value* zeroConstant =
llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
- Builder.CreateStore(zeroConstant, IndexPtr, false);
+ Builder.CreateStore(zeroConstant, IndexPtr);
// Start the loop with a block that tests the condition.
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
@@ -1199,7 +1238,7 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
Counter = Builder.CreateLoad(IndexPtr);
NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
- Builder.CreateStore(NextVal, IndexPtr, false);
+ Builder.CreateStore(NextVal, IndexPtr);
// Finally, branch back up to the condition for the next iteration.
EmitBranch(CondBlock);
@@ -1216,10 +1255,10 @@ void CodeGenFunction::EmitClassMemberwiseCopy(
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl, QualType Ty) {
if (ClassDecl) {
- Dest = GetAddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- Src = GetAddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
+ Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
}
if (BaseClassDecl->hasTrivialCopyConstructor()) {
EmitAggregateCopy(Dest, Src, Ty);
@@ -1255,10 +1294,10 @@ void CodeGenFunction::EmitClassCopyAssignment(
const CXXRecordDecl *BaseClassDecl,
QualType Ty) {
if (ClassDecl) {
- Dest = GetAddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- Src = GetAddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
+ Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
}
if (BaseClassDecl->hasTrivialCopyAssignment()) {
EmitAggregateCopy(Dest, Src, Ty);
@@ -1297,6 +1336,7 @@ CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor,
CXXCtorType Type,
llvm::Function *Fn,
const FunctionArgList &Args) {
+ assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor");
StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args,
SourceLocation());
EmitCtorPrologue(Ctor, Type);
@@ -1326,6 +1366,7 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
const CXXRecordDecl *ClassDecl = Ctor->getParent();
assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
"SynthesizeCXXCopyConstructor - copy constructor has definition already");
+ assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor");
StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args,
SourceLocation());
@@ -1349,10 +1390,11 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
Base->getType());
}
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = getContext().getCanonicalType((*Field)->getType());
+ for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); I != E; ++I) {
+ const FieldDecl *Field = *I;
+
+ QualType FieldType = getContext().getCanonicalType(Field->getType());
const ConstantArrayType *Array =
getContext().getAsConstantArrayType(FieldType);
if (Array)
@@ -1361,8 +1403,8 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
+ LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0);
if (Array) {
const llvm::Type *BasePtr = ConvertType(FieldType);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
@@ -1378,9 +1420,28 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
0 /*ClassDecl*/, FieldClassDecl, FieldType);
continue;
}
+
+ if (Field->getType()->isReferenceType()) {
+ unsigned FieldIndex = CGM.getTypes().getLLVMFieldNo(Field);
+
+ llvm::Value *LHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex,
+ "lhs.ref");
+
+ llvm::Value *RHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex,
+ "rhs.ref");
+
+ // Load the value in RHS.
+ RHS = Builder.CreateLoad(RHS);
+
+ // And store it in the LHS
+ Builder.CreateStore(RHS, LHS);
+
+ continue;
+ }
// Do a built-in assignment of scalar data members.
- LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
+ LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0);
+
if (!hasAggregateLLVMType(Field->getType())) {
RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
EmitStoreThroughLValue(RVRHS, LHS, Field->getType());
@@ -1498,9 +1559,9 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
const Type *BaseType = BaseInit->getBaseClass();
CXXRecordDecl *BaseClassDecl =
cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
- llvm::Value *V = CGF.GetAddressCXXOfBaseClass(ThisPtr, ClassDecl,
- BaseClassDecl,
- /*NullCheckValue=*/false);
+ llvm::Value *V = CGF.GetAddressOfBaseClass(ThisPtr, ClassDecl,
+ BaseClassDecl,
+ /*NullCheckValue=*/false);
CGF.EmitCXXConstructorCall(BaseInit->getConstructor(),
CtorType, V,
BaseInit->const_arg_begin(),
@@ -1564,7 +1625,9 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
llvm::Value *BaseAddrPtr =
CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr);
CGF.EmitCXXAggrConstructorCall(MemberInit->getConstructor(),
- Array, BaseAddrPtr);
+ Array, BaseAddrPtr,
+ MemberInit->const_arg_begin(),
+ MemberInit->const_arg_end());
}
else
CGF.EmitCXXConstructorCall(MemberInit->getConstructor(),
@@ -1714,12 +1777,12 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
// Ignore trivial destructors.
if (BaseClassDecl->hasTrivialDestructor())
continue;
-
- llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(),
- ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()),
- Dtor_Base, V);
+ const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
+
+ llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(),
+ ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ EmitCXXDestructorCall(D, Dtor_Base, V);
}
// If we're emitting a base destructor, we don't want to emit calls to the
@@ -1727,10 +1790,21 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
if (DtorType == Dtor_Base)
return;
- // FIXME: Handle virtual bases.
+ // Handle virtual bases.
for (CXXRecordDecl::reverse_base_class_const_iterator I =
ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) {
- assert(false && "FIXME: Handle virtual bases.");
+ const CXXBaseSpecifier &Base = *I;
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore trivial destructors.
+ if (BaseClassDecl->hasTrivialDestructor())
+ continue;
+ const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
+ llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(),
+ ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ EmitCXXDestructorCall(D, Dtor_Base, V);
}
// If we have a deleting destructor, emit a call to the delete operator.
@@ -1752,9 +1826,3 @@ void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor,
EmitDtorEpilogue(Dtor, DtorType);
FinishFunction();
}
-
-// FIXME: Move this to CGStmtCXX.cpp
-void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
- // FIXME: We need to do more here.
- EmitStmt(S.getTryBlock());
-}
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index d0c7d03..decc73c 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -91,6 +91,42 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
getCallingConventionForDecl(MD));
}
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D,
+ CXXCtorType Type) {
+ llvm::SmallVector<QualType, 16> ArgTys;
+
+ // Add the 'this' pointer.
+ ArgTys.push_back(D->getThisType(Context));
+
+ // Check if we need to add a VTT parameter (which has type void **).
+ if (Type == Ctor_Base && D->getParent()->getNumVBases() != 0)
+ ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));
+
+ const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>();
+ for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
+ ArgTys.push_back(FTP->getArgType(i));
+ return getFunctionInfo(FTP->getResultType(), ArgTys,
+ getCallingConventionForDecl(D));
+}
+
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D,
+ CXXDtorType Type) {
+ llvm::SmallVector<QualType, 16> ArgTys;
+
+ // Add the 'this' pointer.
+ ArgTys.push_back(D->getThisType(Context));
+
+ // Check if we need to add a VTT parameter (which has type void **).
+ if (Type == Dtor_Base && D->getParent()->getNumVBases() != 0)
+ ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));
+
+ const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>();
+ for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
+ ArgTys.push_back(FTP->getArgType(i));
+ return getFunctionInfo(FTP->getResultType(), ArgTys,
+ getCallingConventionForDecl(D));
+}
+
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) {
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
if (MD->isInstance())
@@ -418,6 +454,32 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic) {
return llvm::FunctionType::get(ResultType, ArgTys, IsVariadic);
}
+static bool HasIncompleteReturnTypeOrArgumentTypes(const FunctionProtoType *T) {
+ if (const TagType *TT = T->getResultType()->getAs<TagType>()) {
+ if (!TT->getDecl()->isDefinition())
+ return true;
+ }
+
+ for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) {
+ if (const TagType *TT = T->getArgType(i)->getAs<TagType>()) {
+ if (!TT->getDecl()->isDefinition())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const llvm::Type *
+CodeGenTypes::GetFunctionTypeForVtable(const CXXMethodDecl *MD) {
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+
+ if (!HasIncompleteReturnTypeOrArgumentTypes(FPT))
+ return GetFunctionType(getFunctionInfo(MD), FPT->isVariadic());
+
+ return llvm::OpaqueType::get(getLLVMContext());
+}
+
void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const Decl *TargetDecl,
AttributeListType &PAL,
diff --git a/lib/CodeGen/CGCXXClass.cpp b/lib/CodeGen/CGClass.cpp
index 533aabc..b3c2b98 100644
--- a/lib/CodeGen/CGCXXClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -1,4 +1,4 @@
-//===--- CGCXXClass.cpp - Emit LLVM Code for C++ classes ------------------===//
+//===--- CGClass.cpp - Emit LLVM Code for C++ classes ---------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -31,9 +31,6 @@ ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths,
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
const CXXBaseSpecifier *BS = Element.Base;
- // FIXME: enable test3 from virt.cc to not abort.
- if (BS->isVirtual())
- return 0;
assert(!BS->isVirtual() && "Should not see virtual bases here!");
const CXXRecordDecl *Base =
@@ -75,7 +72,7 @@ static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl) {
CXXBasePaths Paths(/*FindAmbiguities=*/false,
- /*RecordPaths=*/true, /*DetectVirtual=*/true);
+ /*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!");
@@ -84,21 +81,20 @@ static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
unsigned Start = 0;
llvm::Value *VirtualOffset = 0;
- if (const RecordType *RT = Paths.getDetectedVirtual()) {
- const CXXRecordDecl *VBase = cast<CXXRecordDecl>(RT->getDecl());
-
- VirtualOffset =
- CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase);
-
- const CXXBasePath &Path = Paths.front();
- unsigned e = Path.size();
- for (Start = 0; Start != e; ++Start) {
- const CXXBasePathElement& Element = Path[Start];
-
- if (Element.Class == VBase)
- break;
+
+ 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 =
+ CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase);
uint64_t Offset =
ComputeNonVirtualBaseClassOffset(CGF.getContext(), Paths, Start);
@@ -117,10 +113,10 @@ static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
}
llvm::Value *
-CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
- bool NullCheckValue) {
+CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl,
+ bool NullCheckValue) {
QualType BTy =
getContext().getCanonicalType(
getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
@@ -128,7 +124,7 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
if (ClassDecl == BaseClassDecl) {
// Just cast back.
- return Builder.CreateBitCast(BaseValue, BasePtrTy);
+ return Builder.CreateBitCast(Value, BasePtrTy);
}
llvm::BasicBlock *CastNull = 0;
@@ -141,8 +137,8 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
CastEnd = createBasicBlock("cast.end");
llvm::Value *IsNull =
- Builder.CreateICmpEQ(BaseValue,
- llvm::Constant::getNullValue(BaseValue->getType()));
+ Builder.CreateICmpEQ(Value,
+ llvm::Constant::getNullValue(Value->getType()));
Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
EmitBlock(CastNotNull);
}
@@ -150,16 +146,16 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
llvm::Value *Offset =
- GetCXXBaseClassOffset(*this, BaseValue, ClassDecl, BaseClassDecl);
+ GetCXXBaseClassOffset(*this, Value, ClassDecl, BaseClassDecl);
if (Offset) {
// Apply the offset.
- BaseValue = Builder.CreateBitCast(BaseValue, Int8PtrTy);
- BaseValue = Builder.CreateGEP(BaseValue, Offset, "add.ptr");
+ Value = Builder.CreateBitCast(Value, Int8PtrTy);
+ Value = Builder.CreateGEP(Value, Offset, "add.ptr");
}
// Cast back.
- BaseValue = Builder.CreateBitCast(BaseValue, BasePtrTy);
+ Value = Builder.CreateBitCast(Value, BasePtrTy);
if (NullCheckValue) {
Builder.CreateBr(CastEnd);
@@ -167,13 +163,73 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
Builder.CreateBr(CastEnd);
EmitBlock(CastEnd);
- llvm::PHINode *PHI = Builder.CreatePHI(BaseValue->getType());
+ llvm::PHINode *PHI = Builder.CreatePHI(Value->getType());
+ PHI->reserveOperandSpace(2);
+ PHI->addIncoming(Value, CastNotNull);
+ PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
+ CastNull);
+ Value = PHI;
+ }
+
+ return Value;
+}
+
+llvm::Value *
+CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *DerivedClassDecl,
+ bool NullCheckValue) {
+ QualType DerivedTy =
+ getContext().getCanonicalType(
+ getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClassDecl)));
+ const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
+
+ if (ClassDecl == DerivedClassDecl) {
+ // Just cast back.
+ return Builder.CreateBitCast(Value, DerivedPtrTy);
+ }
+
+ llvm::BasicBlock *CastNull = 0;
+ llvm::BasicBlock *CastNotNull = 0;
+ llvm::BasicBlock *CastEnd = 0;
+
+ if (NullCheckValue) {
+ CastNull = createBasicBlock("cast.null");
+ CastNotNull = createBasicBlock("cast.notnull");
+ CastEnd = createBasicBlock("cast.end");
+
+ llvm::Value *IsNull =
+ Builder.CreateICmpEQ(Value,
+ llvm::Constant::getNullValue(Value->getType()));
+ Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
+ EmitBlock(CastNotNull);
+ }
+
+ llvm::Value *Offset = GetCXXBaseClassOffset(*this, Value, DerivedClassDecl,
+ ClassDecl);
+ if (Offset) {
+ // Apply the offset.
+ Value = Builder.CreatePtrToInt(Value, Offset->getType());
+ Value = Builder.CreateSub(Value, Offset);
+ Value = Builder.CreateIntToPtr(Value, DerivedPtrTy);
+ } else {
+ // Just cast.
+ Value = Builder.CreateBitCast(Value, DerivedPtrTy);
+ }
+
+ if (NullCheckValue) {
+ Builder.CreateBr(CastEnd);
+ EmitBlock(CastNull);
+ Builder.CreateBr(CastEnd);
+ EmitBlock(CastEnd);
+
+ llvm::PHINode *PHI = Builder.CreatePHI(Value->getType());
PHI->reserveOperandSpace(2);
- PHI->addIncoming(BaseValue, CastNotNull);
- PHI->addIncoming(llvm::Constant::getNullValue(BaseValue->getType()),
+ PHI->addIncoming(Value, CastNotNull);
+ PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
CastNull);
- BaseValue = PHI;
+ Value = PHI;
}
- return BaseValue;
+ return Value;
}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 0551667..317da7e 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -95,10 +95,10 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
// file at a time.
bool isMain = false;
const LangOptions &LO = M->getLangOptions();
- const char *MainFileName = LO.getMainFileName();
+ const CodeGenOptions &CGO = M->getCodeGenOpts();
if (isMainCompileUnitCreated == false) {
- if (MainFileName) {
- if (!strcmp(AbsFileName.getLast().c_str(), MainFileName))
+ if (!CGO.MainFileName.empty()) {
+ if (AbsFileName.getLast() == CGO.MainFileName)
isMain = true;
} else {
if (Loc.isValid() && SM.isFromMainFile(Loc))
@@ -417,7 +417,7 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
llvm::DIType DbgTy =
DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef, Unit,
- Ty->getDecl()->getNameAsCString(),
+ Ty->getDecl()->getName(),
DefUnit, Line, 0, 0, 0, 0, Src);
return DbgTy;
}
@@ -482,7 +482,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
// may refer to the forward decl if the struct is recursive) and replace all
// uses of the forward declaration with the final definition.
llvm::DICompositeType FwdDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsString().data(),
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(),
DefUnit, Line, 0, 0, 0, 0,
llvm::DIType(), llvm::DIArray());
@@ -507,10 +507,10 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
FieldDecl *Field = *I;
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
- const char *FieldName = Field->getNameAsCString();
+ llvm::StringRef FieldName = Field->getName();
// Ignore unnamed fields.
- if (!FieldName)
+ if (FieldName.empty())
continue;
// Get the location for the field.
@@ -558,7 +558,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
uint64_t Align = M->getContext().getTypeAlign(Ty);
llvm::DICompositeType RealDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsString().data(),
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(),
DefUnit, Line, Size, Align, 0, 0,
llvm::DIType(), Elements);
@@ -592,7 +592,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// may refer to the forward decl if the struct is recursive) and replace all
// uses of the forward declaration with the final definition.
llvm::DICompositeType FwdDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsCString(),
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(),
DefUnit, Line, 0, 0, 0, 0,
llvm::DIType(), llvm::DIArray(),
RuntimeLang);
@@ -628,10 +628,10 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
ObjCIvarDecl *Field = *I;
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
- const char *FieldName = Field->getNameAsCString();
+ llvm::StringRef FieldName = Field->getName();
// Ignore unnamed fields.
- if (!FieldName)
+ if (FieldName.empty())
continue;
// Get the location for the field.
@@ -682,7 +682,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
uint64_t Align = M->getContext().getTypeAlign(Ty);
llvm::DICompositeType RealDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsCString(), DefUnit,
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), DefUnit,
Line, Size, Align, 0, 0, llvm::DIType(),
Elements, RuntimeLang);
@@ -703,7 +703,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
for (EnumDecl::enumerator_iterator
Enum = Decl->enumerator_begin(), EnumEnd = Decl->enumerator_end();
Enum != EnumEnd; ++Enum) {
- Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getNameAsCString(),
+ Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getName(),
Enum->getInitVal().getZExtValue()));
}
@@ -728,7 +728,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
llvm::DIType DbgTy =
DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type,
- Unit, Decl->getNameAsCString(), DefUnit, Line,
+ Unit, Decl->getName(), DefUnit, Line,
Size, Align, 0, 0,
llvm::DIType(), EltArray);
return DbgTy;
@@ -1104,7 +1104,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
FieldAlign = Align*8;
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- Decl->getNameAsCString(), DefUnit,
+ Decl->getName(), DefUnit,
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
@@ -1135,7 +1135,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
// Create the descriptor for the variable.
llvm::DIVariable D =
DebugFactory.CreateVariable(Tag, llvm::DIDescriptor(RegionStack.back()),
- Decl->getNameAsCString(),
+ Decl->getName(),
Unit, Line, Ty);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
@@ -1282,7 +1282,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
XOffset = FieldOffset;
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- Decl->getNameAsCString(), DefUnit,
+ Decl->getName(), DefUnit,
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
@@ -1336,7 +1336,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
// Create the descriptor for the variable.
llvm::DIVariable D =
DebugFactory.CreateComplexVariable(Tag, llvm::DIDescriptor(RegionStack.back()),
- Decl->getNameAsCString(), Unit, Line, Ty,
+ Decl->getName(), Unit, Line, Ty,
addr);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
@@ -1392,9 +1392,9 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
T = M->getContext().getConstantArrayType(ET, ConstVal,
ArrayType::Normal, 0);
}
- const char *DeclName = Decl->getNameAsCString();
+ llvm::StringRef DeclName = Decl->getName();
DebugFactory.CreateGlobalVariable(getContext(Decl, Unit), DeclName, DeclName,
- NULL, Unit, LineNo,
+ llvm::StringRef(), Unit, LineNo,
getOrCreateType(T, Unit),
Var->hasInternalLinkage(),
true/*definition*/, Var);
@@ -1409,7 +1409,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
- const char *Name = Decl->getNameAsCString();
+ llvm::StringRef Name = Decl->getName();
QualType T = M->getContext().getObjCInterfaceType(Decl);
if (T->isIncompleteArrayType()) {
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 349ede5..c047283 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -30,7 +30,9 @@ using namespace CodeGen;
void CodeGenFunction::EmitDecl(const Decl &D) {
switch (D.getKind()) {
- default: assert(0 && "Unknown decl kind!");
+ default:
+ CGM.ErrorUnsupported(&D, "decl");
+ return;
case Decl::ParmVar:
assert(0 && "Parmdecls should not be in declstmts!");
case Decl::Function: // void X();
@@ -38,7 +40,9 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Enum: // enum X;
case Decl::EnumConstant: // enum ? { X = ? }
case Decl::CXXRecord: // struct/union/class X; [C++]
- case Decl::UsingDirective: // using X; [C++]
+ case Decl::Using: // using X; [C++]
+ case Decl::UsingShadow:
+ case Decl::UsingDirective: // using namespace X; [C++]
// None of these decls require codegen support.
return;
@@ -372,7 +376,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
{
// Push a cleanup block and restore the stack there.
- CleanupScope scope(*this);
+ DelayedCleanupBlock scope(*this);
V = Builder.CreateLoad(Stack, "tmp");
llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stackrestore);
@@ -517,7 +521,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
if (const ConstantArrayType *Array =
getContext().getAsConstantArrayType(Ty)) {
- CleanupScope Scope(*this);
+ DelayedCleanupBlock Scope(*this);
QualType BaseElementTy = getContext().getBaseElementType(Array);
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
@@ -528,7 +532,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// Make sure to jump to the exit block.
EmitBranch(Scope.getCleanupExitBlock());
} else {
- CleanupScope Scope(*this);
+ DelayedCleanupBlock Scope(*this);
EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
}
}
@@ -541,7 +545,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
llvm::Constant* F = CGM.GetAddrOfFunction(FD);
assert(F && "Could not find function!");
- CleanupScope scope(*this);
+ DelayedCleanupBlock scope(*this);
const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD);
@@ -562,9 +566,9 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
}
if (needsDispose && CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) {
- CleanupScope scope(*this);
+ DelayedCleanupBlock scope(*this);
llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
- V = Builder.CreateLoad(V, false);
+ V = Builder.CreateLoad(V);
BuildBlockRelease(V);
}
}
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index adfd005..420e275 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -11,6 +11,10 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/StmtCXX.h"
+
+#include "llvm/Intrinsics.h"
+
#include "CodeGenFunction.h"
using namespace clang;
using namespace CodeGen;
@@ -35,29 +39,158 @@ static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
std::vector<const llvm::Type*> Args(3, Int8PtrTy);
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
- Args, false);
+ 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 ();
+
+ 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 ();
+
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ std::vector<const llvm::Type*> Args(1, Int8PtrTy);
+
+ 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 ();
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
+}
+
+// FIXME: Eventually this will all go into the backend. Set from the target for
+// now.
+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 =
+ 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");
+}
+
+// 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) {
+ 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));
+ } 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);
+ if (RD->hasTrivialCopyConstructor()) {
+ CGF.EmitAggExpr(E, This, false);
+ } else if (CXXConstructorDecl *CopyCtor
+ = RD->getCopyConstructor(CGF.getContext(), 0)) {
+ // FIXME: region management
+ llvm::Value *Src = CGF.EmitLValue(E).getAddress();
+
+ // Stolen from EmitClassAggrMemberwiseCopy
+ llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor,
+ Ctor_Complete);
+ CallArgList CallArgs;
+ CallArgs.push_back(std::make_pair(RValue::get(This),
+ CopyCtor->getThisType(CGF.getContext())));
+
+ // Push the Src ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Src),
+ CopyCtor->getParamDecl(0)->getType()));
+ QualType ResultType =
+ CopyCtor->getType()->getAs<FunctionType>()->getResultType();
+ CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ Callee, CallArgs, CopyCtor);
+ // FIXME: region management
+ } else
+ CGF.ErrorUnsupported(E, "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) {
+ // Store the throw exception in the exception object.
+ if (!CGF.hasAggregateLLVMType(ObjectType)) {
+ llvm::Value *Value = E;
+ 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);
+ const CXXRecordDecl *RD;
+ RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl());
+ llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty);
+ if (RD->hasTrivialCopyConstructor()) {
+ CGF.EmitAggregateCopy(This, E, ObjectType);
+ } else if (CXXConstructorDecl *CopyCtor
+ = RD->getCopyConstructor(CGF.getContext(), 0)) {
+ // FIXME: region management
+ llvm::Value *Src = E;
+
+ // Stolen from EmitClassAggrMemberwiseCopy
+ llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor,
+ Ctor_Complete);
+ CallArgList CallArgs;
+ CallArgs.push_back(std::make_pair(RValue::get(This),
+ CopyCtor->getThisType(CGF.getContext())));
+
+ // Push the Src ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Src),
+ CopyCtor->getParamDecl(0)->getType()));
+ QualType ResultType =
+ 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");
+ }
+}
+
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
- // FIXME: Handle rethrows.
if (!E->getSubExpr()) {
- ErrorUnsupported(E, "rethrow expression");
+ 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: We only handle non-class types for now.
- if (ThrowType->isRecordType()) {
- ErrorUnsupported(E, "throw expression");
- return;
- }
-
// FIXME: Handle cleanup.
if (!CleanupEntries.empty()){
- ErrorUnsupported(E, "throw expression");
+ ErrorUnsupported(E, "throw expression with cleanup entries");
return;
}
@@ -71,28 +204,11 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
llvm::ConstantInt::get(SizeTy, TypeSize),
"exception");
- // Store the throw exception in the exception object.
- if (!hasAggregateLLVMType(ThrowType)) {
- llvm::Value *Value = EmitScalarExpr(E->getSubExpr());
- const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0);
-
- Builder.CreateStore(Value, Builder.CreateBitCast(ExceptionPtr, ValuePtrTy));
- } else {
- // FIXME: Handle complex and aggregate expressions.
- ErrorUnsupported(E, "throw expression");
- }
+ CopyObject(*this, E->getSubExpr(), ExceptionPtr);
// Now throw the exception.
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
-
- llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXRtti(CGM.getMangleContext(), ThrowType, Out);
-
- // FIXME: Is it OK to use CreateRuntimeVariable for this?
- llvm::Constant *TypeInfo =
- CGM.CreateRuntimeVariable(llvm::Type::getInt8Ty(getLLVMContext()),
- OutName.c_str());
+ llvm::Constant *TypeInfo = CGM.GenerateRtti(ThrowType);
llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy);
llvm::CallInst *ThrowCall =
@@ -103,3 +219,217 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
// Clear the insertion point to indicate we are in unreachable code.
Builder.ClearInsertionPoint();
}
+
+void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
+#if 1
+ EmitStmt(S.getTryBlock());
+ if (0) {
+ getBeginCatchFn(*this);
+ getEndCatchFn(*this);
+ getUnwindResumeOrRethrowFn(*this);
+ CopyObject(*this, QualType(), 0, 0);
+ }
+#else
+ // FIXME: The below is still just a sketch of the code we need.
+ // Pointer to the personality function
+ llvm::Constant *Personality =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
+ (VMContext),
+ true),
+ "__gxx_personality_v0");
+ Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
+
+ 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());
+
+ // Jump to end if there is no exception
+ EmitBranchThroughCleanup(FinallyEnd);
+
+ // Emit the handlers
+ EmitBlock(TryHandler);
+
+ 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::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");
+
+ SelectorArgs.push_back(Exc);
+ SelectorArgs.push_back(Personality);
+
+ bool HasCatchAll = false;
+ for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
+ const CXXCatchStmt *C = S.getHandler(i);
+ VarDecl *CatchParam = C->getExceptionDecl();
+ if (CatchParam) {
+ llvm::Value *EHType = CGM.GenerateRtti(C->getCaughtType().getNonReferenceType());
+ SelectorArgs.push_back(EHType);
+ } else {
+ // null indicates catch all
+ SelectorArgs.push_back(Null);
+ HasCatchAll = true;
+ }
+ }
+
+ // We use a cleanup unless there was already a catch all.
+ if (!HasCatchAll) {
+ SelectorArgs.push_back(Null);
+ }
+
+ // Find which handler was matched.
+ llvm::Value *Selector
+ = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(),
+ SelectorArgs.end(), "selector");
+ for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
+ const CXXCatchStmt *C = S.getHandler(i);
+ VarDecl *CatchParam = C->getExceptionDecl();
+ Stmt *CatchBody = C->getHandlerBlock();
+
+ llvm::BasicBlock *Next = 0;
+
+ if (SelectorArgs[i+2] != Null) {
+ llvm::BasicBlock *Match = createBasicBlock("match");
+ Next = createBasicBlock("catch.next");
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
+ llvm::Value *Id
+ = Builder.CreateCall(llvm_eh_typeid_for,
+ Builder.CreateBitCast(SelectorArgs[i+2],
+ Int8PtrTy));
+ Builder.CreateCondBr(Builder.CreateICmpEQ(Selector, Id),
+ Match, Next);
+ EmitBlock(Match);
+ }
+
+ llvm::BasicBlock *MatchEnd = createBasicBlock("match.end");
+ llvm::BasicBlock *MatchHandler = createBasicBlock("match.handler");
+
+ PushCleanupBlock(MatchEnd);
+ setInvokeDest(MatchHandler);
+
+ 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
+ }
+
+ EmitStmt(CatchBody);
+ EmitBranchThroughCleanup(FinallyEnd);
+
+ EmitBlock(MatchHandler);
+
+ 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),
+ 0));
+ Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
+ Builder.CreateStore(Exc, RethrowPtr);
+ EmitBranchThroughCleanup(FinallyRethrow);
+
+ CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock();
+
+ 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");
+ Builder.CreateInvoke(getEndCatchFn(*this),
+ Cont, MatchEndHandler,
+ 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)
+ EmitBranchThroughCleanup(FinallyRethrow);
+
+ CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock();
+
+ setInvokeDest(PrevLandingPad);
+
+#if 0
+ EmitBlock(FinallyBlock);
+
+ if (Info.SwitchBlock)
+ EmitBlock(Info.SwitchBlock);
+ if (Info.EndBlock)
+ EmitBlock(Info.EndBlock);
+
+ // Branch around the rethrow code.
+ EmitBranch(FinallyEnd);
+#endif
+
+ EmitBlock(FinallyRethrow);
+ Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
+ Builder.CreateLoad(RethrowPtr));
+ Builder.CreateUnreachable();
+
+ EmitBlock(FinallyEnd);
+#endif
+}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 2a544c5..63fca2d 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -137,7 +137,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
const CXXDestructorDecl *Dtor =
ClassDecl->getDestructor(getContext());
- CleanupScope scope(*this);
+ DelayedCleanupBlock scope(*this);
EmitCXXDestructorCall(Dtor, Dtor_Complete, Val.getAggregateAddr());
}
}
@@ -148,8 +148,8 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
if (BaseClassDecl) {
llvm::Value *Derived = Val.getAggregateAddr();
llvm::Value *Base =
- GetAddressCXXOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
+ GetAddressOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
return RValue::get(Base);
}
}
@@ -258,8 +258,6 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::BlockDeclRefExprClass:
return EmitBlockDeclRefLValue(cast<BlockDeclRefExpr>(E));
- case Expr::CXXConditionDeclExprClass:
- return EmitCXXConditionDeclLValue(cast<CXXConditionDeclExpr>(E));
case Expr::CXXTemporaryObjectExprClass:
case Expr::CXXConstructExprClass:
return EmitCXXConstructLValue(cast<CXXConstructExpr>(E));
@@ -314,9 +312,12 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
QualType Ty) {
- llvm::Value *V = Builder.CreateLoad(Addr, Volatile, "tmp");
+ llvm::LoadInst *Load = Builder.CreateLoad(Addr, "tmp");
+ if (Volatile)
+ Load->setVolatile(true);
// Bool can have different representation in memory than in registers.
+ llvm::Value *V = Load;
if (Ty->isBooleanType())
if (V->getType() != llvm::Type::getInt1Ty(VMContext))
V = Builder.CreateTrunc(V, llvm::Type::getInt1Ty(VMContext), "tobool");
@@ -830,6 +831,24 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
return LV;
}
+static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF,
+ const Expr *E, const FunctionDecl *FD) {
+ llvm::Value* V = CGF.CGM.GetAddrOfFunction(FD);
+ if (!FD->hasPrototype()) {
+ if (const FunctionProtoType *Proto =
+ FD->getType()->getAs<FunctionProtoType>()) {
+ // Ugly case: for a K&R-style definition, the type of the definition
+ // isn't the same as the type of a use. Correct for this with a
+ // bitcast.
+ QualType NoProtoType =
+ CGF.getContext().getFunctionNoProtoType(Proto->getResultType());
+ NoProtoType = CGF.getContext().getPointerType(NoProtoType);
+ V = CGF.Builder.CreateBitCast(V, CGF.ConvertType(NoProtoType), "tmp");
+ }
+ }
+ return LValue::MakeAddr(V, CGF.MakeQualifiers(E->getType()));
+}
+
LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
const NamedDecl *ND = E->getDecl();
@@ -851,7 +870,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
if (VD->hasAttr<BlocksAttr>()) {
V = Builder.CreateStructGEP(V, 1, "forwarding");
- V = Builder.CreateLoad(V, false);
+ V = Builder.CreateLoad(V);
V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD),
VD->getNameAsString());
}
@@ -863,22 +882,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
return LV;
}
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
- llvm::Value* V = CGM.GetAddrOfFunction(FD);
- if (!FD->hasPrototype()) {
- if (const FunctionProtoType *Proto =
- FD->getType()->getAs<FunctionProtoType>()) {
- // Ugly case: for a K&R-style definition, the type of the definition
- // isn't the same as the type of a use. Correct for this with a
- // bitcast.
- QualType NoProtoType =
- getContext().getFunctionNoProtoType(Proto->getResultType());
- NoProtoType = getContext().getPointerType(NoProtoType);
- V = Builder.CreateBitCast(V, ConvertType(NoProtoType), "tmp");
- }
- }
- return LValue::MakeAddr(V, MakeQualifiers(E->getType()));
- }
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
+ return EmitFunctionDeclLValue(*this, E, FD);
if (E->getQualifier()) {
// FIXME: the qualifier check does not seem sufficient here
@@ -1165,7 +1170,10 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
if (VarDecl *VD = dyn_cast<VarDecl>(ND))
return EmitGlobalVarDeclLValue(*this, E, VD);
-
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
+ return EmitFunctionDeclLValue(*this, E, FD);
+
assert(false && "Unhandled member declaration!");
return LValue();
}
@@ -1328,8 +1336,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
// Perform the derived-to-base conversion
llvm::Value *Base =
- GetAddressCXXOfBaseClass(LV.getAddress(), DerivedClassDecl,
- BaseClassDecl, /*NullCheckValue=*/false);
+ GetAddressOfBaseClass(LV.getAddress(), DerivedClassDecl,
+ BaseClassDecl, /*NullCheckValue=*/false);
return LValue::MakeAddr(Base, MakeQualifiers(E->getType()));
}
@@ -1340,7 +1348,23 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
}
case CastExpr::CK_BaseToDerived: {
- return EmitUnsupportedLValue(E, "base-to-derived cast lvalue");
+ const RecordType *BaseClassTy =
+ E->getSubExpr()->getType()->getAs<RecordType>();
+ CXXRecordDecl *BaseClassDecl =
+ cast<CXXRecordDecl>(BaseClassTy->getDecl());
+
+ const RecordType *DerivedClassTy = E->getType()->getAs<RecordType>();
+ CXXRecordDecl *DerivedClassDecl =
+ cast<CXXRecordDecl>(DerivedClassTy->getDecl());
+
+ LValue LV = EmitLValue(E->getSubExpr());
+
+ // Perform the base-to-derived conversion
+ llvm::Value *Derived =
+ GetAddressOfDerivedClass(LV.getAddress(), BaseClassDecl,
+ DerivedClassDecl, /*NullCheckValue=*/false);
+
+ return LValue::MakeAddr(Derived, MakeQualifiers(E->getType()));
}
case CastExpr::CK_BitCast: {
// This must be a reinterpret_cast (or c-style equivalent).
@@ -1460,12 +1484,6 @@ LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) {
return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
}
-LValue
-CodeGenFunction::EmitCXXConditionDeclLValue(const CXXConditionDeclExpr *E) {
- EmitLocalBlockVarDecl(*E->getVarDecl());
- return EmitDeclRefLValue(E);
-}
-
LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) {
llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()), "tmp");
EmitCXXConstructExpr(Temp, E);
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 0e10368..d225d90 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -20,7 +20,6 @@
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
@@ -30,7 +29,7 @@ using namespace CodeGen;
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN AggExprEmitter : public StmtVisitor<AggExprEmitter> {
+class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
CodeGenFunction &CGF;
CGBuilderTy &Builder;
llvm::Value *DestPtr;
@@ -223,6 +222,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
break;
}
+ case CastExpr::CK_DerivedToBaseMemberPointer:
case CastExpr::CK_BaseToDerivedMemberPointer: {
QualType SrcType = E->getSubExpr()->getType();
@@ -242,16 +242,22 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
llvm::Value *DstAdj = Builder.CreateStructGEP(DestPtr, 1, "dst.adj");
// Now See if we need to update the adjustment.
- const CXXRecordDecl *SrcDecl =
+ const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(SrcType->getAs<MemberPointerType>()->
getClass()->getAs<RecordType>()->getDecl());
- const CXXRecordDecl *DstDecl =
+ const CXXRecordDecl *DerivedDecl =
cast<CXXRecordDecl>(E->getType()->getAs<MemberPointerType>()->
getClass()->getAs<RecordType>()->getDecl());
-
- llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DstDecl, SrcDecl);
- if (Adj)
- SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj");
+ if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
+ std::swap(DerivedDecl, BaseDecl);
+
+ llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DerivedDecl, BaseDecl);
+ if (Adj) {
+ if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
+ SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj");
+ else
+ SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj");
+ }
Builder.CreateStore(SrcAdj, DstAdj, VolatileDest);
break;
@@ -389,21 +395,21 @@ void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) {
llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond());
Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
- CGF.PushConditionalTempDestruction();
+ CGF.StartConditionalBranch();
CGF.EmitBlock(LHSBlock);
// Handle the GNU extension for missing LHS.
assert(E->getLHS() && "Must have LHS for aggregate value");
Visit(E->getLHS());
- CGF.PopConditionalTempDestruction();
+ CGF.FinishConditionalBranch();
CGF.EmitBranch(ContBlock);
- CGF.PushConditionalTempDestruction();
+ CGF.StartConditionalBranch();
CGF.EmitBlock(RHSBlock);
Visit(E->getRHS());
- CGF.PopConditionalTempDestruction();
+ CGF.FinishConditionalBranch();
CGF.EmitBranch(ContBlock);
CGF.EmitBlock(ContBlock);
diff --git a/lib/CodeGen/CGCXXExpr.cpp b/lib/CodeGen/CGExprCXX.cpp
index cd7d21b..b982c15 100644
--- a/lib/CodeGen/CGCXXExpr.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -1,4 +1,4 @@
-//===--- CGCXXExpr.cpp - Emit LLVM Code for C++ expressions ---------------===//
+//===--- CGExprCXX.cpp - Emit LLVM Code for C++ expressions ---------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -83,38 +83,41 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
llvm::Value *NewPtr,
llvm::Value *NumElements) {
+ if (E->isArray()) {
+ if (CXXConstructorDecl *Ctor = E->getConstructor())
+ CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
+ E->constructor_arg_begin(),
+ E->constructor_arg_end());
+ return;
+ }
+
QualType AllocType = E->getAllocatedType();
- if (!E->isArray()) {
- if (CXXConstructorDecl *Ctor = E->getConstructor()) {
- CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr,
- E->constructor_arg_begin(),
- E->constructor_arg_end());
+ if (CXXConstructorDecl *Ctor = E->getConstructor()) {
+ CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr,
+ E->constructor_arg_begin(),
+ E->constructor_arg_end());
- return;
- }
+ return;
+ }
- // We have a POD type.
- if (E->getNumConstructorArgs() == 0)
- return;
+ // We have a POD type.
+ if (E->getNumConstructorArgs() == 0)
+ return;
- assert(E->getNumConstructorArgs() == 1 &&
- "Can only have one argument to initializer of POD type.");
+ assert(E->getNumConstructorArgs() == 1 &&
+ "Can only have one argument to initializer of POD type.");
- const Expr *Init = E->getConstructorArg(0);
+ const Expr *Init = E->getConstructorArg(0);
- if (!CGF.hasAggregateLLVMType(AllocType))
- CGF.Builder.CreateStore(CGF.EmitScalarExpr(Init), NewPtr);
- else if (AllocType->isAnyComplexType())
- CGF.EmitComplexExprIntoAddr(Init, NewPtr,
- AllocType.isVolatileQualified());
- else
- CGF.EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified());
- return;
- }
-
- if (CXXConstructorDecl *Ctor = E->getConstructor())
- CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr);
+ if (!CGF.hasAggregateLLVMType(AllocType))
+ CGF.EmitStoreOfScalar(CGF.EmitScalarExpr(Init), NewPtr,
+ AllocType.isVolatileQualified(), AllocType);
+ else if (AllocType->isAnyComplexType())
+ CGF.EmitComplexExprIntoAddr(Init, NewPtr,
+ AllocType.isVolatileQualified());
+ else
+ CGF.EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified());
}
llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
@@ -359,7 +362,7 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
return Builder.CreateBitCast(CGM.GenerateRttiRef(RD), LTy);
return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy);
}
- return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy);
+ return Builder.CreateBitCast(CGM.GenerateRtti(Ty), LTy);
}
Expr *subE = E->getExprOperand();
Ty = subE->getType();
@@ -403,7 +406,7 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
}
return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy);
}
- return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy);
+ return Builder.CreateBitCast(CGM.GenerateRtti(Ty), LTy);
}
llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 9e81e4f..7fa8ffb 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -18,7 +18,6 @@
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
using namespace CodeGen;
@@ -29,7 +28,7 @@ using namespace CodeGen;
typedef CodeGenFunction::ComplexPairTy ComplexPairTy;
namespace {
-class VISIBILITY_HIDDEN ComplexExprEmitter
+class ComplexExprEmitter
: public StmtVisitor<ComplexExprEmitter, ComplexPairTy> {
CodeGenFunction &CGF;
CGBuilderTy &Builder;
@@ -261,34 +260,18 @@ public:
/// load the real and imaginary pieces, returning them as Real/Imag.
ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr,
bool isVolatile) {
- llvm::SmallString<64> Name(SrcPtr->getName().begin(),
- SrcPtr->getName().end());
-
llvm::Value *Real=0, *Imag=0;
if (!IgnoreReal) {
- // FIXME: Clean this up once builder takes Twine/StringRef.
- Name += ".realp";
- llvm::Value *RealPtr = Builder.CreateStructGEP(SrcPtr, 0,
- Name.str().str().c_str());
-
- Name.pop_back(); // .realp -> .real
- // FIXME: Clean this up once builder takes Twine/StringRef.
- Real = Builder.CreateLoad(RealPtr, isVolatile,
- Name.str().str().c_str());
- Name.resize(Name.size()-4); // .real -> .imagp
+ llvm::Value *RealP = Builder.CreateStructGEP(SrcPtr, 0,
+ SrcPtr->getName() + ".realp");
+ Real = Builder.CreateLoad(RealP, isVolatile, SrcPtr->getName() + ".real");
}
if (!IgnoreImag) {
- Name += "imagp";
-
- // FIXME: Clean this up once builder takes Twine/StringRef.
- llvm::Value *ImagPtr = Builder.CreateStructGEP(SrcPtr, 1,
- Name.str().str().c_str());
-
- Name.pop_back(); // .imagp -> .imag
- // FIXME: Clean this up once builder takes Twine/StringRef.
- Imag = Builder.CreateLoad(ImagPtr, isVolatile, Name.str().str().c_str());
+ llvm::Value *ImagP = Builder.CreateStructGEP(SrcPtr, 1,
+ SrcPtr->getName() + ".imagp");
+ Imag = Builder.CreateLoad(ImagP, isVolatile, SrcPtr->getName() + ".imag");
}
return ComplexPairTy(Real, Imag);
}
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 40b845d..9289f78 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -22,14 +22,12 @@
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Target/TargetData.h"
using namespace clang;
using namespace CodeGen;
namespace {
-
-class VISIBILITY_HIDDEN ConstStructBuilder {
+class ConstStructBuilder {
CodeGenModule &CGM;
CodeGenFunction *CGF;
@@ -377,7 +375,7 @@ public:
}
};
-class VISIBILITY_HIDDEN ConstExprEmitter :
+class ConstExprEmitter :
public StmtVisitor<ConstExprEmitter, llvm::Constant*> {
CodeGenModule &CGM;
CodeGenFunction *CGF;
@@ -413,9 +411,10 @@ public:
// Get the function pointer (or index if this is a virtual function).
if (MD->isVirtual()) {
- int64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD);
+ uint64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD);
- Values[0] = llvm::ConstantInt::get(PtrDiffTy, Index + 1);
+ // The pointer is 1 + the virtual table offset in bytes.
+ Values[0] = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1);
} else {
llvm::Constant *FuncPtr = CGM.GetAddrOfFunction(MD);
@@ -673,7 +672,7 @@ public:
if (ILE->getType()->isArrayType())
return EmitArrayInitialization(ILE);
- if (ILE->getType()->isStructureType())
+ if (ILE->getType()->isRecordType())
return EmitStructInitialization(ILE);
if (ILE->getType()->isUnionType())
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index e9bbf35..c1cbecc 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -24,7 +24,6 @@
#include "llvm/GlobalVariable.h"
#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/CFG.h"
#include "llvm/Target/TargetData.h"
#include <cstdarg>
@@ -45,7 +44,7 @@ struct BinOpInfo {
};
namespace {
-class VISIBILITY_HIDDEN ScalarExprEmitter
+class ScalarExprEmitter
: public StmtVisitor<ScalarExprEmitter, Value*> {
CodeGenFunction &CGF;
CGBuilderTy &Builder;
@@ -141,8 +140,11 @@ public:
// l-values.
Value *VisitDeclRefExpr(DeclRefExpr *E) {
- if (const EnumConstantDecl *EC = dyn_cast<EnumConstantDecl>(E->getDecl()))
- return llvm::ConstantInt::get(VMContext, EC->getInitVal());
+ Expr::EvalResult Result;
+ if (E->Evaluate(Result, CGF.getContext()) && Result.Val.isInt()) {
+ assert(!Result.HasSideEffects && "Constant declref with side-effect?!");
+ return llvm::ConstantInt::get(VMContext, Result.Val.getInt());
+ }
return EmitLoadOfLValue(E);
}
Value *VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
@@ -167,7 +169,7 @@ public:
Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E);
Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E);
- Value *VisitMemberExpr(Expr *E) { return EmitLoadOfLValue(E); }
+ Value *VisitMemberExpr(MemberExpr *E);
Value *VisitExtVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); }
Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
return EmitLoadOfLValue(E);
@@ -184,14 +186,14 @@ public:
Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
- Value *VisitCastExpr(const CastExpr *E) {
+ Value *VisitCastExpr(CastExpr *E) {
// Make sure to evaluate VLA bounds now so that we have them for later.
if (E->getType()->isVariablyModifiedType())
CGF.EmitVLASize(E->getType());
return EmitCastExpr(E);
}
- Value *EmitCastExpr(const CastExpr *E);
+ Value *EmitCastExpr(CastExpr *E);
Value *VisitCallExpr(const CallExpr *E) {
if (E->getCallReturnType()->isReferenceType())
@@ -558,6 +560,17 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
Value* SV = llvm::ConstantVector::get(indices.begin(), indices.size());
return Builder.CreateShuffleVector(V1, V2, SV, "shuffle");
}
+Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) {
+ Expr::EvalResult Result;
+ if (E->Evaluate(Result, CGF.getContext()) && Result.Val.isInt()) {
+ if (E->isArrow())
+ CGF.EmitScalarExpr(E->getBase());
+ else
+ EmitLValue(E->getBase());
+ return llvm::ConstantInt::get(VMContext, Result.Val.getInt());
+ }
+ return EmitLoadOfLValue(E);
+}
Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
TestAndClearIgnoreResultAssign();
@@ -748,23 +761,40 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
return V;
}
+static bool ShouldNullCheckClassCastValue(const CastExpr *CE) {
+ const Expr *E = CE->getSubExpr();
+
+ if (isa<CXXThisExpr>(E)) {
+ // We always assume that 'this' is never null.
+ return false;
+ }
+
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(CE)) {
+ // And that lvalue casts are never null.
+ if (ICE->isLvalueCast())
+ return false;
+ }
+
+ return true;
+}
+
// VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts
// have to handle a more broad range of conversions than explicit casts, as they
// handle things like function to ptr-to-function decay etc.
-Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
- const Expr *E = CE->getSubExpr();
+Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
+ Expr *E = CE->getSubExpr();
QualType DestTy = CE->getType();
CastExpr::CastKind Kind = CE->getCastKind();
if (!DestTy->isVoidType())
TestAndClearIgnoreResultAssign();
+ // Since almost all cast kinds apply to scalars, this switch doesn't have
+ // a default case, so the compiler will warn on a missing case. The cases
+ // are in the same order as in the CastKind enum.
switch (Kind) {
- default:
- //return CGF.ErrorUnsupported(E, "type of cast");
- break;
-
case CastExpr::CK_Unknown:
+ // FIXME: All casts should have a known kind!
//assert(0 && "Unknown cast kind!");
break;
@@ -775,6 +805,18 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
case CastExpr::CK_NoOp:
return Visit(const_cast<Expr*>(E));
+ case CastExpr::CK_BaseToDerived: {
+ const CXXRecordDecl *BaseClassDecl =
+ E->getType()->getCXXRecordDeclForPointerType();
+ const CXXRecordDecl *DerivedClassDecl =
+ DestTy->getCXXRecordDeclForPointerType();
+
+ Value *Src = Visit(const_cast<Expr*>(E));
+
+ bool NullCheckValue = ShouldNullCheckClassCastValue(CE);
+ return CGF.GetAddressOfDerivedClass(Src, BaseClassDecl, DerivedClassDecl,
+ NullCheckValue);
+ }
case CastExpr::CK_DerivedToBase: {
const RecordType *DerivedClassTy =
E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
@@ -787,23 +829,19 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
Value *Src = Visit(const_cast<Expr*>(E));
- bool NullCheckValue = true;
-
- if (isa<CXXThisExpr>(E)) {
- // We always assume that 'this' is never null.
- NullCheckValue = false;
- } else if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(CE)) {
- // And that lvalue casts are never null.
- if (ICE->isLvalueCast())
- NullCheckValue = false;
- }
- return CGF.GetAddressCXXOfBaseClass(Src, DerivedClassDecl, BaseClassDecl,
- NullCheckValue);
+ bool NullCheckValue = ShouldNullCheckClassCastValue(CE);
+ return CGF.GetAddressOfBaseClass(Src, DerivedClassDecl, BaseClassDecl,
+ NullCheckValue);
+ }
+ case CastExpr::CK_Dynamic: {
+ Value *V = Visit(const_cast<Expr*>(E));
+ const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(CE);
+ return CGF.EmitDynamicCast(V, DCE);
}
- case CastExpr::CK_ToUnion: {
+ case CastExpr::CK_ToUnion:
assert(0 && "Should be unreachable!");
break;
- }
+
case CastExpr::CK_ArrayToPointerDecay: {
assert(E->getType()->isArrayType() &&
"Array to pointer decay must have array source type!");
@@ -828,6 +866,35 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
case CastExpr::CK_NullToMemberPointer:
return CGF.CGM.EmitNullConstant(DestTy);
+ case CastExpr::CK_BaseToDerivedMemberPointer:
+ case CastExpr::CK_DerivedToBaseMemberPointer: {
+ Value *Src = Visit(E);
+
+ // See if we need to adjust the pointer.
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(E->getType()->getAs<MemberPointerType>()->
+ getClass()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *DerivedDecl =
+ cast<CXXRecordDecl>(CE->getType()->getAs<MemberPointerType>()->
+ getClass()->getAs<RecordType>()->getDecl());
+ if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
+ std::swap(DerivedDecl, BaseDecl);
+
+ llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DerivedDecl, BaseDecl);
+ if (Adj) {
+ if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
+ Src = Builder.CreateSub(Src, Adj, "adj");
+ else
+ Src = Builder.CreateAdd(Src, Adj, "adj");
+ }
+ return Src;
+ }
+
+ case CastExpr::CK_UserDefinedConversion:
+ case CastExpr::CK_ConstructorConversion:
+ assert(0 && "Should be unreachable!");
+ break;
+
case CastExpr::CK_IntegralToPointer: {
Value *Src = Visit(const_cast<Expr*>(E));
@@ -841,23 +908,14 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
return Builder.CreateIntToPtr(IntResult, ConvertType(DestTy));
}
-
case CastExpr::CK_PointerToIntegral: {
Value *Src = Visit(const_cast<Expr*>(E));
return Builder.CreatePtrToInt(Src, ConvertType(DestTy));
}
-
case CastExpr::CK_ToVoid: {
CGF.EmitAnyExpr(E, 0, false, true);
return 0;
}
-
- case CastExpr::CK_Dynamic: {
- Value *V = Visit(const_cast<Expr*>(E));
- const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(CE);
- return CGF.EmitDynamicCast(V, DCE);
- }
-
case CastExpr::CK_VectorSplat: {
const llvm::Type *DstTy = ConvertType(DestTy);
Value *Elt = Visit(const_cast<Expr*>(E));
@@ -879,7 +937,40 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat");
return Yay;
}
+ case CastExpr::CK_IntegralCast:
+ case CastExpr::CK_IntegralToFloating:
+ case CastExpr::CK_FloatingToIntegral:
+ 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;
+ }
}
// Handle cases where the source is an non-complex type.
@@ -924,7 +1015,7 @@ Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
llvm::Value *V = CGF.GetAddrOfBlockDecl(E);
if (E->getType().isObjCGCWeak())
return CGF.CGM.getObjCRuntime().EmitObjCWeakRead(CGF, V);
- return Builder.CreateLoad(V, false, "tmp");
+ return Builder.CreateLoad(V, "tmp");
}
//===----------------------------------------------------------------------===//
@@ -1583,10 +1674,10 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
PI != PE; ++PI)
PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI);
- CGF.PushConditionalTempDestruction();
+ CGF.StartConditionalBranch();
CGF.EmitBlock(RHSBlock);
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
- CGF.PopConditionalTempDestruction();
+ CGF.FinishConditionalBranch();
// Reaquire the RHS block, as there may be subblocks inserted.
RHSBlock = Builder.GetInsertBlock();
@@ -1633,13 +1724,13 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
PI != PE; ++PI)
PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI);
- CGF.PushConditionalTempDestruction();
+ CGF.StartConditionalBranch();
// Emit the RHS condition as a bool value.
CGF.EmitBlock(RHSBlock);
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
- CGF.PopConditionalTempDestruction();
+ CGF.FinishConditionalBranch();
// Reaquire the RHS block, as there may be subblocks inserted.
RHSBlock = Builder.GetInsertBlock();
@@ -1753,7 +1844,7 @@ VisitConditionalOperator(const ConditionalOperator *E) {
Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock);
}
- CGF.PushConditionalTempDestruction();
+ CGF.StartConditionalBranch();
CGF.EmitBlock(LHSBlock);
// Handle the GNU extension for missing LHS.
@@ -1763,15 +1854,15 @@ VisitConditionalOperator(const ConditionalOperator *E) {
else // Perform promotions, to handle cases like "short ?: int"
LHS = EmitScalarConversion(CondVal, E->getCond()->getType(), E->getType());
- CGF.PopConditionalTempDestruction();
+ CGF.FinishConditionalBranch();
LHSBlock = Builder.GetInsertBlock();
CGF.EmitBranch(ContBlock);
- CGF.PushConditionalTempDestruction();
+ CGF.StartConditionalBranch();
CGF.EmitBlock(RHSBlock);
Value *RHS = Visit(E->getRHS());
- CGF.PopConditionalTempDestruction();
+ CGF.FinishConditionalBranch();
RHSBlock = Builder.GetInsertBlock();
CGF.EmitBranch(ContBlock);
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index b431daa..be772c7 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -747,9 +747,14 @@ llvm::Constant *CGObjCGNU::GenerateProtocolList(
std::vector<llvm::Constant*> Elements;
for (const std::string *iter = Protocols.begin(), *endIter = Protocols.end();
iter != endIter ; iter++) {
- llvm::Constant *protocol = ExistingProtocols[*iter];
- if (!protocol)
+ llvm::Constant *protocol = 0;
+ llvm::StringMap<llvm::Constant*>::iterator value =
+ ExistingProtocols.find(*iter);
+ if (value == ExistingProtocols.end()) {
protocol = GenerateEmptyProtocol(*iter);
+ } else {
+ protocol = value->getValue();
+ }
llvm::Constant *Ptr = llvm::ConstantExpr::getBitCast(protocol,
PtrToInt8Ty);
Elements.push_back(Ptr);
@@ -1366,8 +1371,8 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
ConstantStrings.size() + 1);
ConstantStrings.push_back(NULLPtr);
- const char *StringClass = CGM.getLangOptions().ObjCConstantStringClass;
- if (!StringClass) StringClass = "NXConstantString";
+ llvm::StringRef StringClass = CGM.getLangOptions().ObjCConstantStringClass;
+ if (StringClass.empty()) StringClass = "NXConstantString";
Elements.push_back(MakeConstantString(StringClass,
".objc_static_class_name"));
Elements.push_back(llvm::ConstantArray::get(StaticsArrayTy,
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 4355e66..2e8ab29 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -2993,7 +2993,7 @@ llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
4, true);
}
- return Builder.CreateLoad(Entry, false, "tmp");
+ return Builder.CreateLoad(Entry, "tmp");
}
llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel) {
@@ -3009,7 +3009,7 @@ llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel) {
4, true);
}
- return Builder.CreateLoad(Entry, false, "tmp");
+ return Builder.CreateLoad(Entry, "tmp");
}
llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) {
@@ -4516,7 +4516,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName);
if (PTGV)
- return Builder.CreateLoad(PTGV, false, "tmp");
+ return Builder.CreateLoad(PTGV, "tmp");
PTGV = new llvm::GlobalVariable(
CGM.getModule(),
Init->getType(), false,
@@ -4526,7 +4526,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
PTGV->setSection("__DATA, __objc_protorefs, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.AddUsedGlobal(PTGV);
- return Builder.CreateLoad(PTGV, false, "tmp");
+ return Builder.CreateLoad(PTGV, "tmp");
}
/// GenerateCategory - Build metadata for a category implementation.
@@ -5031,8 +5031,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset(
CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar) {
- return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar),
- false, "ivar");
+ return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar),"ivar");
}
CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
@@ -5187,7 +5186,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
CGM.AddUsedGlobal(Entry);
}
- return Builder.CreateLoad(Entry, false, "tmp");
+ return Builder.CreateLoad(Entry, "tmp");
}
llvm::Value *
@@ -5210,7 +5209,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
CGM.AddUsedGlobal(Entry);
}
- return Builder.CreateLoad(Entry, false, "tmp");
+ return Builder.CreateLoad(Entry, "tmp");
}
/// EmitMetaClassRef - Return a Value * of the address of _class_t
@@ -5220,7 +5219,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()];
if (Entry)
- return Builder.CreateLoad(Entry, false, "tmp");
+ return Builder.CreateLoad(Entry, "tmp");
std::string MetaClassName(getMetaclassSymbolPrefix() + ID->getNameAsString());
llvm::GlobalVariable *MetaClassGV = GetClassGlobal(MetaClassName);
@@ -5236,7 +5235,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
- return Builder.CreateLoad(Entry, false, "tmp");
+ return Builder.CreateLoad(Entry, "tmp");
}
/// GetClass - Return a reference to the class for the given interface
@@ -5323,7 +5322,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
CGM.AddUsedGlobal(Entry);
}
- return Builder.CreateLoad(Entry, false, "tmp");
+ return Builder.CreateLoad(Entry, "tmp");
}
/// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
/// objc_assign_ivar (id src, id *dst, ptrdiff_t)
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index a63c832..1a9bc39 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -330,36 +330,6 @@ void CGRecordLayoutBuilder::CheckForMemberPointer(const FieldDecl *FD) {
}
-static const CXXMethodDecl *GetKeyFunction(const RecordDecl *D) {
- const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D);
- if (!RD || !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;
-
- // FIXME: This doesn't work. If we have an out of line body, that body will
- // set the MD to have a body, what we want to know is, was the body present
- // inside the declaration of the class. For now, we just avoid the problem
- // by pretending there is no key function.
- return 0;
- if (MD->getBody())
- continue;
-
- // We found it.
- return MD;
- }
-
- return 0;
-}
-
CGRecordLayout *
CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types,
const RecordDecl *D) {
@@ -389,7 +359,5 @@ CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types,
Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size);
}
- const CXXMethodDecl *KeyFunction = GetKeyFunction(D);
-
- return new CGRecordLayout(Ty, Builder.ContainsMemberPointer, KeyFunction);
+ return new CGRecordLayout(Ty, Builder.ContainsMemberPointer);
}
diff --git a/lib/CodeGen/CGRtti.cpp b/lib/CodeGen/CGRtti.cpp
index 79d8664..43fcb31 100644
--- a/lib/CodeGen/CGRtti.cpp
+++ b/lib/CodeGen/CGRtti.cpp
@@ -49,9 +49,8 @@ public:
llvm::Constant *BuildName(QualType Ty, bool Hidden, bool Extern) {
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXRttiName(CGM.getMangleContext(), Ty, Out);
- llvm::StringRef Name = Out.str();
+ CGM.getMangleContext().mangleCXXRttiName(Ty, OutName);
+ llvm::StringRef Name = OutName.str();
llvm::GlobalVariable::LinkageTypes linktype;
linktype = llvm::GlobalValue::LinkOnceODRLinkage;
@@ -99,9 +98,8 @@ public:
return llvm::Constant::getNullValue(Int8PtrTy);
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXRtti(CGM.getMangleContext(), Ty, Out);
- llvm::StringRef Name = Out.str();
+ CGM.getMangleContext().mangleCXXRtti(Ty, OutName);
+ llvm::StringRef Name = OutName.str();
C = CGM.getModule().getGlobalVariable(Name);
if (C)
@@ -194,10 +192,9 @@ public:
llvm::Constant *C;
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXRtti(CGM.getMangleContext(), CGM.getContext().getTagDeclType(RD),
- Out);
- llvm::StringRef Name = Out.str();
+ CGM.getMangleContext().mangleCXXRtti(CGM.getContext().getTagDeclType(RD),
+ OutName);
+ llvm::StringRef Name = OutName.str();
llvm::GlobalVariable *GV;
GV = CGM.getModule().getGlobalVariable(Name);
@@ -260,13 +257,6 @@ public:
return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), f);
}
- llvm::Constant *BuildType2(QualType Ty) {
- if (const RecordType *RT = Ty.getTypePtr()->getAs<RecordType>())
- if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()))
- return Buildclass_type_info(RD);
- return BuildType(Ty);
- }
-
bool DecideExtern(QualType Ty) {
// For this type, see if all components are never in an anonymous namespace.
if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>())
@@ -297,9 +287,8 @@ public:
llvm::Constant *C;
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXRtti(CGM.getMangleContext(), Ty, Out);
- llvm::StringRef Name = Out.str();
+ CGM.getMangleContext().mangleCXXRtti(Ty, OutName);
+ llvm::StringRef Name = OutName.str();
llvm::GlobalVariable *GV;
GV = CGM.getModule().getGlobalVariable(Name);
@@ -338,10 +327,10 @@ public:
info.push_back(BuildInt(flags));
info.push_back(BuildInt(0));
- info.push_back(BuildType2(PTy));
+ info.push_back(BuildType(PTy));
if (PtrMem)
- info.push_back(BuildType2(BTy));
+ info.push_back(BuildType(BTy));
// We always generate these as hidden, only the name isn't hidden.
return finish(info, GV, Name, true, Extern);
@@ -351,9 +340,8 @@ public:
llvm::Constant *C;
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXRtti(CGM.getMangleContext(), Ty, Out);
- llvm::StringRef Name = Out.str();
+ CGM.getMangleContext().mangleCXXRtti(Ty, OutName);
+ llvm::StringRef Name = OutName.str();
llvm::GlobalVariable *GV;
GV = CGM.getModule().getGlobalVariable(Name);
@@ -376,6 +364,11 @@ public:
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);
+
switch (Type.getTypeClass()) {
default: {
assert(0 && "typeid expression");
@@ -426,7 +419,7 @@ llvm::Constant *CodeGenModule::GenerateRtti(const CXXRecordDecl *RD) {
return b.Buildclass_type_info(RD);
}
-llvm::Constant *CodeGenModule::GenerateRttiNonClass(QualType Ty) {
+llvm::Constant *CodeGenModule::GenerateRtti(QualType Ty) {
RttiBuilder b(*this);
return b.BuildType(Ty);
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index b6d7b39..bbd5462 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -153,9 +153,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
}
// Keep track of the current cleanup stack depth.
- size_t CleanupStackDepth = CleanupEntries.size();
- bool OldDidCallStackSave = DidCallStackSave;
- DidCallStackSave = false;
+ CleanupScope Scope(*this);
for (CompoundStmt::const_body_iterator I = S.body_begin(),
E = S.body_end()-GetLast; I != E; ++I)
@@ -185,10 +183,6 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
RV = EmitAnyExpr(cast<Expr>(LastStmt), AggLoc);
}
- DidCallStackSave = OldDidCallStackSave;
-
- EmitCleanupBlocks(CleanupStackDepth);
-
return RV;
}
@@ -294,6 +288,10 @@ void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) {
void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// C99 6.8.4.1: The first substatement is executed if the expression compares
// unequal to 0. The condition must be a scalar type.
+ CleanupScope ConditionScope(*this);
+
+ if (S.getConditionVariable())
+ EmitLocalBlockVarDecl(*S.getConditionVariable());
// If the condition constant folds and can be elided, try to avoid emitting
// the condition and the dead arm of the if/else.
@@ -306,8 +304,10 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// If the skipped block has no labels in it, just emit the executed block.
// This avoids emitting dead code and simplifies the CFG substantially.
if (!ContainsLabel(Skipped)) {
- if (Executed)
+ if (Executed) {
+ CleanupScope ExecutedScope(*this);
EmitStmt(Executed);
+ }
return;
}
}
@@ -322,14 +322,20 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock);
// Emit the 'then' code.
- EmitBlock(ThenBlock);
- EmitStmt(S.getThen());
+ EmitBlock(ThenBlock);
+ {
+ CleanupScope ThenScope(*this);
+ EmitStmt(S.getThen());
+ }
EmitBranch(ContBlock);
// Emit the 'else' code if present.
if (const Stmt *Else = S.getElse()) {
EmitBlock(ElseBlock);
- EmitStmt(Else);
+ {
+ CleanupScope ElseScope(*this);
+ EmitStmt(Else);
+ }
EmitBranch(ContBlock);
}
@@ -347,15 +353,37 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
// body of the loop.
llvm::BasicBlock *ExitBlock = createBasicBlock("while.end");
llvm::BasicBlock *LoopBody = createBasicBlock("while.body");
+ llvm::BasicBlock *CleanupBlock = 0;
+ llvm::BasicBlock *EffectiveExitBlock = ExitBlock;
// Store the blocks to use for break and continue.
BreakContinueStack.push_back(BreakContinue(ExitBlock, LoopHeader));
+ // C++ [stmt.while]p2:
+ // When the condition of a while statement is a declaration, the
+ // scope of the variable that is declared extends from its point
+ // of declaration (3.3.2) to the end of the while statement.
+ // [...]
+ // The object created in a condition is destroyed and created
+ // with each iteration of the loop.
+ CleanupScope ConditionScope(*this);
+
+ if (S.getConditionVariable()) {
+ EmitLocalBlockVarDecl(*S.getConditionVariable());
+
+ // If this condition variable requires cleanups, create a basic
+ // block to handle those cleanups.
+ if (ConditionScope.requiresCleanups()) {
+ CleanupBlock = createBasicBlock("while.cleanup");
+ EffectiveExitBlock = CleanupBlock;
+ }
+ }
+
// Evaluate the conditional in the while header. C99 6.8.5.1: The
// evaluation of the controlling expression takes place before each
// execution of the loop body.
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
-
+
// while(1) is common, avoid extra exit blocks. Be sure
// to correctly handle break/continue though.
bool EmitBoolCondBranch = true;
@@ -365,23 +393,39 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
// As long as the condition is true, go to the loop body.
if (EmitBoolCondBranch)
- Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock);
-
+ Builder.CreateCondBr(BoolCondVal, LoopBody, EffectiveExitBlock);
+
// Emit the loop body.
- EmitBlock(LoopBody);
- EmitStmt(S.getBody());
+ {
+ CleanupScope BodyScope(*this);
+ EmitBlock(LoopBody);
+ EmitStmt(S.getBody());
+ }
BreakContinueStack.pop_back();
- // Cycle to the condition.
- EmitBranch(LoopHeader);
+ if (CleanupBlock) {
+ // If we have a cleanup block, jump there to perform cleanups
+ // before looping.
+ EmitBranch(CleanupBlock);
+
+ // Emit the cleanup block, performing cleanups for the condition
+ // and then jumping to either the loop header or the exit block.
+ EmitBlock(CleanupBlock);
+ ConditionScope.ForceCleanup();
+ Builder.CreateCondBr(BoolCondVal, LoopHeader, ExitBlock);
+ } else {
+ // Cycle to the condition.
+ EmitBranch(LoopHeader);
+ }
// Emit the exit block.
EmitBlock(ExitBlock, true);
+
// The LoopHeader typically is just a branch if we skipped emitting
// a branch, try to erase it.
- if (!EmitBoolCondBranch)
+ if (!EmitBoolCondBranch && !CleanupBlock)
SimplifyForwardingBlocks(LoopHeader);
}
@@ -435,6 +479,7 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
void CodeGenFunction::EmitForStmt(const ForStmt &S) {
// FIXME: What do we do if the increment (f.e.) contains a stmt expression,
// which contains a continue/break?
+ CleanupScope ForScope(*this);
// Evaluate the first part before the loop.
if (S.getInit())
@@ -443,18 +488,34 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
// Start the loop with a block that tests the condition.
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
-
+ llvm::BasicBlock *IncBlock = 0;
+ llvm::BasicBlock *CondCleanup = 0;
+ llvm::BasicBlock *EffectiveExitBlock = AfterFor;
EmitBlock(CondBlock);
- // Evaluate the condition if present. If not, treat it as a
- // non-zero-constant according to 6.8.5.3p2, aka, true.
+ // Create a cleanup scope for the condition variable cleanups.
+ CleanupScope ConditionScope(*this);
+
+ llvm::Value *BoolCondVal = 0;
if (S.getCond()) {
+ // If the for statement has a condition scope, emit the local variable
+ // declaration.
+ if (S.getConditionVariable()) {
+ EmitLocalBlockVarDecl(*S.getConditionVariable());
+
+ if (ConditionScope.requiresCleanups()) {
+ CondCleanup = createBasicBlock("for.cond.cleanup");
+ EffectiveExitBlock = CondCleanup;
+ }
+ }
+
// As long as the condition is true, iterate the loop.
llvm::BasicBlock *ForBody = createBasicBlock("for.body");
// C99 6.8.5p2/p4: The first substatement is executed if the expression
// compares unequal to 0. The condition must be a scalar type.
- EmitBranchOnBoolExpr(S.getCond(), ForBody, AfterFor);
+ BoolCondVal = EvaluateExprAsBool(S.getCond());
+ Builder.CreateCondBr(BoolCondVal, ForBody, EffectiveExitBlock);
EmitBlock(ForBody);
} else {
@@ -466,7 +527,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
// condition as the continue block.
llvm::BasicBlock *ContinueBlock;
if (S.getInc())
- ContinueBlock = createBasicBlock("for.inc");
+ ContinueBlock = IncBlock = createBasicBlock("for.inc");
else
ContinueBlock = CondBlock;
@@ -479,18 +540,34 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
DI->setLocation(S.getSourceRange().getBegin());
DI->EmitRegionStart(CurFn, Builder);
}
- EmitStmt(S.getBody());
+
+ {
+ // Create a separate cleanup scope for the body, in case it is not
+ // a compound statement.
+ CleanupScope BodyScope(*this);
+ EmitStmt(S.getBody());
+ }
BreakContinueStack.pop_back();
// If there is an increment, emit it next.
if (S.getInc()) {
- EmitBlock(ContinueBlock);
+ EmitBlock(IncBlock);
EmitStmt(S.getInc());
}
// Finally, branch back up to the condition for the next iteration.
- EmitBranch(CondBlock);
+ if (CondCleanup) {
+ // Branch to the cleanup block.
+ EmitBranch(CondCleanup);
+
+ // Emit the cleanup block, which branches back to the loop body or
+ // outside of the for statement once it is done.
+ EmitBlock(CondCleanup);
+ ConditionScope.ForceCleanup();
+ Builder.CreateCondBr(BoolCondVal, CondBlock, AfterFor);
+ } else
+ EmitBranch(CondBlock);
if (DI) {
DI->setLocation(S.getSourceRange().getEnd());
DI->EmitRegionEnd(CurFn, Builder);
@@ -686,6 +763,11 @@ void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S) {
}
void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
+ CleanupScope ConditionScope(*this);
+
+ if (S.getConditionVariable())
+ EmitLocalBlockVarDecl(*S.getConditionVariable());
+
llvm::Value *CondV = EmitScalarExpr(S.getCond());
// Handle nested switch statements.
diff --git a/lib/CodeGen/CGCXXTemp.cpp b/lib/CodeGen/CGTemporaries.cpp
index 4768556..5cfc7ef 100644
--- a/lib/CodeGen/CGCXXTemp.cpp
+++ b/lib/CodeGen/CGTemporaries.cpp
@@ -1,4 +1,4 @@
-//===--- CGCXXTemp.cpp - Emit LLVM Code for C++ temporaries ---------------===//
+//===--- CGTemporaries.cpp - Emit LLVM Code for C++ temporaries -----------===//
//
// The LLVM Compiler Infrastructure
//
@@ -23,7 +23,7 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
// Check if temporaries need to be conditional. If so, we'll create a
// condition boolean, initialize it to 0 and
- if (!ConditionalTempDestructionStack.empty()) {
+ if (ConditionalBranchLevel != 0) {
CondPtr = CreateTempAlloca(llvm::Type::getInt1Ty(VMContext), "cond");
// Initialize it to false. This initialization takes place right after
@@ -141,23 +141,3 @@ LValue CodeGenFunction::EmitCXXExprWithTemporariesLValue(
return LV;
}
-
-void
-CodeGenFunction::PushConditionalTempDestruction() {
- // Store the current number of live temporaries.
- ConditionalTempDestructionStack.push_back(LiveTemporaries.size());
-}
-
-void CodeGenFunction::PopConditionalTempDestruction() {
- size_t NumLiveTemporaries = ConditionalTempDestructionStack.back();
- ConditionalTempDestructionStack.pop_back();
-
- // Pop temporaries.
- while (LiveTemporaries.size() > NumLiveTemporaries) {
- assert(LiveTemporaries.back().CondPtr &&
- "Conditional temporary must have a cond ptr!");
-
- PopCXXTemporary();
- }
-}
-
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index 9be1a3b..715aa4c 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -13,13 +13,15 @@
#include "CodeGenModule.h"
#include "CodeGenFunction.h"
-
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/RecordLayout.h"
+#include "llvm/ADT/DenseSet.h"
#include <cstdio>
using namespace clang;
using namespace CodeGen;
+namespace {
class VtableBuilder {
public:
/// Index_t - Vtable index type.
@@ -52,54 +54,110 @@ private:
llvm::DenseMap<GlobalDecl, Index_t> NonVirtualOffset;
llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex;
- typedef llvm::DenseMap<GlobalDecl, int> Pures_t;
- Pures_t Pures;
- typedef std::pair<Index_t, Index_t> CallOffset;
- typedef llvm::DenseMap<GlobalDecl, CallOffset> Thunks_t;
- Thunks_t Thunks;
- typedef llvm::DenseMap<GlobalDecl,
- std::pair<std::pair<CallOffset, CallOffset>,
- CanQualType> > CovariantThunks_t;
- CovariantThunks_t CovariantThunks;
+ /// 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;
+
+ /// Adjustment - The thunk adjustment.
+ ThunkAdjustment Adjustment;
+ };
+
+ /// Thunks - The thunks in a vtable.
+ typedef llvm::DenseMap<GlobalDecl, Thunk> ThunksMapTy;
+ ThunksMapTy Thunks;
+
+ /// 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;
+
+ /// ReturnType - The return type of the function.
+ CanQualType ReturnType;
+ };
+
+ /// CovariantThunks - The covariant thunks in a vtable.
+ typedef llvm::DenseMap<GlobalDecl, CovariantThunk> CovariantThunksMapTy;
+ CovariantThunksMapTy CovariantThunks;
+
+ /// 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;
- // CtorVtable - Used to hold the AddressPoints (offsets) into the built vtable
- // for use in computing the initializers for the VTT.
- llvm::DenseMap<CtorVtable_t, int64_t> &AddressPoints;
+ // subAddressPoints - Used to hold the AddressPoints (offsets) into the built
+ // vtable for use in computing the initializers for the VTT.
+ llvm::DenseMap<CtorVtable_t, int64_t> &subAddressPoints;
typedef CXXRecordDecl::method_iterator method_iter;
const bool Extern;
const uint32_t LLVMPointerWidth;
Index_t extra;
typedef std::vector<std::pair<const CXXRecordDecl *, int64_t> > Path_t;
- llvm::Constant *cxa_pure;
+ static llvm::DenseMap<CtorVtable_t, int64_t>&
+ AllocAddressPoint(CodeGenModule &cgm, const CXXRecordDecl *l,
+ const CXXRecordDecl *c) {
+ CodeGenModule::AddrMap_t *&oref = cgm.AddressPoints[l];
+ if (oref == 0)
+ oref = new CodeGenModule::AddrMap_t;
+
+ llvm::DenseMap<CtorVtable_t, int64_t> *&ref = (*oref)[c];
+ if (ref == 0)
+ ref = new llvm::DenseMap<CtorVtable_t, int64_t>;
+ return *ref;
+ }
+
+ /// getPureVirtualFn - Return the __cxa_pure_virtual function.
+ llvm::Constant* getPureVirtualFn() {
+ if (!PureVirtualFn) {
+ const llvm::FunctionType *Ty =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ /*isVarArg=*/false);
+ PureVirtualFn = wrap(CGM.CreateRuntimeFunction(Ty, "__cxa_pure_virtual"));
+ }
+
+ return PureVirtualFn;
+ }
+
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), AddressPoints(*new llvm::DenseMap<CtorVtable_t, int64_t>),
+ CGM(cgm), PureVirtualFn(0),subAddressPoints(AllocAddressPoint(cgm, l, c)),
Extern(!l->isInAnonymousNamespace()),
- LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) {
+ LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) {
Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
-
- // Calculate pointer for ___cxa_pure_virtual.
- const llvm::FunctionType *FTy;
- std::vector<const llvm::Type*> ArgTys;
- const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext);
- FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
- cxa_pure = wrap(CGM.CreateRuntimeFunction(FTy, "__cxa_pure_virtual"));
}
llvm::DenseMap<GlobalDecl, Index_t> &getIndex() { return Index; }
llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex()
{ return VBIndex; }
- llvm::DenseMap<CtorVtable_t, int64_t> *getAddressPoints()
- { return &AddressPoints; }
-
llvm::Constant *wrap(Index_t i) {
llvm::Constant *m;
m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i);
@@ -147,8 +205,6 @@ public:
SeenVBase.clear();
}
- Index_t VBlookup(CXXRecordDecl *D, CXXRecordDecl *B);
-
Index_t getNVOffset_1(const CXXRecordDecl *D, const CXXRecordDecl *B,
Index_t Offset = 0) {
@@ -194,7 +250,7 @@ public:
CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
if (D != Class)
- return VBlookup(D, B);
+ return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B);
llvm::DenseMap<const CXXRecordDecl *, Index_t>::iterator i;
i = VBIndex.find(B);
if (i != VBIndex.end())
@@ -242,22 +298,23 @@ public:
CanQualType oret = CGM.getContext().getCanonicalType(nc_oret);
QualType nc_ret = MD->getType()->getAs<FunctionType>()->getResultType();
CanQualType ret = CGM.getContext().getCanonicalType(nc_ret);
- CallOffset ReturnOffset = std::make_pair(0, 0);
+ ThunkAdjustment ReturnAdjustment;
if (oret != ret) {
// FIXME: calculate offsets for covariance
- if (CovariantThunks.count(OMD)) {
- oret = CovariantThunks[OMD].second;
- CovariantThunks.erase(OMD);
+ 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;
- ReturnOffset = std::make_pair(nv, getVbaseOffset(oret, ret));
+ ReturnAdjustment = ThunkAdjustment(nv, getVbaseOffset(oret, ret));
}
Index[GD] = i;
submethods[i] = m;
if (isPure)
- Pures[GD] = 1;
- Pures.erase(OGD);
+ PureVirtualMethods.insert(GD);
+ PureVirtualMethods.erase(OGD);
Thunks.erase(OGD);
if (MorallyVirtual || VCall.count(OGD)) {
Index_t &idx = VCall[OGD];
@@ -278,35 +335,38 @@ public:
(int)VCalls[idx-1], Class->getNameAsCString()));
}
VCall[GD] = idx;
- int64_t O = NonVirtualOffset[GD];
- int v = -((idx+extra+2)*LLVMPointerWidth/8);
+ int64_t NonVirtualAdjustment = NonVirtualOffset[GD];
+ int64_t VirtualAdjustment =
+ -((idx + extra + 2) * LLVMPointerWidth / 8);
+
// Optimize out virtual adjustments of 0.
if (VCalls[idx-1] == 0)
- v = 0;
- CallOffset ThisOffset = std::make_pair(O, v);
+ 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 (ReturnOffset.first || ReturnOffset.second)
- CovariantThunks[GD] = std::make_pair(std::make_pair(ThisOffset,
- ReturnOffset),
- oret);
- else if (!isPure && (ThisOffset.first || ThisOffset.second))
- Thunks[GD] = ThisOffset;
+ 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 O = VCallOffset[OGD] - OverrideOffset/8;
+ int64_t NonVirtualAdjustment = VCallOffset[OGD] - OverrideOffset/8;
- if (O || ReturnOffset.first || ReturnOffset.second) {
- CallOffset ThisOffset = std::make_pair(O, 0);
+ if (NonVirtualAdjustment || !ReturnAdjustment.isEmpty()) {
+ ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0);
- if (ReturnOffset.first || ReturnOffset.second)
- CovariantThunks[GD] = std::make_pair(std::make_pair(ThisOffset,
- ReturnOffset),
- oret);
- else if (!isPure)
- Thunks[GD] = ThisOffset;
+ if (!ReturnAdjustment.isEmpty()) {
+ CovariantThunks[GD] =
+ CovariantThunk(i, ThisAdjustment, ReturnAdjustment, oret);
+ } else if (!isPure)
+ Thunks[GD] = Thunk(i, ThisAdjustment);
}
return true;
}
@@ -316,40 +376,39 @@ public:
}
void InstallThunks() {
- for (Thunks_t::iterator i = Thunks.begin(), e = Thunks.end();
+ 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() && "Trying to thunk a pure");
- Index_t idx = Index[GD];
- Index_t nv_O = i->second.first;
- Index_t v_O = i->second.second;
- submethods[idx] = CGM.BuildThunk(MD, Extern, nv_O, v_O);
+ 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 (CovariantThunks_t::iterator i = CovariantThunks.begin(),
- e = CovariantThunks.end();
- i != e; ++i) {
+
+ 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;
- Index_t idx = Index[GD];
- Index_t nv_t = i->second.first.first.first;
- Index_t v_t = i->second.first.first.second;
- Index_t nv_r = i->second.first.second.first;
- Index_t v_r = i->second.first.second.second;
- submethods[idx] = CGM.BuildCovariantThunk(MD, Extern, nv_t, v_t, nv_r,
- v_r);
+
+ 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 (Pures_t::iterator i = Pures.begin(), e = Pures.end();
- i != e; ++i) {
- GlobalDecl GD = i->first;
- Index_t idx = Index[GD];
- submethods[idx] = cxa_pure;
+
+ for (PureVirtualMethodsSetTy::iterator i = PureVirtualMethods.begin(),
+ e = PureVirtualMethods.end(); i != e; ++i) {
+ GlobalDecl GD = *i;
+ submethods[Index[GD]] = getPureVirtualFn();
}
- Pures.clear();
+ PureVirtualMethods.clear();
}
llvm::Constant *WrapAddrOf(GlobalDecl GD) {
@@ -358,10 +417,7 @@ public:
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD))
return wrap(CGM.GetAddrOfCXXDestructor(Dtor, GD.getDtorType()));
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
+ const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD);
return wrap(CGM.GetAddrOfFunction(MD, Ty));
}
@@ -397,7 +453,7 @@ public:
}
void AddMethod(const GlobalDecl GD, bool MorallyVirtual, Index_t Offset,
- bool ForVirtualBase, int64_t CurrentVBaseOffset) {
+ int64_t CurrentVBaseOffset) {
llvm::Constant *m = WrapAddrOf(GD);
// If we can find a previously allocated slot for this, reuse it.
@@ -413,7 +469,7 @@ public:
D1(printf(" vfn for %s at %d\n", MD->getNameAsString().c_str(),
(int)Index[GD]));
if (MD->isPure())
- Pures[GD] = 1;
+ PureVirtualMethods.insert(GD);
if (MorallyVirtual) {
VCallOffset[GD] = Offset/8;
Index_t &idx = VCall[GD];
@@ -429,8 +485,7 @@ public:
}
void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual,
- Index_t Offset, bool RDisVirtualBase,
- int64_t CurrentVBaseOffset) {
+ Index_t Offset, int64_t CurrentVBaseOffset) {
for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
++mi) {
const CXXMethodDecl *MD = *mi;
@@ -441,12 +496,11 @@ public:
// For destructors, add both the complete and the deleting destructor
// to the vtable.
AddMethod(GlobalDecl(DD, Dtor_Complete), MorallyVirtual, Offset,
- RDisVirtualBase, CurrentVBaseOffset);
+ CurrentVBaseOffset);
AddMethod(GlobalDecl(DD, Dtor_Deleting), MorallyVirtual, Offset,
- RDisVirtualBase, CurrentVBaseOffset);
- } else
- AddMethod(MD, MorallyVirtual, Offset, RDisVirtualBase,
CurrentVBaseOffset);
+ } else
+ AddMethod(MD, MorallyVirtual, Offset, CurrentVBaseOffset);
}
}
@@ -495,7 +549,7 @@ public:
D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n",
RD->getNameAsCString(), Class->getNameAsCString(),
LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
- AddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
+ subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
// Now also add the address point for all our primary bases.
while (1) {
@@ -511,7 +565,7 @@ public:
D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n",
RD->getNameAsCString(), Class->getNameAsCString(),
LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
- AddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
+ subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
}
}
@@ -572,7 +626,7 @@ public:
void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
bool updateVBIndex, Index_t current_vbindex,
- bool RDisVirtualBase, int64_t CurrentVBaseOffset) {
+ int64_t CurrentVBaseOffset) {
if (!RD->isDynamicClass())
return;
@@ -591,21 +645,20 @@ public:
if (!PrimaryBaseWasVirtual)
Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
- updateVBIndex, current_vbindex, PrimaryBaseWasVirtual,
- BaseCurrentVBaseOffset);
+ updateVBIndex, current_vbindex, BaseCurrentVBaseOffset);
}
D1(printf(" doing vcall entries for %s most derived %s\n",
RD->getNameAsCString(), Class->getNameAsCString()));
// And add the virtuals for the class to the primary vtable.
- AddMethods(RD, MorallyVirtual, Offset, RDisVirtualBase, CurrentVBaseOffset);
+ AddMethods(RD, MorallyVirtual, Offset, CurrentVBaseOffset);
}
void VBPrimaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
bool updateVBIndex, Index_t current_vbindex,
bool RDisVirtualBase, int64_t CurrentVBaseOffset,
- bool bottom=false) {
+ bool bottom) {
if (!RD->isDynamicClass())
return;
@@ -626,7 +679,7 @@ public:
VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
updateVBIndex, current_vbindex, PrimaryBaseWasVirtual,
- BaseCurrentVBaseOffset);
+ BaseCurrentVBaseOffset, false);
}
D1(printf(" doing vbase entries for %s most derived %s\n",
@@ -635,7 +688,7 @@ public:
if (RDisVirtualBase || bottom) {
Primaries(RD, MorallyVirtual, Offset, updateVBIndex, current_vbindex,
- RDisVirtualBase, CurrentVBaseOffset);
+ CurrentVBaseOffset);
}
}
@@ -718,30 +771,223 @@ public:
}
};
+}
+
+/// TypeConversionRequiresAdjustment - Returns whether conversion from a
+/// derived type to a base type requires adjustment.
+static bool
+TypeConversionRequiresAdjustment(ASTContext &Ctx,
+ const CXXRecordDecl *DerivedDecl,
+ const CXXRecordDecl *BaseDecl) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/false,
+ /*RecordPaths=*/true, /*DetectVirtual=*/true);
+ if (!const_cast<CXXRecordDecl *>(DerivedDecl)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseDecl), Paths)) {
+ assert(false && "Class must be derived from the passed in base class!");
+ return false;
+ }
+
+ // 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;
+ }
+ }
+
+ return false;
+}
+
+static bool
+TypeConversionRequiresAdjustment(ASTContext &Ctx,
+ QualType DerivedType, QualType BaseType) {
+ // Canonicalize the types.
+ QualType CanDerivedType = Ctx.getCanonicalType(DerivedType);
+ QualType CanBaseType = Ctx.getCanonicalType(BaseType);
+
+ assert(CanDerivedType->getTypeClass() == CanBaseType->getTypeClass() &&
+ "Types must have same type class!");
+
+ if (CanDerivedType == CanBaseType) {
+ // No adjustment needed.
+ return false;
+ }
+
+ if (const ReferenceType *RT = dyn_cast<ReferenceType>(CanDerivedType)) {
+ CanDerivedType = RT->getPointeeType();
+ CanBaseType = cast<ReferenceType>(CanBaseType)->getPointeeType();
+ } else if (const PointerType *PT = dyn_cast<PointerType>(CanDerivedType)) {
+ CanDerivedType = PT->getPointeeType();
+ CanBaseType = cast<PointerType>(CanBaseType)->getPointeeType();
+ } else {
+ assert(false && "Unexpected return type!");
+ }
+
+ if (CanDerivedType == CanBaseType) {
+ // No adjustment needed.
+ return false;
+ }
+
+ const CXXRecordDecl *DerivedDecl =
+ cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl());
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl());
+
+ return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl);
+}
+
+void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
+
+ // Itanium C++ ABI 2.5.2:
+ // The order of the virtual function pointers in a virtual table is the
+ // order of declaration of the corresponding member functions in the class.
+ //
+ // There is an entry for any virtual function declared in a class,
+ // whether it is a new function or overrides a base class function,
+ // unless it overrides a function from the primary base, and conversion
+ // between their return types does not require an adjustment.
+
+ int64_t CurrentIndex = 0;
+
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ if (PrimaryBase) {
+ assert(PrimaryBase->isDefinition() &&
+ "Should have the definition decl of the primary base!");
-VtableBuilder::Index_t VtableBuilder::VBlookup(CXXRecordDecl *D,
- CXXRecordDecl *B) {
- return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B);
+ // Since the record decl shares its vtable pointer with the primary base
+ // we need to start counting at the end of the primary base's vtable.
+ CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase);
+ }
+
+ const CXXDestructorDecl *ImplicitVirtualDtor = 0;
+
+ for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+ e = RD->method_end(); i != e; ++i) {
+ const CXXMethodDecl *MD = *i;
+
+ // We only want virtual methods.
+ if (!MD->isVirtual())
+ continue;
+
+ bool ShouldAddEntryForMethod = true;
+
+ // Check if this method overrides a method in the primary base.
+ for (CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(),
+ e = MD->end_overridden_methods(); i != e; ++i) {
+ const CXXMethodDecl *OverriddenMD = *i;
+ const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent();
+ assert(OverriddenMD->isCanonicalDecl() &&
+ "Should have the canonical decl of the overridden RD!");
+
+ if (OverriddenRD == PrimaryBase) {
+ // Check if converting from the return type of the method to the
+ // return type of the overridden method requires conversion.
+ QualType ReturnType =
+ MD->getType()->getAs<FunctionType>()->getResultType();
+ QualType OverriddenReturnType =
+ OverriddenMD->getType()->getAs<FunctionType>()->getResultType();
+
+ if (!TypeConversionRequiresAdjustment(CGM.getContext(),
+ ReturnType, OverriddenReturnType)) {
+ // This index is shared between the index in the vtable of the primary
+ // base class.
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ const CXXDestructorDecl *OverriddenDD =
+ cast<CXXDestructorDecl>(OverriddenMD);
+
+ // Add both the complete and deleting entries.
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] =
+ getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+ getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ } else {
+ MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD);
+ }
+
+ // We don't need to add an entry for this method.
+ ShouldAddEntryForMethod = false;
+ break;
+ }
+ }
+ }
+
+ if (!ShouldAddEntryForMethod)
+ continue;
+
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ if (MD->isImplicit()) {
+ assert(!ImplicitVirtualDtor &&
+ "Did already see an implicit virtual dtor!");
+ ImplicitVirtualDtor = DD;
+ continue;
+ }
+
+ // Add the complete dtor.
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
+
+ // Add the deleting dtor.
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ } else {
+ // Add the entry.
+ MethodVtableIndices[MD] = CurrentIndex++;
+ }
+ }
+
+ if (ImplicitVirtualDtor) {
+ // Itanium C++ ABI 2.5.2:
+ // If a class has an implicitly-defined virtual destructor,
+ // its entries come after the declared virtual function pointers.
+
+ // Add the complete dtor.
+ MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
+ CurrentIndex++;
+
+ // Add the deleting dtor.
+ MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] =
+ CurrentIndex++;
+ }
+
+ NumVirtualFunctionPointers[RD] = CurrentIndex;
}
-int64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) {
+uint64_t CGVtableInfo::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) {
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
+ NumVirtualFunctionPointers.find(RD);
+ if (I != NumVirtualFunctionPointers.end())
+ return I->second;
+
+ ComputeMethodVtableIndices(RD);
+
+ I = NumVirtualFunctionPointers.find(RD);
+ assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!");
+ return I->second;
+}
+
+uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) {
MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD);
if (I != MethodVtableIndices.end())
return I->second;
const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
-
- 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);
- D1(printf("vtable %s\n", RD->getNameAsCString()));
- b.GenerateVtableForBase(RD);
- b.GenerateVtableForVBases(RD);
-
- MethodVtableIndices.insert(b.getIndex().begin(),
- b.getIndex().end());
-
+
+ ComputeMethodVtableIndices(RD);
+
I = MethodVtableIndices.find(GD);
assert(I != MethodVtableIndices.end() && "Did not find index!");
return I->second;
@@ -782,22 +1028,25 @@ llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass,
const CXXRecordDecl *RD,
uint64_t Offset) {
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
if (LayoutClass != RD)
- mangleCXXCtorVtable(getMangleContext(), LayoutClass, Offset/8, RD, Out);
+ getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset/8, RD, OutName);
else
- mangleCXXVtable(getMangleContext(), RD, Out);
- llvm::StringRef Name = Out.str();
+ 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())
+ if (GV && AddressPoints[LayoutClass] && !GV->isDeclaration()) {
AddressPoint=(*(*(AddressPoints[LayoutClass]))[RD])[std::make_pair(RD,
Offset)];
- else {
+ // 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);
D1(printf("vtable %s\n", RD->getNameAsCString()));
@@ -807,20 +1056,14 @@ llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass,
// then the vtables for all the virtual bases.
b.GenerateVtableForVBases(RD, Offset);
- CodeGenModule::AddrMap_t *&ref = AddressPoints[LayoutClass];
- if (ref == 0)
- ref = new CodeGenModule::AddrMap_t;
-
- (*ref)[RD] = b.getAddressPoints();
-
bool CreateDefinition = true;
if (LayoutClass != RD)
CreateDefinition = true;
else {
- // We have to convert it to have a record layout.
- Types.ConvertTagDeclType(LayoutClass);
- const CGRecordLayout &CGLayout = Types.getCGRecordLayout(LayoutClass);
- if (const CXXMethodDecl *KeyFunction = CGLayout.getKeyFunction()) {
+ 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.
@@ -862,6 +1105,7 @@ llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass,
vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(vtable, &AddressPointC,
1);
+ assert(vtable->getType() == Ptr8Ty);
return vtable;
}
@@ -888,7 +1132,7 @@ class VTTBuilder {
int64_t AddressPoint;
AddressPoint = (*AddressPoints[VtblClass])[std::make_pair(RD, Offset)];
// FIXME: We can never have 0 address point. Do this for now so gepping
- // retains the same structure.
+ // retains the same structure. Later we'll just assert.
if (AddressPoint == 0)
AddressPoint = 1;
D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n",
@@ -1034,9 +1278,8 @@ llvm::Constant *CodeGenModule::GenerateVTT(const CXXRecordDecl *RD) {
return 0;
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXVTT(getMangleContext(), RD, Out);
- llvm::StringRef Name = Out.str();
+ getMangleContext().mangleCXXVTT(RD, OutName);
+ llvm::StringRef Name = OutName.str();
llvm::GlobalVariable::LinkageTypes linktype;
linktype = llvm::GlobalValue::LinkOnceODRLinkage;
@@ -1073,10 +1316,9 @@ llvm::Constant *CGVtableInfo::getVtable(const CXXRecordDecl *RD) {
vtbl = CGM.GenerateVtable(RD, RD);
bool CreateDefinition = true;
- // We have to convert it to have a record layout.
- CGM.getTypes().ConvertTagDeclType(RD);
- const CGRecordLayout &CGLayout = CGM.getTypes().getCGRecordLayout(RD);
- if (const CXXMethodDecl *KeyFunction = CGLayout.getKeyFunction()) {
+
+ 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.
@@ -1096,3 +1338,31 @@ llvm::Constant *CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass,
uint64_t Offset) {
return CGM.GenerateVtable(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);
+
+ // Get the key function.
+ const CXXMethodDecl *KeyFunction = Layout.getKeyFunction();
+
+ if (!KeyFunction) {
+ // If there's no key function, we don't want to emit the vtable here.
+ return;
+ }
+
+ // Check if we have the 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;
+
+ // Emit the data.
+ GenerateClassData(RD);
+}
+
diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h
index 78ae670..5c2b74c 100644
--- a/lib/CodeGen/CGVtable.h
+++ b/lib/CodeGen/CGVtable.h
@@ -17,56 +17,110 @@
#include "llvm/ADT/DenseMap.h"
#include "GlobalDecl.h"
+namespace llvm {
+ class Constant;
+}
+
namespace clang {
- class CXXMethodDecl;
class CXXRecordDecl;
-
+
namespace CodeGen {
class CodeGenModule;
-
+
+/// ThunkAdjustment - Virtual and non-virtual adjustment for thunks.
+class ThunkAdjustment {
+public:
+ ThunkAdjustment(int64_t NonVirtual, int64_t Virtual)
+ : NonVirtual(NonVirtual),
+ Virtual(Virtual) { }
+
+ ThunkAdjustment()
+ : NonVirtual(0), Virtual(0) { }
+
+ // isEmpty - Return whether this thunk adjustment is empty.
+ bool isEmpty() const {
+ return NonVirtual == 0 && Virtual == 0;
+ }
+
+ /// NonVirtual - The non-virtual adjustment.
+ int64_t NonVirtual;
+
+ /// Virtual - The virtual adjustment.
+ int64_t Virtual;
+};
+
+/// CovariantThunkAdjustment - Adjustment of the 'this' pointer and the
+/// return pointer for covariant thunks.
+class CovariantThunkAdjustment {
+public:
+ CovariantThunkAdjustment(const ThunkAdjustment &ThisAdjustment,
+ const ThunkAdjustment &ReturnAdjustment)
+ : ThisAdjustment(ThisAdjustment), ReturnAdjustment(ReturnAdjustment) { }
+
+ CovariantThunkAdjustment() { }
+
+ ThunkAdjustment ThisAdjustment;
+ ThunkAdjustment ReturnAdjustment;
+};
+
class CGVtableInfo {
CodeGenModule &CGM;
-
+
/// MethodVtableIndices - Contains the index (relative to the vtable address
/// point) where the function pointer for a virtual function is stored.
typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVtableIndicesTy;
MethodVtableIndicesTy MethodVtableIndices;
-
+
typedef std::pair<const CXXRecordDecl *,
const CXXRecordDecl *> ClassPairTy;
-
+
/// VirtualBaseClassIndicies - Contains the index into the vtable where the
/// offsets for virtual bases of a class are stored.
typedef llvm::DenseMap<ClassPairTy, int64_t> VirtualBaseClassIndiciesTy;
VirtualBaseClassIndiciesTy VirtualBaseClassIndicies;
llvm::DenseMap<const CXXRecordDecl *, llvm::Constant *> Vtables;
+
+ /// NumVirtualFunctionPointers - Contains the number of virtual function
+ /// pointers in the vtable for a given record decl.
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers;
+
+ /// getNumVirtualFunctionPointers - Return the number of virtual function
+ /// pointers in the vtable for a given record decl.
+ uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
+
+ void ComputeMethodVtableIndices(const CXXRecordDecl *RD);
+
+ /// 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);
+
public:
- CGVtableInfo(CodeGenModule &CGM)
+ CGVtableInfo(CodeGenModule &CGM)
: CGM(CGM) { }
/// getMethodVtableIndex - Return the index (relative to the vtable address
- /// point) where the function pointer for the given virtual function is
+ /// point) where the function pointer for the given virtual function is
/// stored.
- int64_t getMethodVtableIndex(GlobalDecl GD);
-
+ uint64_t getMethodVtableIndex(GlobalDecl GD);
+
/// getVirtualBaseOffsetIndex - Return the index (relative to the vtable
/// address point) where the offset of the virtual base that contains the
/// given Base is stored, otherwise, if no virtual base contains the given
/// class, return 0. Base must be a virtual base class or an unambigious
/// base.
- int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
+ 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);
- /// 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);
-};
+
+ void MaybeEmitVtable(GlobalDecl GD);
+};
+
}
}
#endif
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 10884a7..9281416 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -3,11 +3,9 @@ set(LLVM_NO_RTTI 1)
add_clang_library(clangCodeGen
CGBlocks.cpp
CGBuiltin.cpp
- CGCXX.cpp
- CGCXXClass.cpp
- CGCXXExpr.cpp
- CGCXXTemp.cpp
CGCall.cpp
+ CGClass.cpp
+ CGCXX.cpp
CGDebugInfo.cpp
CGDecl.cpp
CGException.cpp
@@ -15,6 +13,7 @@ add_clang_library(clangCodeGen
CGExprAgg.cpp
CGExprComplex.cpp
CGExprConstant.cpp
+ CGExprCXX.cpp
CGExprScalar.cpp
CGObjC.cpp
CGObjCGNU.cpp
@@ -22,6 +21,7 @@ add_clang_library(clangCodeGen
CGRecordLayoutBuilder.cpp
CGRtti.cpp
CGStmt.cpp
+ CGTemporaries.cpp
CGVtable.cpp
CodeGenFunction.cpp
CodeGenModule.cpp
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 475c7bf..6e0a77c 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -29,7 +29,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
Builder(cgm.getModule().getContext()),
DebugInfo(0), IndirectBranch(0),
SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0),
- CXXThisDecl(0) {
+ CXXThisDecl(0), CXXVTTDecl(0),
+ ConditionalBranchLevel(0) {
LLVMIntTy = ConvertType(getContext().IntTy);
LLVMPointerWidth = Target.getPointerWidth(0);
}
@@ -216,6 +217,24 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
}
}
+static bool NeedsVTTParameter(GlobalDecl GD) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ // We don't have any virtual bases, just return early.
+ if (!MD->getParent()->getNumVBases())
+ return false;
+
+ // Check if we have a base constructor.
+ if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base)
+ return true;
+
+ // Check if we have a base destructor.
+ if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
+ return true;
+
+ return false;
+}
+
void CodeGenFunction::GenerateCode(GlobalDecl GD,
llvm::Function *Fn) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
@@ -235,6 +254,16 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD,
&getContext().Idents.get("this"),
MD->getThisType(getContext()));
Args.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType()));
+
+ // Check if we need a VTT parameter as well.
+ if (NeedsVTTParameter(GD)) {
+ // FIXME: The comment about using a fake decl above applies here too.
+ QualType T = getContext().getPointerType(getContext().VoidPtrTy);
+ CXXVTTDecl =
+ ImplicitParamDecl::Create(getContext(), 0, SourceLocation(),
+ &getContext().Idents.get("vtt"), T);
+ Args.push_back(std::make_pair(CXXVTTDecl, CXXVTTDecl->getType()));
+ }
}
}
@@ -317,6 +346,10 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD,
// Destroy the 'this' declaration.
if (CXXThisDecl)
CXXThisDecl->Destroy(getContext());
+
+ // Destroy the VTT declaration.
+ if (CXXVTTDecl)
+ CXXVTTDecl->Destroy(getContext());
}
/// ContainsLabel - Return true if the statement contains a label in it. If
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index d96c355..7f32045 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -133,17 +133,17 @@ public:
/// block.
CleanupBlockInfo PopCleanupBlock();
- /// CleanupScope - RAII object that will create a cleanup block and set the
- /// insert point to that block. When destructed, it sets the insert point to
- /// the previous block and pushes a new cleanup entry on the stack.
- class CleanupScope {
+ /// DelayedCleanupBlock - RAII object that will create a cleanup block and set
+ /// the insert point to that block. When destructed, it sets the insert point
+ /// to the previous block and pushes a new cleanup entry on the stack.
+ class DelayedCleanupBlock {
CodeGenFunction& CGF;
llvm::BasicBlock *CurBB;
llvm::BasicBlock *CleanupEntryBB;
llvm::BasicBlock *CleanupExitBB;
public:
- CleanupScope(CodeGenFunction &cgf)
+ DelayedCleanupBlock(CodeGenFunction &cgf)
: CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()),
CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0) {
CGF.Builder.SetInsertPoint(CleanupEntryBB);
@@ -155,7 +155,7 @@ public:
return CleanupExitBB;
}
- ~CleanupScope() {
+ ~DelayedCleanupBlock() {
CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB);
// FIXME: This is silly, move this into the builder.
if (CurBB)
@@ -165,6 +165,50 @@ public:
}
};
+ /// \brief Enters a new scope for capturing cleanups, all of which will be
+ /// executed once the scope is exited.
+ class CleanupScope {
+ CodeGenFunction& CGF;
+ size_t CleanupStackDepth;
+ bool OldDidCallStackSave;
+ bool PerformCleanup;
+
+ CleanupScope(const CleanupScope &); // DO NOT IMPLEMENT
+ CleanupScope &operator=(const CleanupScope &); // DO NOT IMPLEMENT
+
+ public:
+ /// \brief Enter a new cleanup scope.
+ explicit CleanupScope(CodeGenFunction &CGF)
+ : CGF(CGF), PerformCleanup(true)
+ {
+ CleanupStackDepth = CGF.CleanupEntries.size();
+ OldDidCallStackSave = CGF.DidCallStackSave;
+ }
+
+ /// \brief Exit this cleanup scope, emitting any accumulated
+ /// cleanups.
+ ~CleanupScope() {
+ if (PerformCleanup) {
+ CGF.DidCallStackSave = OldDidCallStackSave;
+ CGF.EmitCleanupBlocks(CleanupStackDepth);
+ }
+ }
+
+ /// \brief Determine whether this scope requires any cleanups.
+ bool requiresCleanups() const {
+ return CGF.CleanupEntries.size() > CleanupStackDepth;
+ }
+
+ /// \brief Force the emission of cleanups now, instead of waiting
+ /// until this object is destroyed.
+ void ForceCleanup() {
+ assert(PerformCleanup && "Already forced cleanup");
+ CGF.DidCallStackSave = OldDidCallStackSave;
+ CGF.EmitCleanupBlocks(CleanupStackDepth);
+ PerformCleanup = false;
+ }
+ };
+
/// EmitCleanupBlocks - Takes the old cleanup stack size and emits the cleanup
/// blocks that have been added.
void EmitCleanupBlocks(size_t OldCleanupStackSize);
@@ -176,27 +220,31 @@ public:
/// this behavior for branches?
void EmitBranchThroughCleanup(llvm::BasicBlock *Dest);
- /// PushConditionalTempDestruction - Should be called before a conditional
- /// part of an expression is emitted. For example, before the RHS of the
- /// expression below is emitted:
+ /// StartConditionalBranch - Should be called before a conditional part of an
+ /// expression is emitted. For example, before the RHS of the expression below
+ /// is emitted:
///
/// b && f(T());
///
- /// This is used to make sure that any temporaryes created in the conditional
+ /// This is used to make sure that any temporaries created in the conditional
/// branch are only destroyed if the branch is taken.
- void PushConditionalTempDestruction();
+ void StartConditionalBranch() {
+ ++ConditionalBranchLevel;
+ }
- /// PopConditionalTempDestruction - Should be called after a conditional
- /// part of an expression has been emitted.
- void PopConditionalTempDestruction();
+ /// FinishConditionalBranch - Should be called after a conditional part of an
+ /// expression has been emitted.
+ void FinishConditionalBranch() {
+ --ConditionalBranchLevel;
+ }
private:
CGDebugInfo *DebugInfo;
- /// IndirectBranch - The first time an indirect goto is seen we create a
- /// block with an indirect branch. Every time we see the address of a label
- /// taken, we add the label to the indirect goto. Every subsequent indirect
- /// goto is codegen'd as a jump to the IndirectBranch's basic block.
+ /// IndirectBranch - The first time an indirect goto is seen we create a block
+ /// with an indirect branch. Every time we see the address of a label taken,
+ /// we add the label to the indirect goto. Every subsequent indirect goto is
+ /// codegen'd as a jump to the IndirectBranch's basic block.
llvm::IndirectBrInst *IndirectBranch;
/// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C
@@ -269,10 +317,15 @@ private:
/// BlockScopes - Map of which "cleanup scope" scope basic blocks have.
BlockScopeMap BlockScopes;
- /// CXXThisDecl - When parsing an C++ function, this will hold the implicit
- /// 'this' declaration.
+ /// CXXThisDecl - When generating code for a C++ member function,
+ /// this will hold the implicit 'this' declaration.
ImplicitParamDecl *CXXThisDecl;
+ /// CXXVTTDecl - When generating code for a base object constructor or
+ /// base object destructor with virtual bases, this will hold the implicit
+ /// VTT parameter.
+ ImplicitParamDecl *CXXVTTDecl;
+
/// CXXLiveTemporaryInfo - Holds information about a live C++ temporary.
struct CXXLiveTemporaryInfo {
/// Temporary - The live temporary.
@@ -284,9 +337,9 @@ private:
/// DtorBlock - The destructor block.
llvm::BasicBlock *DtorBlock;
- /// CondPtr - If this is a conditional temporary, this is the pointer to
- /// the condition variable that states whether the destructor should be
- /// called or not.
+ /// CondPtr - If this is a conditional temporary, this is the pointer to the
+ /// condition variable that states whether the destructor should be called
+ /// or not.
llvm::Value *CondPtr;
CXXLiveTemporaryInfo(const CXXTemporary *temporary,
@@ -298,10 +351,10 @@ private:
llvm::SmallVector<CXXLiveTemporaryInfo, 4> LiveTemporaries;
- /// ConditionalTempDestructionStack - Contains the number of live temporaries
- /// when PushConditionalTempDestruction was called. This is used so that
- /// we know how many temporaries were created by a certain expression.
- llvm::SmallVector<size_t, 4> ConditionalTempDestructionStack;
+ /// ConditionalBranchLevel - Contains the nesting level of the current
+ /// conditional branch. This is used so that we know if a temporary should be
+ /// destroyed conditionally.
+ unsigned ConditionalBranchLevel;
/// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM
@@ -384,15 +437,17 @@ public:
/// DynamicTypeAdjust - Do the non-virtual and virtual adjustments on an
/// object pointer to alter the dynamic type of the pointer. Used by
/// GenerateCovariantThunk for building thunks.
- llvm::Value *DynamicTypeAdjust(llvm::Value *V, int64_t nv, int64_t v);
+ llvm::Value *DynamicTypeAdjust(llvm::Value *V,
+ const ThunkAdjustment &Adjustment);
/// GenerateThunk - Generate a thunk for the given method
llvm::Constant *GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD,
- bool Extern, int64_t nv, int64_t v);
- llvm::Constant *GenerateCovariantThunk(llvm::Function *Fn,
- const CXXMethodDecl *MD, bool Extern,
- int64_t nv_t, int64_t v_t,
- int64_t nv_r, int64_t v_r);
+ bool Extern,
+ const ThunkAdjustment &ThisAdjustment);
+ llvm::Constant *
+ GenerateCovariantThunk(llvm::Function *Fn, const CXXMethodDecl *MD,
+ bool Extern,
+ const CovariantThunkAdjustment &Adjustment);
void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type);
@@ -416,8 +471,8 @@ public:
const FunctionArgList &Args);
/// EmitDtorEpilogue - Emit all code that comes at the end of class's
- /// destructor. This is to call destructors on members and base classes
- /// in reverse order of their construction.
+ /// destructor. This is to call destructors on members and base classes in
+ /// reverse order of their construction.
void EmitDtorEpilogue(const CXXDestructorDecl *Dtor,
CXXDtorType Type);
@@ -461,9 +516,9 @@ public:
/// label maps to.
llvm::BasicBlock *getBasicBlockForLabel(const LabelStmt *S);
- /// SimplifyForwardingBlocks - If the given basic block is only a
- /// branch to another basic block, simplify it. This assumes that no
- /// other code could potentially reference the basic block.
+ /// SimplifyForwardingBlocks - If the given basic block is only a branch to
+ /// another basic block, simplify it. This assumes that no other code could
+ /// potentially reference the basic block.
void SimplifyForwardingBlocks(llvm::BasicBlock *BB);
/// EmitBlock - Emit the given block \arg BB and set it as the insert point,
@@ -579,9 +634,9 @@ public:
// instruction in LLVM instead once it works well enough.
llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty);
- // EmitVLASize - Generate code for any VLA size expressions that might occur
- // in a variably modified type. If Ty is a VLA, will return the value that
- // corresponds to the size in bytes of the VLA type. Will return 0 otherwise.
+ /// EmitVLASize - Generate code for any VLA size expressions that might occur
+ /// in a variably modified type. If Ty is a VLA, will return the value that
+ /// corresponds to the size in bytes of the VLA type. Will return 0 otherwise.
///
/// This function can be called with a null (unreachable) insert point.
llvm::Value *EmitVLASize(QualType Ty);
@@ -594,15 +649,20 @@ public:
/// generating code for an C++ member function.
llvm::Value *LoadCXXThis();
- /// GetAddressCXXOfBaseClass - This function will add the necessary delta
- /// to the load of 'this' and returns address of the base class.
+ /// GetAddressOfBaseClass - This function will add the necessary delta to the
+ /// load of 'this' and returns address of the base class.
// FIXME. This currently only does a derived to non-virtual base conversion.
// Other kinds of conversions will come later.
- llvm::Value *GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
+ llvm::Value *GetAddressOfBaseClass(llvm::Value *Value,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl,
+ bool NullCheckValue);
+
+ llvm::Value *GetAddressOfDerivedClass(llvm::Value *Value,
const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
+ const CXXRecordDecl *DerivedClassDecl,
bool NullCheckValue);
-
+
llvm::Value *
GetVirtualCXXBaseClassOffset(llvm::Value *This,
const CXXRecordDecl *ClassDecl,
@@ -637,10 +697,15 @@ public:
void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
const ConstantArrayType *ArrayTy,
- llvm::Value *ArrayPtr);
+ llvm::Value *ArrayPtr,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd);
+
void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
llvm::Value *NumElements,
- llvm::Value *ArrayPtr);
+ llvm::Value *ArrayPtr,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd);
void EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
const ArrayType *Array,
@@ -858,7 +923,6 @@ public:
LValue EmitBlockDeclRefLValue(const BlockDeclRefExpr *E);
- LValue EmitCXXConditionDeclLValue(const CXXConditionDeclExpr *E);
LValue EmitCXXConstructLValue(const CXXConstructExpr *E);
LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E);
LValue EmitCXXExprWithTemporariesLValue(const CXXExprWithTemporaries *E);
@@ -880,9 +944,8 @@ public:
/// result type, and using the given argument list which specifies both the
/// LLVM arguments and the types they were derived from.
///
- /// \param TargetDecl - If given, the decl of the function in a
- /// direct call; used to set attributes on the call (noreturn,
- /// etc.).
+ /// \param TargetDecl - If given, the decl of the function in a direct call;
+ /// used to set attributes on the call (noreturn, etc.).
RValue EmitCall(const CGFunctionInfo &FnInfo,
llvm::Value *Callee,
const CallArgList &Args,
@@ -994,15 +1057,14 @@ public:
/// LoadComplexFromAddr - Load a complex number from the specified address.
ComplexPairTy LoadComplexFromAddr(llvm::Value *SrcAddr, bool SrcIsVolatile);
- /// CreateStaticBlockVarDecl - Create a zero-initialized LLVM global
- /// for a static block var decl.
+ /// CreateStaticBlockVarDecl - Create a zero-initialized LLVM global for a
+ /// static block var decl.
llvm::GlobalVariable * CreateStaticBlockVarDecl(const VarDecl &D,
const char *Separator,
- llvm::GlobalValue::LinkageTypes
- Linkage);
+ llvm::GlobalValue::LinkageTypes Linkage);
- /// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++
- /// runtime initialized static block var decl.
+ /// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++ runtime
+ /// initialized static block var decl.
void EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
llvm::GlobalVariable *GV);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 195acc5..4b3b122 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
@@ -160,19 +161,13 @@ const char *CodeGenModule::getMangledName(const GlobalDecl &GD) {
/// the unmangled name.
///
const char *CodeGenModule::getMangledName(const NamedDecl *ND) {
- // In C, functions with no attributes never need to be mangled. Fastpath them.
- if (!getLangOptions().CPlusPlus && !ND->hasAttrs()) {
+ if (!getMangleContext().shouldMangleDeclName(ND)) {
assert(ND->getIdentifier() && "Attempt to mangle unnamed decl.");
return ND->getNameAsCString();
}
llvm::SmallString<256> Name;
- llvm::raw_svector_ostream Out(Name);
- if (!mangleName(getMangleContext(), ND, Out)) {
- assert(ND->getIdentifier() && "Attempt to mangle unnamed decl.");
- return ND->getNameAsCString();
- }
-
+ getMangleContext().mangleName(ND, Name);
Name += '\0';
return UniqueMangledName(Name.begin(), Name.end());
}
@@ -353,8 +348,12 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
else if (Features.getStackProtectorMode() == LangOptions::SSPReq)
F->addFnAttr(llvm::Attribute::StackProtectReq);
- if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- F->setAlignment(AA->getAlignment()/8);
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) {
+ unsigned width = Context.Target.getCharWidth();
+ F->setAlignment(AA->getAlignment() / width);
+ while ((AA = AA->getNext<AlignedAttr>()))
+ F->setAlignment(std::max(F->getAlignment(), AA->getAlignment() / width));
+ }
// C++ ABI requires 2-byte alignment for member functions.
if (F->getAlignment() < 2 && isa<CXXMethodDecl>(D))
F->setAlignment(2);
@@ -551,7 +550,7 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
// cannot be.
if (VD->isInAnonymousNamespace())
return true;
- if (VD->getStorageClass() == VarDecl::Static) {
+ if (VD->getLinkage() == VarDecl::InternalLinkage) {
// Initializer has side effects?
if (VD->getInit() && VD->getInit()->HasSideEffects(Context))
return false;
@@ -616,16 +615,9 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
Context.getSourceManager(),
"Generating code for declaration");
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
- const CXXRecordDecl *RD = MD->getParent();
- // We have to convert it to have a record layout.
- Types.ConvertTagDeclType(RD);
- const CGRecordLayout &CGLayout = Types.getCGRecordLayout(RD);
- // A definition of a KeyFunction, generates all the class data, such
- // as vtable, rtti and the VTT.
- if (CGLayout.getKeyFunction() == MD)
- getVtableInfo().GenerateClassData(RD);
- }
+ if (isa<CXXMethodDecl>(D))
+ getVtableInfo().MaybeEmitVtable(GD);
+
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
EmitCXXConstructor(CD, GD.getCtorType());
else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D))
@@ -697,143 +689,20 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
// A called constructor which has no definition or declaration need be
// synthesized.
else if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
- const CXXRecordDecl *ClassDecl =
- cast<CXXRecordDecl>(CD->getDeclContext());
- if (CD->isCopyConstructor(getContext()))
- DeferredCopyConstructorToEmit(D);
- else if (!ClassDecl->hasUserDeclaredConstructor())
+ if (CD->isImplicit())
+ DeferredDeclsToEmit.push_back(D);
+ } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) {
+ if (DD->isImplicit())
+ DeferredDeclsToEmit.push_back(D);
+ } else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ if (MD->isCopyAssignment() && MD->isImplicit())
DeferredDeclsToEmit.push_back(D);
}
- else if (isa<CXXDestructorDecl>(FD))
- DeferredDestructorToEmit(D);
- else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
- if (MD->isCopyAssignment())
- DeferredCopyAssignmentToEmit(D);
}
return F;
}
-/// Defer definition of copy constructor(s) which need be implicitly defined.
-void CodeGenModule::DeferredCopyConstructorToEmit(GlobalDecl CopyCtorDecl) {
- const CXXConstructorDecl *CD =
- cast<CXXConstructorDecl>(CopyCtorDecl.getDecl());
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
- if (ClassDecl->hasTrivialCopyConstructor() ||
- ClassDecl->hasUserDeclaredCopyConstructor())
- return;
-
- // First make sure all direct base classes and virtual bases and non-static
- // data mebers which need to have their copy constructors implicitly defined
- // are defined. 12.8.p7
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(Context, 0))
- GetAddrOfCXXConstructor(BaseCopyCtor, Ctor_Complete);
- }
-
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = Context.getCanonicalType((*Field)->getType());
- if (const ArrayType *Array = Context.getAsArrayType(FieldType))
- FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- if ((*Field)->isAnonymousStructOrUnion())
- continue;
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (CXXConstructorDecl *FieldCopyCtor =
- FieldClassDecl->getCopyConstructor(Context, 0))
- GetAddrOfCXXConstructor(FieldCopyCtor, Ctor_Complete);
- }
- }
- DeferredDeclsToEmit.push_back(CopyCtorDecl);
-}
-
-/// Defer definition of copy assignments which need be implicitly defined.
-void CodeGenModule::DeferredCopyAssignmentToEmit(GlobalDecl CopyAssignDecl) {
- const CXXMethodDecl *CD = cast<CXXMethodDecl>(CopyAssignDecl.getDecl());
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
-
- if (ClassDecl->hasTrivialCopyAssignment() ||
- ClassDecl->hasUserDeclaredCopyAssignment())
- return;
-
- // First make sure all direct base classes and virtual bases and non-static
- // data mebers which need to have their copy assignments implicitly defined
- // are defined. 12.8.p12
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- const CXXMethodDecl *MD = 0;
- if (!BaseClassDecl->hasTrivialCopyAssignment() &&
- !BaseClassDecl->hasUserDeclaredCopyAssignment() &&
- BaseClassDecl->hasConstCopyAssignment(getContext(), MD))
- GetAddrOfFunction(MD, 0);
- }
-
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = Context.getCanonicalType((*Field)->getType());
- if (const ArrayType *Array = Context.getAsArrayType(FieldType))
- FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- if ((*Field)->isAnonymousStructOrUnion())
- continue;
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- const CXXMethodDecl *MD = 0;
- if (!FieldClassDecl->hasTrivialCopyAssignment() &&
- !FieldClassDecl->hasUserDeclaredCopyAssignment() &&
- FieldClassDecl->hasConstCopyAssignment(getContext(), MD))
- GetAddrOfFunction(MD, 0);
- }
- }
- DeferredDeclsToEmit.push_back(CopyAssignDecl);
-}
-
-void CodeGenModule::DeferredDestructorToEmit(GlobalDecl DtorDecl) {
- const CXXDestructorDecl *DD = cast<CXXDestructorDecl>(DtorDecl.getDecl());
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(DD->getDeclContext());
- if (ClassDecl->hasTrivialDestructor() ||
- ClassDecl->hasUserDeclaredDestructor())
- return;
-
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (const CXXDestructorDecl *BaseDtor =
- BaseClassDecl->getDestructor(Context))
- GetAddrOfCXXDestructor(BaseDtor, Dtor_Complete);
- }
-
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = Context.getCanonicalType((*Field)->getType());
- if (const ArrayType *Array = Context.getAsArrayType(FieldType))
- FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- if ((*Field)->isAnonymousStructOrUnion())
- continue;
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (const CXXDestructorDecl *FieldDtor =
- FieldClassDecl->getDestructor(Context))
- GetAddrOfCXXDestructor(FieldDtor, Dtor_Complete);
- }
- }
- DeferredDeclsToEmit.push_back(DtorDecl);
-}
-
-
/// GetAddrOfFunction - Return the address of the given function. If Ty is
/// non-null, then this function will use the specified type if it has to
/// create it (this occurs when we see a definition of the function).
@@ -982,9 +851,8 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
return CodeGenModule::GVA_TemplateInstantiation;
}
}
-
- // Static variables get internal linkage.
- if (VD->getStorageClass() == VarDecl::Static)
+
+ if (VD->getLinkage() == VarDecl::InternalLinkage)
return CodeGenModule::GVA_Internal;
return CodeGenModule::GVA_StrongExternal;
@@ -1097,7 +965,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
} else if (Linkage == GVA_TemplateInstantiation)
GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
- else if (!CodeGenOpts.NoCommon &&
+ else if (!getLangOptions().CPlusPlus && !CodeGenOpts.NoCommon &&
!D->hasExternalStorage() && !D->getInit() &&
!D->getAttr<SectionAttr>()) {
GV->setLinkage(llvm::GlobalVariable::CommonLinkage);
@@ -1734,6 +1602,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::NamespaceAlias:
break;
case Decl::CXXConstructor:
+ // Skip function templates
+ if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate())
+ return;
+
EmitCXXConstructors(cast<CXXConstructorDecl>(D));
break;
case Decl::CXXDestructor:
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index c8562d6..78bc4ed 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -231,15 +231,16 @@ public:
llvm::Constant *GenerateRttiRef(const CXXRecordDecl *RD);
/// GenerateRttiNonClass - Generate the rtti information for the given
/// non-class type.
- llvm::Constant *GenerateRttiNonClass(QualType Ty);
+ llvm::Constant *GenerateRtti(QualType Ty);
+
+ /// BuildThunk - Build a thunk for the given method.
+ llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern,
+ const ThunkAdjustment &ThisAdjustment);
- /// BuildThunk - Build a thunk for the given method
- llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern, int64_t nv,
- int64_t v);
/// BuildCoVariantThunk - Build a thunk for the given method
- llvm::Constant *BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern,
- int64_t nv_t, int64_t v_t,
- int64_t nv_r, int64_t v_r);
+ llvm::Constant *
+ BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern,
+ const CovariantThunkAdjustment &Adjustment);
typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
typedef llvm::DenseMap<const CXXRecordDecl *,
@@ -427,9 +428,6 @@ private:
llvm::Constant *GetOrCreateLLVMGlobal(const char *MangledName,
const llvm::PointerType *PTy,
const VarDecl *D);
- void DeferredCopyConstructorToEmit(GlobalDecl D);
- void DeferredCopyAssignmentToEmit(GlobalDecl D);
- void DeferredDestructorToEmit(GlobalDecl D);
/// SetCommonAttributes - Set attributes which are common to any
/// form of a global definition (alias, Objective-C method,
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 1f83f37..c89879f 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -38,7 +38,13 @@ CodeGenTypes::~CodeGenTypes() {
I = CGRecordLayouts.begin(), E = CGRecordLayouts.end();
I != E; ++I)
delete I->second;
- CGRecordLayouts.clear();
+ {
+ llvm::FoldingSet<CGFunctionInfo>::iterator
+ I = FunctionInfos.begin(), E = FunctionInfos.end();
+ while (I != E)
+ delete &*I++;
+ }
+ delete TheABIInfo;
}
/// ConvertType - Convert the specified type to its LLVM form.
@@ -197,6 +203,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
case BuiltinType::Void:
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
// LLVM void type can only be used as the result of a function call. Just
// map to the same as char.
return llvm::IntegerType::get(getLLVMContext(), 8);
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index f447549..2ff602f 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -20,6 +20,7 @@
#include <vector>
#include "CGCall.h"
+#include "CGCXX.h"
namespace llvm {
class FunctionType;
@@ -34,6 +35,8 @@ namespace llvm {
namespace clang {
class ABIInfo;
class ASTContext;
+ class CXXConstructorDecl;
+ class CXXDestructorDecl;
class CXXMethodDecl;
class FieldDecl;
class FunctionProtoType;
@@ -61,17 +64,9 @@ namespace CodeGen {
/// is a member pointer, or a struct that contains a member pointer.
bool ContainsMemberPointer;
- /// KeyFunction - The key function of the record layout (if one exists),
- /// which is the first non-pure virtual function that is not inline at the
- /// point of class definition.
- /// See http://www.codesourcery.com/public/cxx-abi/abi.html#vague-vtable.
- const CXXMethodDecl *KeyFunction;
-
public:
- CGRecordLayout(const llvm::Type *T, bool ContainsMemberPointer,
- const CXXMethodDecl *KeyFunction)
- : LLVMType(T), ContainsMemberPointer(ContainsMemberPointer),
- KeyFunction(KeyFunction) { }
+ CGRecordLayout(const llvm::Type *T, bool ContainsMemberPointer)
+ : LLVMType(T), ContainsMemberPointer(ContainsMemberPointer) { }
/// getLLVMType - Return llvm type associated with this record.
const llvm::Type *getLLVMType() const {
@@ -81,10 +76,6 @@ namespace CodeGen {
bool containsMemberPointer() const {
return ContainsMemberPointer;
}
-
- const CXXMethodDecl *getKeyFunction() const {
- return KeyFunction;
- }
};
/// CodeGenTypes - This class organizes the cross-module state that is used
@@ -173,6 +164,12 @@ public:
const llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info,
bool IsVariadic);
+
+ /// GetFunctionTypeForVtable - Get the LLVM function type for use in a vtable,
+ /// given a CXXMethodDecl. If the method to has an incomplete return type,
+ /// and/or incomplete argument types, this will return the opaque type.
+ const llvm::Type *GetFunctionTypeForVtable(const CXXMethodDecl *MD);
+
const CGRecordLayout &getCGRecordLayout(const TagDecl*) const;
/// getLLVMFieldNo - Return llvm::StructType element number
@@ -192,7 +189,11 @@ public:
const CGFunctionInfo &getFunctionInfo(const FunctionDecl *FD);
const CGFunctionInfo &getFunctionInfo(const CXXMethodDecl *MD);
const CGFunctionInfo &getFunctionInfo(const ObjCMethodDecl *MD);
-
+ const CGFunctionInfo &getFunctionInfo(const CXXConstructorDecl *D,
+ CXXCtorType Type);
+ const CGFunctionInfo &getFunctionInfo(const CXXDestructorDecl *D,
+ CXXDtorType Type);
+
// getFunctionInfo - Get the function info for a member function.
const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD,
const FunctionProtoType *FTP);
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index 0a7124d..d6f7808 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -23,100 +23,111 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "CGVtable.h"
using namespace clang;
+using namespace CodeGen;
namespace {
- class VISIBILITY_HIDDEN CXXNameMangler {
- MangleContext &Context;
- llvm::raw_ostream &Out;
-
- const CXXMethodDecl *Structor;
- unsigned StructorType;
- CXXCtorType CtorType;
-
- llvm::DenseMap<uintptr_t, unsigned> Substitutions;
-
- public:
- CXXNameMangler(MangleContext &C, llvm::raw_ostream &os)
- : Context(C), Out(os), Structor(0), StructorType(0) { }
-
- bool mangle(const NamedDecl *D);
- void mangleCalloffset(int64_t nv, int64_t v);
- void mangleThunk(const FunctionDecl *FD, int64_t nv, int64_t v);
- void mangleCovariantThunk(const FunctionDecl *FD,
- int64_t nv_t, int64_t v_t,
- int64_t nv_r, int64_t v_r);
- void mangleGuardVariable(const VarDecl *D);
-
- void mangleCXXVtable(const CXXRecordDecl *RD);
- void mangleCXXVTT(const CXXRecordDecl *RD);
- void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
- const CXXRecordDecl *Type);
- void mangleCXXRtti(QualType Ty);
- void mangleCXXRttiName(QualType Ty);
- void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type);
- void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type);
-
- private:
- bool mangleSubstitution(const NamedDecl *ND);
- bool mangleSubstitution(QualType T);
- bool mangleSubstitution(uintptr_t Ptr);
-
- bool mangleStandardSubstitution(const NamedDecl *ND);
-
- void addSubstitution(const NamedDecl *ND) {
- ND = cast<NamedDecl>(ND->getCanonicalDecl());
+
+static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) {
+ assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
+ "Passed in decl is not a ctor or dtor!");
+
+ if (const TemplateDecl *TD = MD->getPrimaryTemplate()) {
+ MD = cast<CXXMethodDecl>(TD->getTemplatedDecl());
- addSubstitution(reinterpret_cast<uintptr_t>(ND));
- }
- void addSubstitution(QualType T);
- void addSubstitution(uintptr_t Ptr);
+ assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
+ "Templated decl is not a ctor or dtor!");
+ }
- bool mangleFunctionDecl(const FunctionDecl *FD);
-
- void mangleFunctionEncoding(const FunctionDecl *FD);
- void mangleName(const NamedDecl *ND);
- void mangleName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
- void mangleUnqualifiedName(const NamedDecl *ND);
- void mangleUnscopedName(const NamedDecl *ND);
- void mangleUnscopedTemplateName(const TemplateDecl *ND);
- void mangleSourceName(const IdentifierInfo *II);
- void mangleLocalName(const NamedDecl *ND);
- void mangleNestedName(const NamedDecl *ND);
- void mangleNestedName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
- void manglePrefix(const DeclContext *DC);
- void mangleTemplatePrefix(const TemplateDecl *ND);
- void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
- void mangleQualifiers(Qualifiers Quals);
- void mangleType(QualType T);
-
- // Declare manglers for every type class.
+ return MD;
+}
+
+/// CXXNameMangler - Manage the mangling of a single name.
+class CXXNameMangler {
+ MangleContext &Context;
+ llvm::raw_svector_ostream Out;
+
+ const CXXMethodDecl *Structor;
+ unsigned StructorType;
+
+ llvm::DenseMap<uintptr_t, unsigned> Substitutions;
+
+public:
+ CXXNameMangler(MangleContext &C, llvm::SmallVectorImpl<char> &Res)
+ : Context(C), Out(Res), Structor(0), StructorType(0) { }
+ CXXNameMangler(MangleContext &C, llvm::SmallVectorImpl<char> &Res,
+ const CXXConstructorDecl *D, CXXCtorType Type)
+ : Context(C), Out(Res), Structor(getStructor(D)), StructorType(Type) { }
+ CXXNameMangler(MangleContext &C, llvm::SmallVectorImpl<char> &Res,
+ const CXXDestructorDecl *D, CXXDtorType Type)
+ : Context(C), Out(Res), Structor(getStructor(D)), StructorType(Type) { }
+
+ llvm::raw_svector_ostream &getStream() { return Out; }
+
+ void mangle(const NamedDecl *D, llvm::StringRef Prefix = "_Z");
+ void mangleCallOffset(const ThunkAdjustment &Adjustment);
+ void mangleNumber(int64_t Number);
+ void mangleFunctionEncoding(const FunctionDecl *FD);
+ void mangleName(const NamedDecl *ND);
+ void mangleType(QualType T);
+
+private:
+ bool mangleSubstitution(const NamedDecl *ND);
+ bool mangleSubstitution(QualType T);
+ bool mangleSubstitution(uintptr_t Ptr);
+
+ bool mangleStandardSubstitution(const NamedDecl *ND);
+
+ void addSubstitution(const NamedDecl *ND) {
+ ND = cast<NamedDecl>(ND->getCanonicalDecl());
+
+ addSubstitution(reinterpret_cast<uintptr_t>(ND));
+ }
+ void addSubstitution(QualType T);
+ void addSubstitution(uintptr_t Ptr);
+
+ bool mangleFunctionDecl(const FunctionDecl *FD);
+
+ void mangleName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+ void mangleUnqualifiedName(const NamedDecl *ND);
+ void mangleUnscopedName(const NamedDecl *ND);
+ void mangleUnscopedTemplateName(const TemplateDecl *ND);
+ void mangleSourceName(const IdentifierInfo *II);
+ void mangleLocalName(const NamedDecl *ND);
+ void mangleNestedName(const NamedDecl *ND);
+ void mangleNestedName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+ void manglePrefix(const DeclContext *DC);
+ void mangleTemplatePrefix(const TemplateDecl *ND);
+ void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
+ void mangleQualifiers(Qualifiers Quals);
+
+ // Declare manglers for every type class.
#define ABSTRACT_TYPE(CLASS, PARENT)
#define NON_CANONICAL_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T);
#include "clang/AST/TypeNodes.def"
- void mangleType(const TagType*);
- void mangleBareFunctionType(const FunctionType *T,
- bool MangleReturnType);
- void mangleExpression(const Expr *E);
- void mangleCXXCtorType(CXXCtorType T);
- void mangleCXXDtorType(CXXDtorType T);
-
- void mangleTemplateArgs(const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
- void mangleTemplateArgumentList(const TemplateArgumentList &L);
- void mangleTemplateArgument(const TemplateArgument &A);
-
- void mangleTemplateParameter(unsigned Index);
- };
+ void mangleType(const TagType*);
+ void mangleBareFunctionType(const FunctionType *T,
+ bool MangleReturnType);
+ void mangleExpression(const Expr *E);
+ void mangleCXXCtorType(CXXCtorType T);
+ void mangleCXXDtorType(CXXDtorType T);
+
+ void mangleTemplateArgs(const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+ void mangleTemplateArgumentList(const TemplateArgumentList &L);
+ void mangleTemplateArgument(const TemplateArgument &A);
+
+ void mangleTemplateParameter(unsigned Index);
+};
}
static bool isInCLinkageSpecification(const Decl *D) {
@@ -130,132 +141,72 @@ static bool isInCLinkageSpecification(const Decl *D) {
return false;
}
-bool CXXNameMangler::mangleFunctionDecl(const FunctionDecl *FD) {
+bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
+ // In C, functions with no attributes never need to be mangled. Fastpath them.
+ if (!getASTContext().getLangOptions().CPlusPlus && !D->hasAttrs())
+ return false;
+
+ // Any decl can be declared with __asm("foo") on it, and this takes precedence
+ // over all other naming in the .o file.
+ if (D->hasAttr<AsmLabelAttr>())
+ return true;
+
// Clang's "overloadable" attribute extension to C/C++ implies name mangling
// (always) as does passing a C++ member function and a function
// whose name is not a simple identifier.
- if (!FD->hasAttr<OverloadableAttr>() && !isa<CXXMethodDecl>(FD) &&
- FD->getDeclName().isIdentifier()) {
- // C functions are not mangled, and "main" is never mangled.
- if (!Context.getASTContext().getLangOptions().CPlusPlus || FD->isMain())
- return false;
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) ||
+ !FD->getDeclName().isIdentifier()))
+ return true;
- // No mangling in an "implicit extern C" header.
- if (FD->getLocation().isValid() &&
- Context.getASTContext().getSourceManager().
- isInExternCSystemHeader(FD->getLocation()))
- return false;
+ // Otherwise, no mangling is done outside C++ mode.
+ if (!getASTContext().getLangOptions().CPlusPlus)
+ return false;
- // No name mangling in a C linkage specification.
- if (isInCLinkageSpecification(FD))
- return false;
- }
+ // No mangling in an "implicit extern C" header.
+ if (D->getLocation().isValid() &&
+ getASTContext().getSourceManager().
+ 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))
+ return false;
- // If we get here, mangle the decl name!
- Out << "_Z";
- mangleFunctionEncoding(FD);
return true;
}
-bool CXXNameMangler::mangle(const NamedDecl *D) {
+void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) {
// Any decl can be declared with __asm("foo") on it, and this takes precedence
// over all other naming in the .o file.
if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
// If we have an asm name, then we use it as the mangling.
Out << '\01'; // LLVM IR Marker for __asm("foo")
Out << ALA->getLabel();
- return true;
+ return;
}
// <mangled-name> ::= _Z <encoding>
// ::= <data name>
// ::= <special-name>
-
- // FIXME: Actually use a visitor to decode these?
+ Out << Prefix;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- return mangleFunctionDecl(FD);
-
- if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- if (!Context.getASTContext().getLangOptions().CPlusPlus ||
- isInCLinkageSpecification(D) ||
- D->getDeclContext()->isTranslationUnit())
- return false;
-
- Out << "_Z";
- mangleName(VD);
- return true;
- }
-
- return false;
-}
-
-void CXXNameMangler::mangleCXXCtor(const CXXConstructorDecl *D,
- CXXCtorType Type) {
- assert(!Structor && "Structor already set!");
- Structor = D;
- StructorType = Type;
-
- mangle(D);
-}
-
-void CXXNameMangler::mangleCXXDtor(const CXXDestructorDecl *D,
- CXXDtorType Type) {
- assert(!Structor && "Structor already set!");
- Structor = D;
- StructorType = Type;
-
- mangle(D);
-}
-
-void CXXNameMangler::mangleCXXVtable(const CXXRecordDecl *RD) {
- // <special-name> ::= TV <type> # virtual table
- Out << "_ZTV";
- mangleName(RD);
-}
-
-void CXXNameMangler::mangleCXXVTT(const CXXRecordDecl *RD) {
- // <special-name> ::= TT <type> # VTT structure
- Out << "_ZTT";
- mangleName(RD);
-}
-
-void CXXNameMangler::mangleCXXCtorVtable(const CXXRecordDecl *RD,
- int64_t Offset,
- const CXXRecordDecl *Type) {
- // <special-name> ::= TC <type> <offset number> _ <base type>
- Out << "_ZTC";
- mangleName(RD);
- Out << Offset;
- Out << "_";
- mangleName(Type);
-}
-
-void CXXNameMangler::mangleCXXRtti(QualType Ty) {
- // <special-name> ::= TI <type> # typeinfo structure
- Out << "_ZTI";
-
- mangleType(Ty);
-}
-
-void CXXNameMangler::mangleCXXRttiName(QualType Ty) {
- // <special-name> ::= TS <type> # typeinfo name (null terminated byte string)
- Out << "_ZTS";
-
- mangleType(Ty);
-}
-
-void CXXNameMangler::mangleGuardVariable(const VarDecl *D) {
- // <special-name> ::= GV <object name> # Guard variable for one-time
- // # initialization
-
- Out << "_ZGV";
- mangleName(D);
+ mangleFunctionEncoding(FD);
+ else
+ mangleName(cast<VarDecl>(D));
}
void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
// <encoding> ::= <function name> <bare-function-type>
mangleName(FD);
+ // Don't mangle in the type if this isn't a decl we should typically mangle.
+ if (!Context.shouldMangleDeclName(FD))
+ return;
+
// Whether the mangling of a function type includes the return type depends on
// the context and the nature of the function. The rules for deciding whether
// the return type is included are:
@@ -277,7 +228,7 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) ||
isa<CXXConversionDecl>(FD)))
MangleReturnType = true;
-
+
// Mangle the type of the primary template.
FD = PrimaryTemplate->getTemplatedDecl();
}
@@ -290,15 +241,16 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
mangleBareFunctionType(FT, MangleReturnType);
}
-static bool isStdNamespace(const DeclContext *DC) {
- if (!DC->isNamespace() || !DC->getParent()->isTranslationUnit())
- return false;
-
- const NamespaceDecl *NS = cast<NamespaceDecl>(DC);
+static bool isStdNamespace(const NamespaceDecl *NS) {
const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier();
return II && II->isStr("std");
}
+static bool isStdNamespace(const DeclContext *DC) {
+ return DC->isNamespace() && DC->getParent()->isTranslationUnit() &&
+ isStdNamespace(cast<NamespaceDecl>(DC));
+}
+
static const TemplateDecl *
isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
// Check if we have a function template.
@@ -315,7 +267,7 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
TemplateArgs = &Spec->getTemplateArgs();
return Spec->getSpecializedTemplate();
}
-
+
return 0;
}
@@ -328,7 +280,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
const DeclContext *DC = ND->getDeclContext();
while (isa<LinkageSpecDecl>(DC))
DC = DC->getParent();
-
+
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = 0;
@@ -341,24 +293,24 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
mangleUnscopedName(ND);
return;
}
-
+
if (isa<FunctionDecl>(DC)) {
mangleLocalName(ND);
return;
}
-
+
mangleNestedName(ND);
}
-void CXXNameMangler::mangleName(const TemplateDecl *TD,
+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() ==
+ assert(cast<LinkageSpecDecl>(DC)->getLanguage() ==
LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!");
DC = DC->getParent();
}
-
+
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
mangleUnscopedTemplateName(TD);
mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
@@ -372,7 +324,7 @@ void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) {
// ::= St <unqualified-name> # ::std::
if (isStdNamespace(ND->getDeclContext()))
Out << "St";
-
+
mangleUnqualifiedName(ND);
}
@@ -381,61 +333,39 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) {
// ::= <substitution>
if (mangleSubstitution(ND))
return;
-
+
mangleUnscopedName(ND->getTemplatedDecl());
addSubstitution(ND);
}
-void CXXNameMangler::mangleCalloffset(int64_t nv, int64_t v) {
+void CXXNameMangler::mangleNumber(int64_t Number) {
+ // <number> ::= [n] <non-negative decimal integer>
+ if (Number < 0) {
+ Out << 'n';
+ Number = -Number;
+ }
+
+ Out << Number;
+}
+
+void CXXNameMangler::mangleCallOffset(const ThunkAdjustment &Adjustment) {
// <call-offset> ::= h <nv-offset> _
// ::= v <v-offset> _
// <nv-offset> ::= <offset number> # non-virtual base override
- // <v-offset> ::= <offset nubmer> _ <virtual offset number>
+ // <v-offset> ::= <offset number> _ <virtual offset number>
// # virtual base override, with vcall offset
- if (v == 0) {
- Out << "h";
- if (nv < 0) {
- Out << "n";
- nv = -nv;
- }
- Out << nv;
- } else {
- Out << "v";
- if (nv < 0) {
- Out << "n";
- nv = -nv;
- }
- Out << nv;
- Out << "_";
- if (v < 0) {
- Out << "n";
- v = -v;
- }
- Out << v;
+ if (!Adjustment.Virtual) {
+ Out << 'h';
+ mangleNumber(Adjustment.NonVirtual);
+ Out << '_';
+ return;
}
- Out << "_";
-}
-
-void CXXNameMangler::mangleThunk(const FunctionDecl *FD, int64_t nv,
- int64_t v) {
- // <special-name> ::= T <call-offset> <base encoding>
- // # base is the nominal target function of thunk
- Out << "_ZT";
- mangleCalloffset(nv, v);
- mangleFunctionEncoding(FD);
-}
-
- void CXXNameMangler::mangleCovariantThunk(const FunctionDecl *FD,
- int64_t nv_t, int64_t v_t,
- int64_t nv_r, int64_t v_r) {
- // <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
- // # base is the nominal target function of thunk
- // # first call-offset is 'this' adjustment
- // # second call-offset is result adjustment
- Out << "_ZTc";
- mangleCalloffset(nv_t, v_t);
- mangleCalloffset(nv_r, v_r);
- mangleFunctionEncoding(FD);
+
+ Out << 'v';
+ mangleNumber(Adjustment.NonVirtual);
+ Out << '_';
+ mangleNumber(Adjustment.Virtual);
+ Out << '_';
}
void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
@@ -453,13 +383,13 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
Out << "12_GLOBAL__N_1";
break;
}
- }
+ }
if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
mangleSourceName(II);
break;
}
-
+
// We must have an anonymous struct.
const TagDecl *TD = cast<TagDecl>(ND);
if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) {
@@ -470,12 +400,12 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
mangleSourceName(D->getDeclName().getAsIdentifierInfo());
break;
}
-
+
// Get a unique id for the anonymous struct.
uint64_t AnonStructId = Context.getAnonymousStructId(TD);
// Mangle it as a source name in the form
- // [n] $_<id>
+ // [n] $_<id>
// where n is the length of the string.
llvm::SmallString<8> Str;
Str += "$_";
@@ -525,6 +455,12 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
cast<FunctionDecl>(ND)->getNumParams());
break;
+ case DeclarationName::CXXLiteralOperatorName:
+ // Guessing based on existing ABI.
+ Out << "ul";
+ mangleSourceName(Name.getCXXLiteralIdentifier());
+ break;
+
case DeclarationName::CXXUsingDirective:
assert(false && "Can't mangle a using directive name!");
break;
@@ -545,29 +481,29 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND) {
Out << 'N';
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND))
mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers()));
-
+
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = 0;
- if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
+ if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD);
mangleTemplateArgumentList(*TemplateArgs);
} else {
manglePrefix(ND->getDeclContext());
mangleUnqualifiedName(ND);
}
-
+
Out << 'E';
}
-void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
+void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
// <nested-name> ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
Out << 'N';
-
+
mangleTemplatePrefix(TD);
mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
-
+
Out << 'E';
}
@@ -591,23 +527,23 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC) {
while (isa<LinkageSpecDecl>(DC))
DC = DC->getParent();
-
+
if (DC->isTranslationUnit())
return;
-
+
if (mangleSubstitution(cast<NamedDecl>(DC)))
return;
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = 0;
- if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) {
+ if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) {
mangleTemplatePrefix(TD);
mangleTemplateArgumentList(*TemplateArgs);
} else {
manglePrefix(DC->getParent());
mangleUnqualifiedName(cast<NamedDecl>(DC));
}
-
+
addSubstitution(cast<NamedDecl>(DC));
}
@@ -618,12 +554,12 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
if (mangleSubstitution(ND))
return;
-
+
// FIXME: <template-param>
-
+
manglePrefix(ND->getDeclContext());
mangleUnqualifiedName(ND->getTemplatedDecl());
-
+
addSubstitution(ND);
}
@@ -838,6 +774,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
break;
case BuiltinType::ObjCId: Out << "11objc_object"; break;
case BuiltinType::ObjCClass: Out << "10objc_class"; break;
+ case BuiltinType::ObjCSel: Out << "13objc_selector"; break;
}
}
@@ -992,7 +929,7 @@ void CXXNameMangler::mangleType(const FixedWidthIntType *T) {
void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl();
assert(TD && "FIXME: Support dependent template names!");
-
+
mangleName(TD, T->getArgs(), T->getNumArgs());
}
@@ -1001,7 +938,7 @@ void CXXNameMangler::mangleType(const TypenameType *T) {
Out << 'N';
const Type *QTy = T->getQualifier()->getAsType();
- if (const TemplateSpecializationType *TST =
+ if (const TemplateSpecializationType *TST =
dyn_cast<TemplateSpecializationType>(QTy)) {
if (!mangleSubstitution(QualType(TST, 0))) {
TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
@@ -1010,7 +947,7 @@ void CXXNameMangler::mangleType(const TypenameType *T) {
mangleTemplateArgs(TST->getArgs(), TST->getNumArgs());
addSubstitution(QualType(TST, 0));
}
- } else if (const TemplateTypeParmType *TTPT =
+ } else if (const TemplateTypeParmType *TTPT =
dyn_cast<TemplateTypeParmType>(QTy)) {
// We use the QualType mangle type variant here because it handles
// substitutions.
@@ -1019,7 +956,7 @@ void CXXNameMangler::mangleType(const TypenameType *T) {
assert(false && "Unhandled type!");
mangleSourceName(T->getIdentifier());
-
+
Out << 'E';
}
@@ -1047,7 +984,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
case Expr::DeclRefExprClass: {
const Decl *D = cast<DeclRefExpr>(E)->getDecl();
-
+
switch (D->getKind()) {
default: assert(false && "Unhandled decl kind!");
case Decl::NonTypeTemplateParm: {
@@ -1057,23 +994,23 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
}
}
-
+
break;
}
-
- case Expr::UnresolvedDeclRefExprClass: {
- const UnresolvedDeclRefExpr *DRE = cast<UnresolvedDeclRefExpr>(E);
+
+ case Expr::DependentScopeDeclRefExprClass: {
+ const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E);
const Type *QTy = DRE->getQualifier()->getAsType();
assert(QTy && "Qualifier was not type!");
// ::= sr <type> <unqualified-name> # dependent name
Out << "sr";
mangleType(QualType(QTy, 0));
-
+
assert(DRE->getDeclName().getNameKind() == DeclarationName::Identifier &&
"Unhandled decl name kind!");
mangleSourceName(DRE->getDeclName().getAsIdentifierInfo());
-
+
break;
}
@@ -1122,13 +1059,8 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
void CXXNameMangler::mangleTemplateArgumentList(const TemplateArgumentList &L) {
// <template-args> ::= I <template-arg>+ E
Out << "I";
-
- for (unsigned i = 0, e = L.size(); i != e; ++i) {
- const TemplateArgument &A = L[i];
-
- mangleTemplateArgument(A);
- }
-
+ for (unsigned i = 0, e = L.size(); i != e; ++i)
+ mangleTemplateArgument(L[i]);
Out << "E";
}
@@ -1136,11 +1068,8 @@ void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
// <template-args> ::= I <template-arg>+ E
Out << "I";
-
- for (unsigned i = 0; i != NumTemplateArgs; ++i) {
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
mangleTemplateArgument(TemplateArgs[i]);
- }
-
Out << "E";
}
@@ -1161,14 +1090,12 @@ void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) {
mangleExpression(A.getAsExpr());
Out << 'E';
break;
- case TemplateArgument::Integral:
+ case TemplateArgument::Integral: {
// <expr-primary> ::= L <type> <value number> E # integer literal
+ const llvm::APSInt *Integral = A.getAsIntegral();
Out << 'L';
-
mangleType(A.getIntegralType());
-
- const llvm::APSInt *Integral = A.getAsIntegral();
if (A.getIntegralType()->isBooleanType()) {
// Boolean values are encoded as 0/1.
Out << (Integral->getBoolValue() ? '1' : '0');
@@ -1177,10 +1104,27 @@ void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) {
Out << 'n';
Integral->abs().print(Out, false);
}
+ Out << 'E';
+ break;
+ }
+ case TemplateArgument::Declaration: {
+ // <expr-primary> ::= L <mangled-name> E # external name
+ // FIXME: Clang produces AST's where pointer-to-member-function expressions
+ // and pointer-to-function expressions are represented as a declaration not
+ // an expression; this is not how gcc represents them and this changes the
+ // mangling.
+ Out << 'L';
+ // References to external entities use the mangled name; if the name would
+ // not normally be manged then mangle it as unqualified.
+ //
+ // FIXME: The ABI specifies that external names here should have _Z, but
+ // gcc leaves this off.
+ mangle(cast<NamedDecl>(A.getAsDecl()), "Z");
Out << 'E';
break;
}
+ }
}
void CXXNameMangler::mangleTemplateParameter(unsigned Index) {
@@ -1198,7 +1142,7 @@ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) {
// Try one of the standard substitutions first.
if (mangleStandardSubstitution(ND))
return true;
-
+
ND = cast<NamedDecl>(ND->getCanonicalDecl());
return mangleSubstitution(reinterpret_cast<uintptr_t>(ND));
}
@@ -1208,79 +1152,79 @@ bool CXXNameMangler::mangleSubstitution(QualType T) {
if (const RecordType *RT = T->getAs<RecordType>())
return mangleSubstitution(RT->getDecl());
}
-
+
uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
return mangleSubstitution(TypePtr);
}
bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
- llvm::DenseMap<uintptr_t, unsigned>::iterator I =
+ llvm::DenseMap<uintptr_t, unsigned>::iterator I =
Substitutions.find(Ptr);
if (I == Substitutions.end())
return false;
-
+
unsigned SeqID = I->second;
if (SeqID == 0)
Out << "S_";
else {
SeqID--;
-
+
// <seq-id> is encoded in base-36, using digits and upper case letters.
char Buffer[10];
char *BufferPtr = Buffer + 9;
-
+
*BufferPtr = 0;
if (SeqID == 0) *--BufferPtr = '0';
-
+
while (SeqID) {
assert(BufferPtr > Buffer && "Buffer overflow!");
-
+
unsigned char c = static_cast<unsigned char>(SeqID) % 36;
-
+
*--BufferPtr = (c < 10 ? '0' + c : 'A' + c - 10);
SeqID /= 36;
}
-
+
Out << 'S' << BufferPtr << '_';
}
-
+
return true;
}
static bool isCharType(QualType T) {
if (T.isNull())
return false;
-
+
return T->isSpecificBuiltinType(BuiltinType::Char_S) ||
T->isSpecificBuiltinType(BuiltinType::Char_U);
}
-/// isCharSpecialization - Returns whether a given type is a template
+/// isCharSpecialization - Returns whether a given type is a template
/// specialization of a given name with a single argument of type char.
static bool isCharSpecialization(QualType T, const char *Name) {
if (T.isNull())
return false;
-
+
const RecordType *RT = T->getAs<RecordType>();
if (!RT)
return false;
-
- const ClassTemplateSpecializationDecl *SD =
+
+ const ClassTemplateSpecializationDecl *SD =
dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
if (!SD)
return false;
if (!isStdNamespace(SD->getDeclContext()))
return false;
-
+
const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
if (TemplateArgs.size() != 1)
return false;
-
+
if (!isCharType(TemplateArgs[0].getAsType()))
return false;
-
+
return SD->getIdentifier()->getName() == Name;
}
@@ -1298,55 +1242,55 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
if (const ClassTemplateDecl *TD = dyn_cast<ClassTemplateDecl>(ND)) {
if (!isStdNamespace(TD->getDeclContext()))
return false;
-
+
// <substitution> ::= Sa # ::std::allocator
if (TD->getIdentifier()->isStr("allocator")) {
Out << "Sa";
return true;
}
-
+
// <<substitution> ::= Sb # ::std::basic_string
if (TD->getIdentifier()->isStr("basic_string")) {
Out << "Sb";
return true;
}
}
-
- if (const ClassTemplateSpecializationDecl *SD =
+
+ if (const ClassTemplateSpecializationDecl *SD =
dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
// <substitution> ::= Ss # ::std::basic_string<char,
// ::std::char_traits<char>,
// ::std::allocator<char> >
if (SD->getIdentifier()->isStr("basic_string")) {
const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
-
+
if (TemplateArgs.size() != 3)
return false;
-
+
if (!isCharType(TemplateArgs[0].getAsType()))
return false;
-
+
if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
return false;
-
+
if (!isCharSpecialization(TemplateArgs[2].getAsType(), "allocator"))
return false;
Out << "Ss";
return true;
}
-
- // <substitution> ::= So # ::std::basic_ostream<char,
+
+ // <substitution> ::= So # ::std::basic_ostream<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;
@@ -1364,138 +1308,144 @@ void CXXNameMangler::addSubstitution(QualType T) {
return;
}
}
-
+
uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
addSubstitution(TypePtr);
}
void CXXNameMangler::addSubstitution(uintptr_t Ptr) {
unsigned SeqID = Substitutions.size();
-
- assert(!Substitutions.count(Ptr) && "Substitution already exists!");
- Substitutions[Ptr] = SeqID;
-}
-
-namespace clang {
- /// \brief Mangles the name of the declaration D and emits that name to the
- /// given output stream.
- ///
- /// If the declaration D requires a mangled name, this routine will emit that
- /// mangled name to \p os and return true. Otherwise, \p os will be unchanged
- /// and this routine will return false. In this case, the caller should just
- /// emit the identifier of the declaration (\c D->getIdentifier()) as its
- /// name.
- bool mangleName(MangleContext &Context, const NamedDecl *D,
- llvm::raw_ostream &os) {
- assert(!isa<CXXConstructorDecl>(D) &&
- "Use mangleCXXCtor for constructor decls!");
- assert(!isa<CXXDestructorDecl>(D) &&
- "Use mangleCXXDtor for destructor decls!");
-
- PrettyStackTraceDecl CrashInfo(const_cast<NamedDecl *>(D), SourceLocation(),
- Context.getASTContext().getSourceManager(),
- "Mangling declaration");
-
- CXXNameMangler Mangler(Context, os);
- if (!Mangler.mangle(D))
- return false;
-
- os.flush();
- return true;
- }
-
- /// \brief Mangles the a thunk with the offset n for the declaration D and
- /// emits that name to the given output stream.
- void mangleThunk(MangleContext &Context, const FunctionDecl *FD,
- int64_t nv, int64_t v, llvm::raw_ostream &os) {
- // FIXME: Hum, we might have to thunk these, fix.
- assert(!isa<CXXDestructorDecl>(FD) &&
- "Use mangleCXXDtor for destructor decls!");
-
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleThunk(FD, nv, v);
- os.flush();
- }
-
- /// \brief Mangles the a covariant thunk for the declaration D and emits that
- /// name to the given output stream.
- void mangleCovariantThunk(MangleContext &Context, const FunctionDecl *FD,
- int64_t nv_t, int64_t v_t,
- int64_t nv_r, int64_t v_r,
- llvm::raw_ostream &os) {
- // FIXME: Hum, we might have to thunk these, fix.
- assert(!isa<CXXDestructorDecl>(FD) &&
- "Use mangleCXXDtor for destructor decls!");
-
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleCovariantThunk(FD, nv_t, v_t, nv_r, v_r);
- os.flush();
- }
-
- /// mangleGuardVariable - Returns the mangled name for a guard variable
- /// for the passed in VarDecl.
- void mangleGuardVariable(MangleContext &Context, const VarDecl *D,
- llvm::raw_ostream &os) {
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleGuardVariable(D);
-
- os.flush();
- }
-
- void mangleCXXCtor(MangleContext &Context, const CXXConstructorDecl *D,
- CXXCtorType Type, llvm::raw_ostream &os) {
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleCXXCtor(D, Type);
- os.flush();
- }
-
- void mangleCXXDtor(MangleContext &Context, const CXXDestructorDecl *D,
- CXXDtorType Type, llvm::raw_ostream &os) {
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleCXXDtor(D, Type);
+ assert(!Substitutions.count(Ptr) && "Substitution already exists!");
+ Substitutions[Ptr] = SeqID;
+}
- os.flush();
- }
+//
- void mangleCXXVtable(MangleContext &Context, const CXXRecordDecl *RD,
- llvm::raw_ostream &os) {
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleCXXVtable(RD);
+/// \brief Mangles the name of the declaration D and emits that name to the
+/// given output stream.
+///
+/// If the declaration D requires a mangled name, this routine will emit that
+/// mangled name to \p os and return true. Otherwise, \p os will be unchanged
+/// and this routine will return false. In this case, the caller should just
+/// emit the identifier of the declaration (\c D->getIdentifier()) as its
+/// name.
+void MangleContext::mangleName(const NamedDecl *D,
+ llvm::SmallVectorImpl<char> &Res) {
+ assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
+ "Invalid mangleName() call, argument is not a variable or function!");
+ assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
+ "Invalid mangleName() call on 'structor decl!");
+
+ PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
+ getASTContext().getSourceManager(),
+ "Mangling declaration");
+
+ CXXNameMangler Mangler(*this, Res);
+ return Mangler.mangle(D);
+}
+
+void MangleContext::mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
+ llvm::SmallVectorImpl<char> &Res) {
+ CXXNameMangler Mangler(*this, Res, D, Type);
+ Mangler.mangle(D);
+}
+
+void MangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
+ llvm::SmallVectorImpl<char> &Res) {
+ CXXNameMangler Mangler(*this, Res, D, Type);
+ Mangler.mangle(D);
+}
+
+/// \brief Mangles the a thunk with the offset n for the declaration D and
+/// emits that name to the given output stream.
+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!");
- os.flush();
- }
-
- void mangleCXXVTT(MangleContext &Context, const CXXRecordDecl *RD,
- llvm::raw_ostream &os) {
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleCXXVTT(RD);
+ // <special-name> ::= T <call-offset> <base encoding>
+ // # base is the nominal target function of thunk
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZT";
+ Mangler.mangleCallOffset(ThisAdjustment);
+ Mangler.mangleFunctionEncoding(FD);
+}
+
+/// \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!");
- os.flush();
- }
+ // <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
+ // # base is the nominal target function of thunk
+ // # first call-offset is 'this' adjustment
+ // # second call-offset is result adjustment
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZTc";
+ Mangler.mangleCallOffset(Adjustment.ThisAdjustment);
+ Mangler.mangleCallOffset(Adjustment.ReturnAdjustment);
+ Mangler.mangleFunctionEncoding(FD);
+}
- void mangleCXXCtorVtable(MangleContext &Context, const CXXRecordDecl *RD,
- int64_t Offset, const CXXRecordDecl *Type,
- llvm::raw_ostream &os) {
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleCXXCtorVtable(RD, Offset, Type);
+/// mangleGuardVariable - Returns the mangled name for a guard variable
+/// for the passed in VarDecl.
+void MangleContext::mangleGuardVariable(const VarDecl *D,
+ llvm::SmallVectorImpl<char> &Res) {
+ // <special-name> ::= GV <object name> # Guard variable for one-time
+ // # initialization
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZGV";
+ Mangler.mangleName(D);
+}
- os.flush();
- }
+void MangleContext::mangleCXXVtable(const CXXRecordDecl *RD,
+ llvm::SmallVectorImpl<char> &Res) {
+ // <special-name> ::= TV <type> # virtual table
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZTV";
+ Mangler.mangleName(RD);
+}
- void mangleCXXRtti(MangleContext &Context, QualType Ty,
- llvm::raw_ostream &os) {
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleCXXRtti(Ty);
+void MangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
+ llvm::SmallVectorImpl<char> &Res) {
+ // <special-name> ::= TT <type> # VTT structure
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZTT";
+ Mangler.mangleName(RD);
+}
- os.flush();
- }
+void MangleContext::mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
+ const CXXRecordDecl *Type,
+ llvm::SmallVectorImpl<char> &Res) {
+ // <special-name> ::= TC <type> <offset number> _ <base type>
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZTC";
+ Mangler.mangleName(RD);
+ Mangler.getStream() << Offset;
+ Mangler.getStream() << "_";
+ Mangler.mangleName(Type);
+}
- void mangleCXXRttiName(MangleContext &Context, QualType Ty,
- llvm::raw_ostream &os) {
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleCXXRttiName(Ty);
+void MangleContext::mangleCXXRtti(QualType Ty,
+ llvm::SmallVectorImpl<char> &Res) {
+ // <special-name> ::= TI <type> # typeinfo structure
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZTI";
+ Mangler.mangleType(Ty);
+}
- os.flush();
- }
+void MangleContext::mangleCXXRttiName(QualType Ty,
+ llvm::SmallVectorImpl<char> &Res) {
+ // <special-name> ::= TS <type> # typeinfo name (null terminated byte string)
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZTS";
+ Mangler.mangleType(Ty);
}
diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h
index 458708f..65b1d9f 100644
--- a/lib/CodeGen/Mangle.h
+++ b/lib/CodeGen/Mangle.h
@@ -23,7 +23,7 @@
#include "llvm/ADT/DenseMap.h"
namespace llvm {
- class raw_ostream;
+ template<typename T> class SmallVectorImpl;
}
namespace clang {
@@ -34,50 +34,59 @@ namespace clang {
class NamedDecl;
class VarDecl;
- class MangleContext {
- ASTContext &Context;
-
- llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
+namespace CodeGen {
+ class CovariantThunkAdjustment;
+ class ThunkAdjustment;
+
+/// MangleContext - Context for tracking state which persists across multiple
+/// calls to the C++ name mangler.
+class MangleContext {
+ ASTContext &Context;
- public:
- explicit MangleContext(ASTContext &Context)
+ llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
+
+public:
+ explicit MangleContext(ASTContext &Context)
: Context(Context) { }
-
- ASTContext &getASTContext() const { return Context; }
-
- uint64_t getAnonymousStructId(const TagDecl *TD) {
- std::pair<llvm::DenseMap<const TagDecl *,
- uint64_t>::iterator, bool> Result =
+
+ ASTContext &getASTContext() const { return Context; }
+
+ uint64_t getAnonymousStructId(const TagDecl *TD) {
+ std::pair<llvm::DenseMap<const TagDecl *,
+ uint64_t>::iterator, bool> Result =
AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size()));
- return Result.first->second;
- }
- };
+ return Result.first->second;
+ }
+
+ /// @name Mangler Entry Points
+ /// @{
- bool mangleName(MangleContext &Context, const NamedDecl *D,
- llvm::raw_ostream &os);
- void mangleThunk(MangleContext &Context, const FunctionDecl *FD,
- int64_t n, int64_t vn, llvm::raw_ostream &os);
- void mangleCovariantThunk(MangleContext &Context, const FunctionDecl *FD,
- int64_t nv_t, int64_t v_t,
- int64_t nv_r, int64_t v_r,
- llvm::raw_ostream &os);
- void mangleGuardVariable(MangleContext &Context, const VarDecl *D,
- llvm::raw_ostream &os);
- void mangleCXXVtable(MangleContext &Context, const CXXRecordDecl *RD,
- llvm::raw_ostream &os);
- void mangleCXXVTT(MangleContext &Context, const CXXRecordDecl *RD,
- llvm::raw_ostream &os);
- void mangleCXXCtorVtable(MangleContext &Context, const CXXRecordDecl *RD,
- int64_t Offset, const CXXRecordDecl *Type,
- llvm::raw_ostream &os);
- void mangleCXXRtti(MangleContext &Context, QualType T,
- llvm::raw_ostream &os);
- void mangleCXXRttiName(MangleContext &Context, QualType T,
- llvm::raw_ostream &os);
- void mangleCXXCtor(MangleContext &Context, const CXXConstructorDecl *D,
- CXXCtorType Type, llvm::raw_ostream &os);
- void mangleCXXDtor(MangleContext &Context, const CXXDestructorDecl *D,
- CXXDtorType Type, llvm::raw_ostream &os);
+ bool shouldMangleDeclName(const NamedDecl *D);
+
+ void mangleName(const NamedDecl *D, llvm::SmallVectorImpl<char> &);
+ void mangleThunk(const FunctionDecl *FD,
+ const ThunkAdjustment &ThisAdjustment,
+ llvm::SmallVectorImpl<char> &);
+ void mangleCovariantThunk(const FunctionDecl *FD,
+ const CovariantThunkAdjustment& Adjustment,
+ llvm::SmallVectorImpl<char> &);
+ void mangleGuardVariable(const VarDecl *D, llvm::SmallVectorImpl<char> &);
+ void mangleCXXVtable(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
+ void mangleCXXVTT(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
+ void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
+ const CXXRecordDecl *Type,
+ 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,
+ llvm::SmallVectorImpl<char> &);
+
+ /// @}
+};
+
+}
}
#endif
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 1d8f31d..017059d 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -22,13 +22,11 @@
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Target/TargetData.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/ADT/OwningPtr.h"
using namespace clang;
-
namespace {
- class VISIBILITY_HIDDEN CodeGeneratorImpl : public CodeGenerator {
+ class CodeGeneratorImpl : public CodeGenerator {
Diagnostic &Diags;
llvm::OwningPtr<const llvm::TargetData> TD;
ASTContext *Ctx;
diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp
index ba0bc66..2bc6175 100644
--- a/lib/CodeGen/TargetABIInfo.cpp
+++ b/lib/CodeGen/TargetABIInfo.cpp
@@ -771,7 +771,7 @@ void X86_64ABIInfo::classify(QualType Ty,
// reference.
if (hasNonTrivialDestructorOrCopyConstructor(RT))
return;
-
+
const RecordDecl *RD = RT->getDecl();
// Assume variable sized types are passed in memory.
@@ -782,6 +782,32 @@ void X86_64ABIInfo::classify(QualType Ty,
// Reset Lo class, this will be recomputed.
Current = NoClass;
+
+ // If this is a C++ record, classify the bases first.
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(),
+ e = CXXRD->bases_end(); i != e; ++i) {
+ assert(!i->isVirtual() && !i->getType()->isDependentType() &&
+ "Unexpected base class!");
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+
+ // Classify this field.
+ //
+ // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate exceeds a
+ // single eightbyte, each is classified separately. Each eightbyte gets
+ // initialized to class NO_CLASS.
+ Class FieldLo, FieldHi;
+ uint64_t Offset = OffsetBase + Layout.getBaseClassOffset(Base);
+ classify(i->getType(), Context, Offset, FieldLo, FieldHi);
+ Lo = merge(Lo, FieldLo);
+ Hi = merge(Hi, FieldHi);
+ if (Lo == Memory || Hi == Memory)
+ break;
+ }
+ }
+
+ // Classify the fields one at a time, merging the results.
unsigned idx = 0;
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
i != e; ++i, ++idx) {
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
index ea75c34..8a57d14 100644
--- a/lib/Driver/ArgList.cpp
+++ b/lib/Driver/ArgList.cpp
@@ -17,6 +17,23 @@
using namespace clang::driver;
+void arg_iterator::SkipToNextArg() {
+ for (; Current != Args.end(); ++Current) {
+ // Done if there are no filters.
+ if (!Id0.isValid())
+ break;
+
+ // Otherwise require a match.
+ const Option &O = (*Current)->getOption();
+ if (O.matches(Id0) ||
+ (Id1.isValid() && O.matches(Id1)) ||
+ (Id2.isValid() && O.matches(Id2)))
+ break;
+ }
+}
+
+//
+
ArgList::ArgList(arglist_type &_Args) : Args(_Args) {
}
@@ -98,95 +115,46 @@ void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id) const {
}
}
-void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0) const {
- // FIXME: Make fast.
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(Id0)) {
- A->claim();
- A->render(*this, Output);
- }
- }
-}
-
-void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0,
- OptSpecifier Id1) const {
- // FIXME: Make fast.
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(Id0) || A->getOption().matches(Id1)) {
- A->claim();
- A->render(*this, Output);
- }
- }
-}
-
void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0,
OptSpecifier Id1, OptSpecifier Id2) const {
- // FIXME: Make fast.
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(Id0) || A->getOption().matches(Id1) ||
- A->getOption().matches(Id2)) {
- A->claim();
- A->render(*this, Output);
- }
- }
-}
-
-void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0) const {
- // FIXME: Make fast.
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(Id0)) {
- A->claim();
- for (unsigned i = 0, e = A->getNumValues(); i != e; ++i)
- Output.push_back(A->getValue(*this, i));
- }
+ for (arg_iterator it = filtered_begin(Id0, Id1, Id2),
+ ie = filtered_end(); it != ie; ++it) {
+ it->claim();
+ it->render(*this, Output);
}
}
void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0,
- OptSpecifier Id1) const {
- // FIXME: Make fast.
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(Id0) || A->getOption().matches(Id1)) {
- A->claim();
- for (unsigned i = 0, e = A->getNumValues(); i != e; ++i)
- Output.push_back(A->getValue(*this, i));
- }
+ OptSpecifier Id1, OptSpecifier Id2) const {
+ for (arg_iterator it = filtered_begin(Id0, Id1, Id2),
+ ie = filtered_end(); it != ie; ++it) {
+ it->claim();
+ for (unsigned i = 0, e = it->getNumValues(); i != e; ++i)
+ Output.push_back(it->getValue(*this, i));
}
}
void ArgList::AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0,
const char *Translation,
bool Joined) const {
- // FIXME: Make fast.
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(Id0)) {
- A->claim();
-
- if (Joined) {
- std::string Value = Translation;
- Value += A->getValue(*this, 0);
- Output.push_back(MakeArgString(Value.c_str()));
- } else {
- Output.push_back(Translation);
- Output.push_back(A->getValue(*this, 0));
- }
+ for (arg_iterator it = filtered_begin(Id0),
+ ie = filtered_end(); it != ie; ++it) {
+ it->claim();
+
+ if (Joined) {
+ Output.push_back(MakeArgString(llvm::StringRef(Translation) +
+ it->getValue(*this, 0)));
+ } else {
+ Output.push_back(Translation);
+ Output.push_back(it->getValue(*this, 0));
}
}
}
void ArgList::ClaimAllArgs(OptSpecifier Id0) const {
- // FIXME: Make fast.
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(Id0))
- A->claim();
- }
+ for (arg_iterator it = filtered_begin(Id0),
+ ie = filtered_end(); it != ie; ++it)
+ it->claim();
}
const char *ArgList::MakeArgString(const llvm::Twine &T) const {
diff --git a/lib/Driver/CC1Options.cpp b/lib/Driver/CC1Options.cpp
index 672fe04..13f84c0 100644
--- a/lib/Driver/CC1Options.cpp
+++ b/lib/Driver/CC1Options.cpp
@@ -8,19 +8,14 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/CC1Options.h"
-#include "clang/Driver/OptTable.h"
#include "clang/Driver/Option.h"
-
+#include "clang/Driver/OptTable.h"
+using namespace clang;
using namespace clang::driver;
using namespace clang::driver::options;
using namespace clang::driver::cc1options;
static OptTable::Info CC1InfoTable[] = {
- // The InputOption info
- { "<input>", 0, 0, Option::InputClass, DriverOption, 0, OPT_INVALID, OPT_INVALID },
- // The UnknownOption info
- { "<unknown>", 0, 0, Option::UnknownClass, 0, 0, OPT_INVALID, OPT_INVALID },
-
#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
{ NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index ffa627a..b819cda 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -85,9 +85,16 @@ bool Compilation::CleanupFileList(const ArgStringList &Files,
for (ArgStringList::const_iterator
it = Files.begin(), ie = Files.end(); it != ie; ++it) {
+
llvm::sys::Path P(*it);
std::string Error;
+ if (!P.isRegularFile()) {
+ // If we have a special file in our list, i.e. /dev/null
+ // then don't call eraseFromDisk() and just continue.
+ continue;
+ }
+
if (P.eraseFromDisk(false, &Error)) {
// Failure is only failure if the file doesn't exist. There is a
// race condition here due to the limited interface of
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index b40dc27..87357cf 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -965,10 +965,9 @@ void Driver::BuildJobs(Compilation &C) const {
if (isa<FlagOption>(Opt)) {
bool DuplicateClaimed = false;
- // FIXME: Use iterator.
- for (ArgList::const_iterator it = C.getArgs().begin(),
- ie = C.getArgs().end(); it != ie; ++it) {
- if ((*it)->isClaimed() && (*it)->getOption().matches(&Opt)) {
+ for (arg_iterator it = C.getArgs().filtered_begin(&Opt),
+ ie = C.getArgs().filtered_end(); it != ie; ++it) {
+ if ((*it)->isClaimed()) {
DuplicateClaimed = true;
break;
}
diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp
index eddaee0..d1af95c 100644
--- a/lib/Driver/DriverOptions.cpp
+++ b/lib/Driver/DriverOptions.cpp
@@ -15,11 +15,6 @@ using namespace clang::driver;
using namespace clang::driver::options;
static OptTable::Info InfoTable[] = {
- // The InputOption info
- { "<input>", 0, 0, Option::InputClass, DriverOption, 0, OPT_INVALID, OPT_INVALID },
- // The UnknownOption info
- { "<unknown>", 0, 0, Option::UnknownClass, 0, 0, OPT_INVALID, OPT_INVALID },
-
#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
{ NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 5f0551b..eb165cf 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -130,13 +130,9 @@ void Clang::AddPreprocessingOptions(const Driver &D,
// wonky, but we include looking for .gch so we can support seamless
// replacement into a build system already set up to be generating
// .gch files.
- //
- // FIXME: Use iterator.
- for (ArgList::const_iterator
- it = Args.begin(), ie = Args.end(); it != ie; ++it) {
- const Arg *A = *it;
- if (!A->getOption().matches(options::OPT_clang_i_Group))
- continue;
+ for (arg_iterator it = Args.filtered_begin(options::OPT_clang_i_Group),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ const Arg *A = it;
if (A->getOption().matches(options::OPT_include)) {
// Use PCH if the user requested it, except for C++ (for now).
@@ -209,7 +205,7 @@ void Clang::AddPreprocessingOptions(const Driver &D,
/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targetting.
//
// FIXME: tblgen this.
-static llvm::StringRef getARMTargetCPU(const ArgList &Args) {
+static const char *getARMTargetCPU(const ArgList &Args) {
// FIXME: Warn on inconsistent use of -mcpu and -march.
// If we have -mcpu=, use that.
@@ -370,7 +366,8 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
CmdArgs.push_back(ABIName);
// Set the CPU based on -march= and -mcpu=.
- CmdArgs.push_back(Args.MakeArgString("-mcpu=" + getARMTargetCPU(Args)));
+ CmdArgs.push_back("-mcpu");
+ CmdArgs.push_back(getARMTargetCPU(Args));
// Select the float ABI as determined by -msoft-float, -mhard-float, and
// -mfloat-abi=.
@@ -421,15 +418,15 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
// Floating point operations and argument passing are soft.
//
// FIXME: This changes CPP defines, we need -target-soft-float.
- CmdArgs.push_back("-soft-float");
- CmdArgs.push_back("-float-abi=soft");
+ CmdArgs.push_back("-msoft-float");
+ CmdArgs.push_back("-mfloat-abi=soft");
} else if (FloatABI == "softfp") {
// Floating point operations are hard, but argument passing is soft.
- CmdArgs.push_back("-float-abi=soft");
+ CmdArgs.push_back("-mfloat-abi=soft");
} else {
// Floating point operations and argument passing are hard.
assert(FloatABI == "hard" && "Invalid float abi!");
- CmdArgs.push_back("-float-abi=hard");
+ CmdArgs.push_back("-mfloat-abi=hard");
}
}
@@ -440,12 +437,12 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
true) ||
Args.hasArg(options::OPT_mkernel) ||
Args.hasArg(options::OPT_fapple_kext))
- CmdArgs.push_back("--disable-red-zone");
+ CmdArgs.push_back("-disable-red-zone");
if (Args.hasFlag(options::OPT_msoft_float,
options::OPT_mno_soft_float,
false))
- CmdArgs.push_back("--no-implicit-float");
+ CmdArgs.push_back("-no-implicit-float");
const char *CPUName = 0;
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
@@ -479,29 +476,25 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
}
if (CPUName) {
- CmdArgs.push_back("--mcpu");
+ CmdArgs.push_back("-mcpu");
CmdArgs.push_back(CPUName);
}
- // FIXME: Use iterator.
- for (ArgList::const_iterator
- it = Args.begin(), ie = Args.end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(options::OPT_m_x86_Features_Group)) {
- llvm::StringRef Name = A->getOption().getName();
+ for (arg_iterator it = Args.filtered_begin(options::OPT_m_x86_Features_Group),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ llvm::StringRef Name = it->getOption().getName();
+ it->claim();
- // Skip over "-m".
- assert(Name.startswith("-m") && "Invalid feature name.");
- Name = Name.substr(2);
+ // Skip over "-m".
+ assert(Name.startswith("-m") && "Invalid feature name.");
+ Name = Name.substr(2);
- bool IsNegative = Name.startswith("no-");
- if (IsNegative)
- Name = Name.substr(3);
+ bool IsNegative = Name.startswith("no-");
+ if (IsNegative)
+ Name = Name.substr(3);
- A->claim();
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
- }
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
}
}
@@ -707,39 +700,42 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
else
Model = getToolChain().GetDefaultRelocationModel();
}
- CmdArgs.push_back("--relocation-model");
- CmdArgs.push_back(Model);
+ if (llvm::StringRef(Model) != "pic") {
+ CmdArgs.push_back("-mrelocation-model");
+ CmdArgs.push_back(Model);
+ }
// Infer the __PIC__ value.
//
// FIXME: This isn't quite right on Darwin, which always sets
// __PIC__=2.
if (strcmp(Model, "pic") == 0 || strcmp(Model, "dynamic-no-pic") == 0) {
- if (Args.hasArg(options::OPT_fPIC))
- CmdArgs.push_back("-pic-level=2");
- else
- CmdArgs.push_back("-pic-level=1");
+ CmdArgs.push_back("-pic-level");
+ CmdArgs.push_back(Args.hasArg(options::OPT_fPIC) ? "2" : "1");
}
+ if (!Args.hasFlag(options::OPT_fmerge_all_constants,
+ options::OPT_fno_merge_all_constants))
+ CmdArgs.push_back("-no-merge-all-constants");
+
+ // LLVM Code Generator Options.
- if (Args.hasArg(options::OPT_ftime_report))
- CmdArgs.push_back("--time-passes");
// FIXME: Set --enable-unsafe-fp-math.
if (Args.hasFlag(options::OPT_fno_omit_frame_pointer,
options::OPT_fomit_frame_pointer))
- CmdArgs.push_back("--disable-fp-elim");
+ CmdArgs.push_back("-mdisable-fp-elim");
if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss,
- options::OPT_fno_zero_initialized_in_bss,
- true))
- CmdArgs.push_back("--nozero-initialized-in-bss");
+ options::OPT_fno_zero_initialized_in_bss))
+ CmdArgs.push_back("-mno-zero-initialized-in-bss");
if (Args.hasArg(options::OPT_dA) || Args.hasArg(options::OPT_fverbose_asm))
- CmdArgs.push_back("--asm-verbose");
- if (Args.hasArg(options::OPT_fdebug_pass_structure))
- CmdArgs.push_back("--debug-pass=Structure");
- if (Args.hasArg(options::OPT_fdebug_pass_arguments))
- CmdArgs.push_back("--debug-pass=Arguments");
- if (!Args.hasFlag(options::OPT_fmerge_all_constants,
- options::OPT_fno_merge_all_constants))
- CmdArgs.push_back("--no-merge-all-constants");
+ CmdArgs.push_back("-masm-verbose");
+ if (Args.hasArg(options::OPT_fdebug_pass_structure)) {
+ CmdArgs.push_back("-mdebug-pass");
+ CmdArgs.push_back("Structure");
+ }
+ if (Args.hasArg(options::OPT_fdebug_pass_arguments)) {
+ CmdArgs.push_back("-mdebug-pass");
+ CmdArgs.push_back("Arguments");
+ }
// This is a coarse approximation of what llvm-gcc actually does, both
// -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more
@@ -751,15 +747,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
!Args.hasArg(options::OPT_mkernel));
if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables,
AsynchronousUnwindTables))
- CmdArgs.push_back("--unwind-tables=1");
- else
- CmdArgs.push_back("--unwind-tables=0");
+ CmdArgs.push_back("-munwind-tables");
+
+ if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
+ CmdArgs.push_back("-mlimit-float-precision");
+ CmdArgs.push_back(A->getValue(Args));
+ }
// FIXME: Handle -mtune=.
(void) Args.hasArg(options::OPT_mtune_EQ);
if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
- CmdArgs.push_back("-code-model");
+ CmdArgs.push_back("-mcode-model");
CmdArgs.push_back(A->getValue(Args));
}
@@ -785,11 +784,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().IsMathErrnoDefault()))
CmdArgs.push_back("-fno-math-errno");
- if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
- CmdArgs.push_back("--limit-float-precision");
- CmdArgs.push_back(A->getValue(Args));
- }
-
Arg *Unsupported;
if ((Unsupported = Args.getLastArg(options::OPT_MG)) ||
(Unsupported = Args.getLastArg(options::OPT_MQ)) ||
@@ -865,7 +859,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
if (Args.hasArg(options::OPT__relocatable_pch))
- CmdArgs.push_back("--relocatable-pch");
+ CmdArgs.push_back("-relocatable-pch");
if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) {
CmdArgs.push_back("-fconstant-string-class");
@@ -873,13 +867,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
// Pass -fmessage-length=.
+ CmdArgs.push_back("-fmessage-length");
if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
- A->render(Args, CmdArgs);
+ CmdArgs.push_back(A->getValue(Args));
} else {
// If -fmessage-length=N was not specified, determine whether this is a
// terminal and, if so, implicitly define -fmessage-length appropriately.
unsigned N = llvm::sys::Process::StandardErrColumns();
- CmdArgs.push_back("-fmessage-length");
CmdArgs.push_back(Args.MakeArgString(llvm::Twine(N)));
}
@@ -931,30 +925,26 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fblocks");
}
+ // -fexceptions=0 is default.
if (needsExceptions(Args, InputType, getToolChain().getTriple()))
CmdArgs.push_back("-fexceptions");
- else
- CmdArgs.push_back("-fexceptions=0");
// -frtti is default.
if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti))
CmdArgs.push_back("-fno-rtti");
// -fsigned-char is default.
- if (!Args.hasFlag(options::OPT_fsigned_char,
- options::OPT_funsigned_char,
+ if (!Args.hasFlag(options::OPT_fsigned_char, options::OPT_funsigned_char,
isSignedCharDefault(getToolChain().getTriple())))
- CmdArgs.push_back("-fsigned-char=0");
+ CmdArgs.push_back("-fno-signed-char");
// -fms-extensions=0 is default.
- if (Args.hasFlag(options::OPT_fms_extensions,
- options::OPT_fno_ms_extensions,
+ if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
getToolChain().getTriple().getOS() == llvm::Triple::Win32))
CmdArgs.push_back("-fms-extensions");
// -fnext-runtime is default.
- if (!Args.hasFlag(options::OPT_fnext_runtime,
- options::OPT_fgnu_runtime,
+ if (!Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
getToolChain().getTriple().getOS() == llvm::Triple::Darwin))
CmdArgs.push_back("-fgnu-runtime");
@@ -1092,15 +1082,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Explicitly warn that these options are unsupported, even though
// we are allowing compilation to continue.
- // FIXME: Use iterator.
- for (ArgList::const_iterator
- it = Args.begin(), ie = Args.end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(options::OPT_pg)) {
- A->claim();
- D.Diag(clang::diag::warn_drv_clang_unsupported)
- << A->getAsString(Args);
- }
+ for (arg_iterator it = Args.filtered_begin(options::OPT_pg),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ it->claim();
+ D.Diag(clang::diag::warn_drv_clang_unsupported) << it->getAsString(Args);
}
// Claim some arguments which clang supports automatically.
@@ -1113,15 +1098,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Claim some arguments which clang doesn't support, but we don't
// care to warn the user about.
-
- // FIXME: Use iterator.
- for (ArgList::const_iterator
- it = Args.begin(), ie = Args.end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(options::OPT_clang_ignored_f_Group) ||
- A->getOption().matches(options::OPT_clang_ignored_m_Group))
- A->claim();
- }
+ Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group);
+ Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group);
}
void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
@@ -1394,18 +1372,13 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
// used to inhibit the default -fno-builtin-str{cat,cpy}.
//
// FIXME: Should we grow a better way to deal with "removing" args?
- //
- // FIXME: Use iterator.
- for (ArgList::const_iterator it = Args.begin(),
- ie = Args.end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(options::OPT_f_Group) ||
- A->getOption().matches(options::OPT_fsyntax_only)) {
- if (!A->getOption().matches(options::OPT_fbuiltin_strcat) &&
- !A->getOption().matches(options::OPT_fbuiltin_strcpy)) {
- A->claim();
- A->render(Args, CmdArgs);
- }
+ for (arg_iterator it = Args.filtered_begin(options::OPT_f_Group,
+ options::OPT_fsyntax_only),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ if (!it->getOption().matches(options::OPT_fbuiltin_strcat) &&
+ !it->getOption().matches(options::OPT_fbuiltin_strcpy)) {
+ it->claim();
+ it->render(Args, CmdArgs);
}
}
} else
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 750286b..3397677 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -135,6 +135,7 @@ types::ID types::lookupTypeForExtension(const char *Ext) {
.Case("CC", TY_CXX)
.Case("cp", TY_CXX)
.Case("hh", TY_CXXHeader)
+ .Case("hpp", TY_CXXHeader)
.Case("ads", TY_Ada)
.Case("adb", TY_Ada)
.Case("ast", TY_AST)
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index e3cd6dd..f647c8a 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -14,25 +14,28 @@
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/PCHReader.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.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/Support/Compiler.h"
+#include "llvm/LLVMContext.h"
#include "llvm/System/Path.h"
-
using namespace clang;
-ASTUnit::ASTUnit(DiagnosticClient *diagClient) : tempFile(false) {
+ASTUnit::ASTUnit(DiagnosticClient *diagClient) : tempFile(false) {
Diags.setClient(diagClient ? diagClient : new TextDiagnosticBuffer());
}
-ASTUnit::~ASTUnit() {
+ASTUnit::~ASTUnit() {
if (tempFile)
llvm::sys::Path(getPCHFileName()).eraseFromDisk();
-
+
// The ASTUnit object owns the DiagnosticClient.
delete Diags.getClient();
}
@@ -41,7 +44,7 @@ namespace {
/// \brief Gathers information from PCHReader that will be used to initialize
/// a Preprocessor.
-class VISIBILITY_HIDDEN PCHInfoCollector : public PCHReaderListener {
+class PCHInfoCollector : public PCHReaderListener {
LangOptions &LangOpt;
HeaderSearch &HSI;
std::string &TargetTriple;
@@ -171,3 +174,90 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
return AST.take();
}
+
+namespace {
+
+class NullAction : public ASTFrontendAction {
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return new ASTConsumer();
+ }
+
+public:
+ virtual bool hasCodeCompletionSupport() const { return false; }
+};
+
+}
+
+ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
+ Diagnostic &Diags,
+ bool OnlyLocalDecls,
+ bool UseBumpAllocator) {
+ // Create the compiler instance to use for building the AST.
+ CompilerInstance Clang(&llvm::getGlobalContext(), false);
+ llvm::OwningPtr<ASTUnit> AST;
+ NullAction Act;
+
+ Clang.getInvocation() = CI;
+
+ Clang.setDiagnostics(&Diags);
+ Clang.setDiagnosticClient(Diags.getClient());
+
+ // Create the target instance.
+ Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
+ Clang.getTargetOpts()));
+ if (!Clang.hasTarget())
+ goto error;
+
+ // Inform the target of the language options.
+ //
+ // FIXME: We shouldn't need to do this, the target should be immutable once
+ // created. This complexity should be lifted elsewhere.
+ Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
+
+ assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
+ "Invocation must have exactly one source file!");
+ assert(Clang.getFrontendOpts().Inputs[0].first != FrontendOptions::IK_AST &&
+ "FIXME: AST inputs not yet supported here!");
+
+ // Create the AST unit.
+ //
+ // FIXME: Use the provided diagnostic client.
+ AST.reset(new ASTUnit());
+
+ // Create a file manager object to provide access to and cache the filesystem.
+ Clang.setFileManager(&AST->getFileManager());
+
+ // Create the source manager.
+ Clang.setSourceManager(&AST->getSourceManager());
+
+ // Create the preprocessor.
+ Clang.createPreprocessor();
+
+ if (!Act.BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
+ /*IsAST=*/false))
+ goto error;
+
+ Act.Execute();
+
+ // Steal the created 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();
+
+ Act.EndSourceFile();
+
+ Clang.takeDiagnosticClient();
+ Clang.takeDiagnostics();
+
+ return AST.take();
+
+error:
+ Clang.takeSourceManager();
+ Clang.takeFileManager();
+ Clang.takeDiagnosticClient();
+ Clang.takeDiagnostics();
+ return 0;
+}
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index ede3d47..5df1ece 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -30,7 +30,6 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PathDiagnosticClients.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
#include "llvm/System/Program.h"
@@ -62,7 +61,7 @@ CreatePlistHTMLDiagnosticClient(const std::string& prefix,
namespace {
- class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
+ class AnalysisConsumer : public ASTConsumer {
public:
typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D);
@@ -312,7 +311,8 @@ static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr,
}
-static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D,
+static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D,
GRTransferFuncs* tf) {
llvm::OwningPtr<GRTransferFuncs> TF(tf);
@@ -327,10 +327,6 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Decl *
return;
GRExprEngine Eng(mgr);
-
- Eng.setTransferFunctions(tf);
- Eng.RegisterInternalChecks(); // FIXME: Internal checks should just
- // automatically register.
if (C.Opts.EnableExperimentalInternalChecks)
RegisterExperimentalInternalChecks(Eng);
@@ -339,6 +335,8 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Decl *
if (C.Opts.EnableExperimentalChecks)
RegisterExperimentalChecks(Eng);
+
+ Eng.setTransferFunctions(tf);
// Set the graph auditor.
llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
@@ -455,26 +453,8 @@ static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr,
static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr,
Decl *D) {
- if (!D)
- return;
-
- C.DisplayFunction(D);
- llvm::OwningPtr<GRTransferFuncs> TF(CreateCallInliner(mgr.getASTContext()));
-
- // Construct the analysis engine.
- GRExprEngine Eng(mgr);
-
- Eng.setTransferFunctions(TF.get());
- Eng.RegisterInternalChecks();
- RegisterAppleChecks(Eng, *D);
-
- // Execute the worklist algorithm.
- Eng.ExecuteWorkList(mgr.getStackFrame(D));
-
- // Visualize the exploded graph.
- if (mgr.shouldVisualizeGraphviz())
- Eng.ViewGraph(mgr.shouldTrimGraph());
+ ActionGRExprEngine(C, mgr, D, CreateCallInliner(mgr.getASTContext()));
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp
index bc56029..9dc109d 100644
--- a/lib/Frontend/Backend.cpp
+++ b/lib/Frontend/Backend.cpp
@@ -25,12 +25,9 @@
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/StandardPasses.h"
#include "llvm/Support/Timer.h"
-#include "llvm/System/Path.h"
-#include "llvm/System/Program.h"
#include "llvm/Target/SubtargetFeature.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
@@ -39,10 +36,11 @@ using namespace clang;
using namespace llvm;
namespace {
- class VISIBILITY_HIDDEN BackendConsumer : public ASTConsumer {
+ class BackendConsumer : public ASTConsumer {
BackendAction Action;
- CodeGenOptions CodeGenOpts;
- TargetOptions TargetOpts;
+ const CodeGenOptions &CodeGenOpts;
+ const LangOptions &LangOpts;
+ const TargetOptions &TargetOpts;
llvm::raw_ostream *AsmOutStream;
llvm::formatted_raw_ostream FormattedOutStream;
ASTContext *Context;
@@ -78,10 +76,12 @@ namespace {
public:
BackendConsumer(BackendAction action, Diagnostic &Diags,
const LangOptions &langopts, const CodeGenOptions &compopts,
- const TargetOptions &targetopts, const std::string &infile,
- llvm::raw_ostream* OS, LLVMContext& C) :
+ const TargetOptions &targetopts, bool TimePasses,
+ const std::string &infile, llvm::raw_ostream *OS,
+ LLVMContext& C) :
Action(action),
CodeGenOpts(compopts),
+ LangOpts(langopts),
TargetOpts(targetopts),
AsmOutStream(OS),
LLVMIRGeneration("LLVM IR Generation Time"),
@@ -94,8 +94,7 @@ namespace {
FormattedOutStream.setStream(*AsmOutStream,
formatted_raw_ostream::PRESERVE_STREAM);
- // Enable -time-passes if -ftime-report is enabled.
- llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
+ llvm::TimePassesIsEnabled = TimePasses;
}
~BackendConsumer() {
@@ -109,7 +108,7 @@ namespace {
virtual void Initialize(ASTContext &Ctx) {
Context = &Ctx;
- if (CodeGenOpts.TimePasses)
+ if (llvm::TimePassesIsEnabled)
LLVMIRGeneration.startTimer();
Gen->Initialize(Ctx);
@@ -118,7 +117,7 @@ namespace {
ModuleProvider = new ExistingModuleProvider(TheModule);
TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription());
- if (CodeGenOpts.TimePasses)
+ if (llvm::TimePassesIsEnabled)
LLVMIRGeneration.stopTimer();
}
@@ -127,24 +126,24 @@ namespace {
Context->getSourceManager(),
"LLVM IR generation of declaration");
- if (CodeGenOpts.TimePasses)
+ if (llvm::TimePassesIsEnabled)
LLVMIRGeneration.startTimer();
Gen->HandleTopLevelDecl(D);
- if (CodeGenOpts.TimePasses)
+ if (llvm::TimePassesIsEnabled)
LLVMIRGeneration.stopTimer();
}
virtual void HandleTranslationUnit(ASTContext &C) {
{
PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
- if (CodeGenOpts.TimePasses)
+ if (llvm::TimePassesIsEnabled)
LLVMIRGeneration.startTimer();
Gen->HandleTranslationUnit(C);
- if (CodeGenOpts.TimePasses)
+ if (llvm::TimePassesIsEnabled)
LLVMIRGeneration.stopTimer();
}
@@ -215,11 +214,50 @@ bool BackendConsumer::AddEmitPasses(std::string &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.
+ 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]);
+
std::string FeaturesStr;
if (TargetOpts.CPU.size() || TargetOpts.Features.size()) {
SubtargetFeatures Features;
Features.setCPU(TargetOpts.CPU);
- for (std::vector<std::string>::iterator
+ for (std::vector<std::string>::const_iterator
it = TargetOpts.Features.begin(),
ie = TargetOpts.Features.end(); it != ie; ++it)
Features.AddFeature(*it);
@@ -306,7 +344,7 @@ void BackendConsumer::CreatePasses() {
llvm::createStandardModulePasses(PM, OptLevel, CodeGenOpts.OptimizeSize,
CodeGenOpts.UnitAtATime,
CodeGenOpts.UnrollLoops,
- CodeGenOpts.SimplifyLibCalls,
+ /*SimplifyLibCalls=*/!LangOpts.NoBuiltin,
/*HaveExceptions=*/true,
InliningPass);
}
@@ -318,7 +356,7 @@ void BackendConsumer::EmitAssembly() {
if (!TheModule || !TheTargetData)
return;
- TimeRegion Region(CodeGenOpts.TimePasses ? &CodeGenerationTime : 0);
+ TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : 0);
// Make sure IR generation is happy with the module. This is
// released by the module provider.
@@ -375,9 +413,10 @@ ASTConsumer *clang::CreateBackendConsumer(BackendAction Action,
const LangOptions &LangOpts,
const CodeGenOptions &CodeGenOpts,
const TargetOptions &TargetOpts,
+ bool TimePasses,
const std::string& InFile,
llvm::raw_ostream* OS,
LLVMContext& C) {
return new BackendConsumer(Action, Diags, LangOpts, CodeGenOpts,
- TargetOpts, InFile, OS, C);
+ TargetOpts, TimePasses, InFile, OS, C);
}
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 3f0f430..03123d3 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -21,6 +21,7 @@ add_clang_library(clangFrontend
HTMLPrint.cpp
InitHeaderSearch.cpp
InitPreprocessor.cpp
+ LangStandards.cpp
PCHReader.cpp
PCHReaderDecl.cpp
PCHReaderStmt.cpp
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index 339a1c4..7296246 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -22,7 +22,6 @@
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
@@ -40,7 +39,7 @@ using namespace clang::io;
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN PTHEntry {
+class PTHEntry {
Offset TokenData, PPCondData;
public:
@@ -54,7 +53,7 @@ public:
};
-class VISIBILITY_HIDDEN PTHEntryKeyVariant {
+class PTHEntryKeyVariant {
union { const FileEntry* FE; const char* Path; };
enum { IsFE = 0x1, IsDE = 0x2, IsNoExist = 0x0 } Kind;
struct stat *StatBuf;
@@ -105,7 +104,7 @@ public:
}
};
-class VISIBILITY_HIDDEN FileEntryPTHEntryInfo {
+class FileEntryPTHEntryInfo {
public:
typedef PTHEntryKeyVariant key_type;
typedef key_type key_type_ref;
@@ -169,7 +168,7 @@ typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap;
typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy;
namespace {
-class VISIBILITY_HIDDEN PTHWriter {
+class PTHWriter {
IDMap IM;
llvm::raw_fd_ostream& Out;
Preprocessor& PP;
@@ -483,7 +482,8 @@ void PTHWriter::GeneratePTH(const std::string *MainFile) {
if (!B) continue;
FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
- Lexer L(FID, SM, LOpts);
+ const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
+ Lexer L(FID, FromFile, SM, LOpts);
PM.insert(FE, LexTokens(L));
}
@@ -577,7 +577,7 @@ public:
};
namespace {
-class VISIBILITY_HIDDEN PTHIdentifierTableTrait {
+class PTHIdentifierTableTrait {
public:
typedef PTHIdKey* key_type;
typedef key_type key_type_ref;
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 0365761..1083d5e 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -27,7 +27,9 @@
#include "llvm/LLVMContext.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Timer.h"
#include "llvm/System/Path.h"
+#include "llvm/System/Program.h"
using namespace clang;
CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext,
@@ -255,6 +257,16 @@ void CompilerInstance::createCodeCompletionConsumer() {
getFrontendOpts().DebugCodeCompletionPrinter,
getFrontendOpts().ShowMacrosInCodeCompletion,
llvm::outs()));
+
+ if (CompletionConsumer->isOutputBinary() &&
+ llvm::sys::Program::ChangeStdoutToBinary()) {
+ getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary);
+ CompletionConsumer.reset();
+ }
+}
+
+void CompilerInstance::createFrontendTimer() {
+ FrontendTimer.reset(new llvm::Timer("Clang front-end timer"));
}
CodeCompleteConsumer *
@@ -321,7 +333,7 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
&OutputPathName);
if (!OS) {
// FIXME: Don't fail this way.
- llvm::errs() << "ERROR: " << Error << "\n";
+ llvm::errs() << "error: " << Error << "\n";
::exit(1);
}
@@ -353,16 +365,16 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
OutFile = "-";
}
- llvm::raw_fd_ostream *OS =
+ llvm::OwningPtr<llvm::raw_fd_ostream> OS(
new llvm::raw_fd_ostream(OutFile.c_str(), Error,
- (Binary ? llvm::raw_fd_ostream::F_Binary : 0));
- if (!OS)
+ (Binary ? llvm::raw_fd_ostream::F_Binary : 0)));
+ if (!Error.empty())
return 0;
if (ResultPathName)
*ResultPathName = OutFile;
- return OS;
+ return OS.take();
}
// Initialization Utilities
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index b4a79c6..c537507 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -8,20 +8,32 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/Version.h"
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/CC1Options.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/OptTable.h"
+#include "clang/Driver/Option.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/LangStandard.h"
+#include "clang/Frontend/PCHReader.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/System/Host.h"
+#include "llvm/System/Path.h"
using namespace clang;
-void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
- const llvm::SmallVectorImpl<llvm::StringRef> &Args) {
-}
-
static const char *getAnalysisName(Analyses Kind) {
switch (Kind) {
default:
llvm::llvm_unreachable("Unknown analysis store!");
#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\
- case NAME: return CMDFLAG;
+ case NAME: return "-" CMDFLAG;
#include "clang/Frontend/Analyses.def"
}
}
@@ -56,6 +68,10 @@ static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) {
}
}
+//===----------------------------------------------------------------------===//
+// Serialization (to args)
+//===----------------------------------------------------------------------===//
+
static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
std::vector<std::string> &Res) {
for (unsigned i = 0, e = Opts.AnalysisList.size(); i != e; ++i)
@@ -93,7 +109,7 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
if (Opts.EnableExperimentalChecks)
Res.push_back("-analyzer-experimental-checks");
if (Opts.EnableExperimentalInternalChecks)
- Res.push_back("-analyzer-experimental-internal-checls");
+ Res.push_back("-analyzer-experimental-internal-checks");
}
static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
@@ -106,20 +122,56 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-disable-red-zone");
if (!Opts.MergeAllConstants)
Res.push_back("-fno-merge-all-constants");
- // NoCommon is only derived.
+ if (Opts.NoCommon)
+ Res.push_back("-fno-common");
if (Opts.NoImplicitFloat)
Res.push_back("-no-implicit-float");
if (Opts.OptimizeSize) {
assert(Opts.OptimizationLevel == 2 && "Invalid options!");
Res.push_back("-Os");
- } else if (Opts.OptimizationLevel == 0)
- Res.push_back("-O" + Opts.OptimizationLevel);
+ } else if (Opts.OptimizationLevel != 0)
+ Res.push_back("-O" + llvm::utostr(Opts.OptimizationLevel));
+ if (!Opts.MainFileName.empty()) {
+ Res.push_back("-main-file-name");
+ Res.push_back(Opts.MainFileName);
+ }
// SimplifyLibCalls is only derived.
// TimePasses is only derived.
// UnitAtATime is unused.
// UnrollLoops is only derived.
// VerifyModule is only derived.
// Inlining is only derived.
+
+ if (Opts.AsmVerbose)
+ Res.push_back("-masm-verbose");
+ if (!Opts.CodeModel.empty()) {
+ Res.push_back("-mcode-model");
+ Res.push_back(Opts.CodeModel);
+ }
+ if (!Opts.DebugPass.empty()) {
+ Res.push_back("-mdebug-pass");
+ Res.push_back(Opts.DebugPass);
+ }
+ if (Opts.DisableFPElim)
+ Res.push_back("-mdisable-fp-elim");
+ if (!Opts.FloatABI.empty()) {
+ Res.push_back("-mfloat-abi");
+ Res.push_back(Opts.FloatABI);
+ }
+ if (!Opts.LimitFloatPrecision.empty()) {
+ Res.push_back("-mlimit-float-precision");
+ Res.push_back(Opts.LimitFloatPrecision);
+ }
+ if (Opts.NoZeroInitializedInBSS)
+ Res.push_back("-mno-zero-initialized-bss");
+ if (Opts.SoftFloat)
+ Res.push_back("-msoft-float");
+ if (Opts.UnwindTables)
+ Res.push_back("-munwind-tables");
+ if (Opts.RelocationModel != "pic") {
+ Res.push_back("-mrelocation-model");
+ Res.push_back(Opts.RelocationModel);
+ }
}
static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts,
@@ -178,18 +230,18 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
static const char *getInputKindName(FrontendOptions::InputKind Kind) {
switch (Kind) {
- case FrontendOptions::IK_None: break;
- case FrontendOptions::IK_AST: return "ast";
- case FrontendOptions::IK_Asm: return "assembler-with-cpp";
- case FrontendOptions::IK_C: return "c";
- case FrontendOptions::IK_CXX: return "c++";
- case FrontendOptions::IK_ObjC: return "objective-c";
- case FrontendOptions::IK_ObjCXX: return "objective-c++";
- case FrontendOptions::IK_OpenCL: return "cl";
- case FrontendOptions::IK_PreprocessedC: return "cpp-output";
- case FrontendOptions::IK_PreprocessedCXX: return "c++-cpp-output";
- case FrontendOptions::IK_PreprocessedObjC: return "objective-c-cpp-output";
- case FrontendOptions::IK_PreprocessedObjCXX: return "objective-c++-cpp-output";
+ case FrontendOptions::IK_None: break;
+ case FrontendOptions::IK_AST: return "ast";
+ case FrontendOptions::IK_Asm: return "assembler-with-cpp";
+ case FrontendOptions::IK_C: return "c";
+ case FrontendOptions::IK_CXX: return "c++";
+ case FrontendOptions::IK_ObjC: return "objective-c";
+ case FrontendOptions::IK_ObjCXX: return "objective-c++";
+ case FrontendOptions::IK_OpenCL: return "cl";
+ case FrontendOptions::IK_PreprocessedC: return "cpp-output";
+ case FrontendOptions::IK_PreprocessedCXX: return "c++-cpp-output";
+ case FrontendOptions::IK_PreprocessedObjC: return "objective-c-cpp-output";
+ case FrontendOptions::IK_PreprocessedObjCXX:return "objective-c++-cpp-output";
}
llvm::llvm_unreachable("Unexpected language kind!");
@@ -247,7 +299,7 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
if (Opts.ShowMacrosInCodeCompletion)
Res.push_back("-code-completion-macros");
if (Opts.ShowStats)
- Res.push_back("-stats");
+ Res.push_back("-print-stats");
if (Opts.ShowTimers)
Res.push_back("-ftime-report");
@@ -305,13 +357,13 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
/// User specified include entries.
for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) {
const HeaderSearchOptions::Entry &E = Opts.UserEntries[i];
- if (E.IsFramework && (E.Group != frontend::Angled || E.IsUserSupplied))
+ if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied))
llvm::llvm_report_error("Invalid option set!");
if (E.IsUserSupplied) {
if (E.Group == frontend::After) {
Res.push_back("-idirafter");
} else if (E.Group == frontend::Quoted) {
- Res.push_back("-iquoted");
+ Res.push_back("-iquote");
} else if (E.Group == frontend::System) {
Res.push_back("-isystem");
} else {
@@ -391,8 +443,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fno-lax-vector-conversions");
if (Opts.AltiVec)
Res.push_back("-faltivec");
- Res.push_back("-fexceptions");
- Res.push_back(Opts.Exceptions ? "1" : "0");
+ if (Opts.Exceptions)
+ Res.push_back("-fexceptions");
if (!Opts.Rtti)
Res.push_back("-fno-rtti");
if (!Opts.NeXTRuntime)
@@ -406,7 +458,7 @@ static void LangOptsToArgs(const LangOptions &Opts,
if (Opts.POSIXThreads)
Res.push_back("-pthread");
if (Opts.Blocks)
- Res.push_back("-fblocks=1");
+ Res.push_back("-fblocks");
if (Opts.EmitAllDecls)
Res.push_back("-femit-all-decls");
if (!Opts.MathErrno)
@@ -425,12 +477,13 @@ static void LangOptsToArgs(const LangOptions &Opts,
}
if (Opts.ObjCGCBitmapPrint)
Res.push_back("-print-ivar-layout");
- Res.push_back("-faccess-control");
- Res.push_back(Opts.AccessControl ? "1" : "0");
- Res.push_back("-fsigned-char");
- Res.push_back(Opts.CharIsSigned ? "1" : "0");
- Res.push_back("-fshort-wchar");
- Res.push_back(Opts.ShortWChar ? "1" : "0");
+ // FIXME: Don't forget to update when the default changes!
+ if (Opts.AccessControl)
+ Res.push_back("-faccess-control");
+ if (!Opts.CharIsSigned)
+ Res.push_back("-fno-signed-char");
+ if (Opts.ShortWChar)
+ Res.push_back("-fshort-wchar");
if (!Opts.ElideConstructors)
Res.push_back("-fno-elide-constructors");
if (Opts.getGCMode() != LangOptions::NonGC) {
@@ -444,7 +497,7 @@ static void LangOptsToArgs(const LangOptions &Opts,
if (Opts.getVisibilityMode() != LangOptions::Default) {
Res.push_back("-fvisibility");
if (Opts.getVisibilityMode() == LangOptions::Hidden) {
- Res.push_back("default");
+ Res.push_back("hidden");
} else {
assert(Opts.getVisibilityMode() == LangOptions::Protected &&
"Invalid visibility!");
@@ -455,15 +508,11 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-stack-protector");
Res.push_back(llvm::utostr(Opts.getStackProtectorMode()));
}
- if (Opts.getMainFileName()) {
- Res.push_back("-main-file-name");
- Res.push_back(Opts.getMainFileName());
- }
if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth) {
Res.push_back("-ftemplate-depth");
Res.push_back(llvm::utostr(Opts.InstantiationDepth));
}
- if (Opts.ObjCConstantStringClass) {
+ if (!Opts.ObjCConstantStringClass.empty()) {
Res.push_back("-fconstant-string-class");
Res.push_back(Opts.ObjCConstantStringClass);
}
@@ -472,28 +521,34 @@ static void LangOptsToArgs(const LangOptions &Opts,
static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
std::vector<std::string> &Res) {
for (unsigned i = 0, e = Opts.Macros.size(); i != e; ++i)
- Res.push_back((Opts.Macros[i].second ? "-U" : "-D") + Opts.Macros[i].first);
+ Res.push_back(std::string(Opts.Macros[i].second ? "-U" : "-D") +
+ Opts.Macros[i].first);
for (unsigned i = 0, e = Opts.Includes.size(); i != e; ++i) {
+ // FIXME: We need to avoid reincluding the implicit PCH and PTH includes.
Res.push_back("-include");
Res.push_back(Opts.Includes[i]);
}
for (unsigned i = 0, e = Opts.MacroIncludes.size(); i != e; ++i) {
Res.push_back("-imacros");
- Res.push_back(Opts.Includes[i]);
+ Res.push_back(Opts.MacroIncludes[i]);
}
if (!Opts.UsePredefines)
Res.push_back("-undef");
if (!Opts.ImplicitPCHInclude.empty()) {
- Res.push_back("-implicit-pch-include");
+ Res.push_back("-include-pch");
Res.push_back(Opts.ImplicitPCHInclude);
}
if (!Opts.ImplicitPTHInclude.empty()) {
- Res.push_back("-implicit-pth-include");
+ Res.push_back("-include-pth");
Res.push_back(Opts.ImplicitPTHInclude);
}
if (!Opts.TokenCache.empty()) {
- Res.push_back("-token-cache");
- Res.push_back(Opts.TokenCache);
+ if (Opts.ImplicitPTHInclude.empty()) {
+ Res.push_back("-token-cache");
+ Res.push_back(Opts.TokenCache);
+ } else
+ assert(Opts.ImplicitPTHInclude == Opts.TokenCache &&
+ "Unsupported option combination!");
}
}
@@ -520,7 +575,7 @@ static void TargetOptsToArgs(const TargetOptions &Opts,
Res.push_back("-triple");
Res.push_back(Opts.Triple);
if (!Opts.CPU.empty()) {
- Res.push_back("-target-cpu");
+ Res.push_back("-mcpu");
Res.push_back(Opts.CPU);
}
if (!Opts.ABI.empty()) {
@@ -545,3 +600,663 @@ void CompilerInvocation::toArgs(std::vector<std::string> &Res) {
PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), Res);
TargetOptsToArgs(getTargetOpts(), Res);
}
+
+//===----------------------------------------------------------------------===//
+// Deserialization (to args)
+//===----------------------------------------------------------------------===//
+
+using namespace clang::driver;
+using namespace clang::driver::cc1options;
+
+static llvm::StringRef getLastArgValue(ArgList &Args, cc1options::ID ID,
+ llvm::StringRef Default = "") {
+ if (Arg *A = Args.getLastArg(ID))
+ return A->getValue(Args);
+ return Default;
+}
+
+static int getLastArgIntValue(ArgList &Args, cc1options::ID ID,
+ int Default, Diagnostic &Diags) {
+ Arg *A = Args.getLastArg(ID);
+ if (!A)
+ return Default;
+
+ int Res = Default;
+ if (llvm::StringRef(A->getValue(Args)).getAsInteger(10, Res))
+ Diags.Report(diag::err_drv_invalid_int_value)
+ << A->getAsString(Args) << A->getValue(Args);
+
+ return Res;
+}
+
+static std::vector<std::string>
+getAllArgValues(ArgList &Args, cc1options::ID ID) {
+ llvm::SmallVector<const char *, 16> Values;
+ Args.AddAllArgValues(Values, ID);
+ return std::vector<std::string>(Values.begin(), Values.end());
+}
+
+//
+
+static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
+ Diagnostic &Diags) {
+ using namespace cc1options;
+
+ Opts.AnalysisList.clear();
+#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) \
+ if (Args.hasArg(OPT_analysis_##NAME)) Opts.AnalysisList.push_back(NAME);
+#include "clang/Frontend/Analyses.def"
+
+ if (Arg *A = Args.getLastArg(OPT_analyzer_store)) {
+ llvm::StringRef Name = A->getValue(Args);
+ AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name)
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \
+ .Case(CMDFLAG, NAME##Model)
+#include "clang/Frontend/Analyses.def"
+ .Default(NumStores);
+ // FIXME: Error handling.
+ if (Value == NumStores)
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_O)->getAsString(Args) << Name;
+ else
+ Opts.AnalysisStoreOpt = Value;
+ }
+
+ if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) {
+ llvm::StringRef Name = A->getValue(Args);
+ AnalysisConstraints Value = llvm::StringSwitch<AnalysisConstraints>(Name)
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \
+ .Case(CMDFLAG, NAME##Model)
+#include "clang/Frontend/Analyses.def"
+ .Default(NumConstraints);
+ // FIXME: Error handling.
+ if (Value == NumConstraints)
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_O)->getAsString(Args) << Name;
+ else
+ Opts.AnalysisConstraintsOpt = Value;
+ }
+
+ if (Arg *A = Args.getLastArg(OPT_analyzer_output)) {
+ llvm::StringRef Name = A->getValue(Args);
+ AnalysisDiagClients Value = llvm::StringSwitch<AnalysisDiagClients>(Name)
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) \
+ .Case(CMDFLAG, PD_##NAME)
+#include "clang/Frontend/Analyses.def"
+ .Default(NUM_ANALYSIS_DIAG_CLIENTS);
+ // FIXME: Error handling.
+ if (Value == NUM_ANALYSIS_DIAG_CLIENTS)
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_O)->getAsString(Args) << Name;
+ else
+ Opts.AnalysisDiagOpt = Value;
+ }
+
+ Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz);
+ 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.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead);
+ Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume);
+ Opts.AnalyzeSpecificFunction = getLastArgValue(Args, OPT_analyze_function);
+ Opts.EnableExperimentalChecks = Args.hasArg(OPT_analyzer_experimental_checks);
+ Opts.EnableExperimentalInternalChecks =
+ Args.hasArg(OPT_analyzer_experimental_internal_checks);
+ Opts.TrimGraph = Args.hasArg(OPT_trim_egraph);
+}
+
+static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
+ Diagnostic &Diags) {
+ using namespace cc1options;
+ // -Os implies -O2
+ if (Args.hasArg(OPT_Os))
+ Opts.OptimizationLevel = 2;
+ else {
+ Opts.OptimizationLevel = getLastArgIntValue(Args, OPT_O, 0, Diags);
+ if (Opts.OptimizationLevel > 3) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_O)->getAsString(Args) << Opts.OptimizationLevel;
+ Opts.OptimizationLevel = 3;
+ }
+ }
+
+ // We must always run at least the always inlining pass.
+ Opts.Inlining = (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining
+ : CodeGenOptions::OnlyAlwaysInlining;
+
+ Opts.DebugInfo = Args.hasArg(OPT_g);
+ Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns);
+ Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
+ Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants);
+ Opts.NoCommon = Args.hasArg(OPT_fno_common);
+ Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float);
+ Opts.OptimizeSize = Args.hasArg(OPT_Os);
+ Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize);
+
+ Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose);
+ Opts.CodeModel = getLastArgValue(Args, OPT_mcode_model);
+ Opts.DebugPass = getLastArgValue(Args, OPT_mdebug_pass);
+ Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim);
+ Opts.FloatABI = getLastArgValue(Args, OPT_mfloat_abi);
+ Opts.LimitFloatPrecision = getLastArgValue(Args, OPT_mlimit_float_precision);
+ Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss);
+ Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
+ Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
+ Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic");
+
+ Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name);
+
+ // FIXME: Put elsewhere?
+#ifdef NDEBUG
+ Opts.VerifyModule = 0;
+#else
+ Opts.VerifyModule = 1;
+#endif
+}
+
+static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
+ ArgList &Args) {
+ using namespace cc1options;
+ Opts.OutputFile = getLastArgValue(Args, OPT_dependency_file);
+ Opts.Targets = getAllArgValues(Args, OPT_MT);
+ Opts.IncludeSystemHeaders = Args.hasArg(OPT_sys_header_deps);
+ Opts.UsePhonyTargets = Args.hasArg(OPT_MP);
+}
+
+static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
+ Diagnostic &Diags) {
+ using namespace cc1options;
+ Opts.IgnoreWarnings = Args.hasArg(OPT_w);
+ Opts.NoRewriteMacros = Args.hasArg(OPT_Wno_rewrite_macros);
+ Opts.Pedantic = Args.hasArg(OPT_pedantic);
+ Opts.PedanticErrors = Args.hasArg(OPT_pedantic_errors);
+ Opts.ShowCarets = !Args.hasArg(OPT_fno_caret_diagnostics);
+ Opts.ShowColors = Args.hasArg(OPT_fcolor_diagnostics);
+ Opts.ShowColumn = !Args.hasArg(OPT_fno_show_column);
+ Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info);
+ Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location);
+ Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option);
+ Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
+ Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
+ Opts.MessageLength = getLastArgIntValue(Args, OPT_fmessage_length, 0, Diags);
+ Opts.DumpBuildInformation = getLastArgValue(Args, OPT_dump_build_information);
+ Opts.Warnings = getAllArgValues(Args, OPT_W);
+}
+
+static FrontendOptions::InputKind
+ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
+ using namespace cc1options;
+ Opts.ProgramAction = frontend::ParseSyntaxOnly;
+ if (const Arg *A = Args.getLastArg(OPT_Action_Group)) {
+ switch (A->getOption().getID()) {
+ default:
+ assert(0 && "Invalid option in group!");
+ case OPT_ast_dump:
+ Opts.ProgramAction = frontend::ASTDump; break;
+ case OPT_ast_print:
+ Opts.ProgramAction = frontend::ASTPrint; break;
+ case OPT_ast_print_xml:
+ Opts.ProgramAction = frontend::ASTPrintXML; break;
+ case OPT_ast_view:
+ Opts.ProgramAction = frontend::ASTView; break;
+ case OPT_dump_raw_tokens:
+ Opts.ProgramAction = frontend::DumpRawTokens; break;
+ case OPT_dump_record_layouts:
+ Opts.ProgramAction = frontend::DumpRecordLayouts; break;
+ case OPT_dump_tokens:
+ Opts.ProgramAction = frontend::DumpTokens; break;
+ case OPT_S:
+ Opts.ProgramAction = frontend::EmitAssembly; break;
+ case OPT_emit_llvm_bc:
+ Opts.ProgramAction = frontend::EmitBC; break;
+ case OPT_emit_html:
+ Opts.ProgramAction = frontend::EmitHTML; break;
+ case OPT_emit_llvm:
+ Opts.ProgramAction = frontend::EmitLLVM; break;
+ case OPT_emit_llvm_only:
+ Opts.ProgramAction = frontend::EmitLLVMOnly; break;
+ case OPT_fixit:
+ Opts.ProgramAction = frontend::FixIt; break;
+ case OPT_emit_pch:
+ Opts.ProgramAction = frontend::GeneratePCH; break;
+ case OPT_emit_pth:
+ Opts.ProgramAction = frontend::GeneratePTH; break;
+ case OPT_parse_noop:
+ Opts.ProgramAction = frontend::ParseNoop; break;
+ case OPT_parse_print_callbacks:
+ Opts.ProgramAction = frontend::ParsePrintCallbacks; break;
+ case OPT_fsyntax_only:
+ Opts.ProgramAction = frontend::ParseSyntaxOnly; break;
+ case OPT_print_decl_contexts:
+ Opts.ProgramAction = frontend::PrintDeclContext; break;
+ case OPT_E:
+ Opts.ProgramAction = frontend::PrintPreprocessedInput; break;
+ case OPT_rewrite_blocks:
+ Opts.ProgramAction = frontend::RewriteBlocks; break;
+ case OPT_rewrite_macros:
+ Opts.ProgramAction = frontend::RewriteMacros; break;
+ case OPT_rewrite_objc:
+ Opts.ProgramAction = frontend::RewriteObjC; break;
+ case OPT_rewrite_test:
+ Opts.ProgramAction = frontend::RewriteTest; break;
+ case OPT_analyze:
+ Opts.ProgramAction = frontend::RunAnalysis; break;
+ case OPT_Eonly:
+ Opts.ProgramAction = frontend::RunPreprocessorOnly; break;
+ }
+ }
+ if (const Arg *A = Args.getLastArg(OPT_plugin)) {
+ Opts.ProgramAction = frontend::PluginAction;
+ Opts.ActionName = A->getValue(Args);
+ }
+
+ if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) {
+ Opts.CodeCompletionAt =
+ ParsedSourceLocation::FromString(A->getValue(Args));
+ if (Opts.CodeCompletionAt.FileName.empty())
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue(Args);
+ }
+ Opts.DebugCodeCompletionPrinter =
+ !Args.hasArg(OPT_no_code_completion_debug_printer);
+ Opts.DisableFree = Args.hasArg(OPT_disable_free);
+ Opts.EmptyInputOnly = Args.hasArg(OPT_empty_input_only);
+
+ Opts.FixItLocations.clear();
+ for (arg_iterator it = Args.filtered_begin(OPT_fixit_at),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ const char *Loc = it->getValue(Args);
+ ParsedSourceLocation PSL = ParsedSourceLocation::FromString(Loc);
+
+ if (PSL.FileName.empty()) {
+ Diags.Report(diag::err_drv_invalid_value) << it->getAsString(Args) << Loc;
+ continue;
+ }
+
+ Opts.FixItLocations.push_back(PSL);
+ }
+
+ Opts.OutputFile = getLastArgValue(Args, OPT_o);
+ Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch);
+ Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros);
+ Opts.ShowStats = Args.hasArg(OPT_print_stats);
+ Opts.ShowTimers = Args.hasArg(OPT_ftime_report);
+ Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view);
+
+ FrontendOptions::InputKind DashX = FrontendOptions::IK_None;
+ if (const Arg *A = Args.getLastArg(OPT_x)) {
+ DashX = llvm::StringSwitch<FrontendOptions::InputKind>(A->getValue(Args))
+ .Case("c", FrontendOptions::IK_C)
+ .Case("cl", FrontendOptions::IK_OpenCL)
+ .Case("c", FrontendOptions::IK_C)
+ .Case("cl", FrontendOptions::IK_OpenCL)
+ .Case("c++", FrontendOptions::IK_CXX)
+ .Case("objective-c", FrontendOptions::IK_ObjC)
+ .Case("objective-c++", FrontendOptions::IK_ObjCXX)
+ .Case("cpp-output", FrontendOptions::IK_PreprocessedC)
+ .Case("assembler-with-cpp", FrontendOptions::IK_Asm)
+ .Case("c++-cpp-output", FrontendOptions::IK_PreprocessedCXX)
+ .Case("objective-c-cpp-output", FrontendOptions::IK_PreprocessedObjC)
+ .Case("objective-c++-cpp-output", FrontendOptions::IK_PreprocessedObjCXX)
+ .Case("c-header", FrontendOptions::IK_C)
+ .Case("objective-c-header", FrontendOptions::IK_ObjC)
+ .Case("c++-header", FrontendOptions::IK_CXX)
+ .Case("objective-c++-header", FrontendOptions::IK_ObjCXX)
+ .Case("ast", FrontendOptions::IK_AST)
+ .Default(FrontendOptions::IK_None);
+ if (DashX == FrontendOptions::IK_None)
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue(Args);
+ }
+
+ // '-' is the default input if none is given.
+ std::vector<std::string> Inputs = getAllArgValues(Args, OPT_INPUT);
+ Opts.Inputs.clear();
+ if (Inputs.empty())
+ Inputs.push_back("-");
+ for (unsigned i = 0, e = Inputs.size(); i != e; ++i) {
+ FrontendOptions::InputKind IK = DashX;
+ if (IK == FrontendOptions::IK_None) {
+ IK = FrontendOptions::getInputKindForExtension(
+ llvm::StringRef(Inputs[i]).rsplit('.').second);
+ // FIXME: Remove this hack.
+ if (i == 0)
+ DashX = IK;
+ }
+ Opts.Inputs.push_back(std::make_pair(IK, Inputs[i]));
+ }
+
+ return DashX;
+}
+
+static std::string GetBuiltinIncludePath(const char *Argv0,
+ void *MainAddr) {
+ llvm::sys::Path P = llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
+
+ if (!P.isEmpty()) {
+ P.eraseComponent(); // Remove /clang from foo/bin/clang
+ P.eraseComponent(); // Remove /bin from foo/bin
+
+ // Get foo/lib/clang/<version>/include
+ 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) {
+ using namespace cc1options;
+ Opts.Sysroot = getLastArgValue(Args, OPT_isysroot, "/");
+ Opts.Verbose = Args.hasArg(OPT_v);
+ 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);
+
+ // Add -I... and -F... options in order.
+ for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F),
+ ie = Args.filtered_end(); it != ie; ++it)
+ Opts.AddPath(it->getValue(Args), frontend::Angled, true,
+ /*IsFramework=*/ it->getOption().matches(OPT_F));
+
+ // Add -iprefix/-iwith-prefix/-iwithprefixbefore options.
+ llvm::StringRef Prefix = ""; // FIXME: This isn't the correct default prefix.
+ for (arg_iterator it = Args.filtered_begin(OPT_iprefix, OPT_iwithprefix,
+ OPT_iwithprefixbefore),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ if (it->getOption().matches(OPT_iprefix))
+ Prefix = it->getValue(Args);
+ else if (it->getOption().matches(OPT_iwithprefix))
+ Opts.AddPath(Prefix.str() + it->getValue(Args),
+ frontend::System, false, false);
+ else
+ Opts.AddPath(Prefix.str() + it->getValue(Args),
+ frontend::Angled, false, false);
+ }
+
+ for (arg_iterator it = Args.filtered_begin(OPT_idirafter),
+ ie = Args.filtered_end(); it != ie; ++it)
+ Opts.AddPath(it->getValue(Args), frontend::After, true, false);
+ for (arg_iterator it = Args.filtered_begin(OPT_iquote),
+ ie = Args.filtered_end(); it != ie; ++it)
+ Opts.AddPath(it->getValue(Args), frontend::Quoted, true, false);
+ for (arg_iterator it = Args.filtered_begin(OPT_isystem),
+ ie = Args.filtered_end(); it != ie; ++it)
+ Opts.AddPath(it->getValue(Args), frontend::System, true, false);
+
+ // FIXME: Need options for the various environment variables!
+}
+
+static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
+ FrontendOptions::InputKind IK,
+ Diagnostic &Diags) {
+ // FIXME: Cleanup per-file based stuff.
+
+ // Set some properties which depend soley on the input kind; it would be nice
+ // to move these to the language standard, and have the driver resolve the
+ // input kind + language standard.
+ if (IK == FrontendOptions::IK_Asm) {
+ Opts.AsmPreprocessor = 1;
+ } else if (IK == FrontendOptions::IK_ObjC ||
+ IK == FrontendOptions::IK_ObjCXX ||
+ IK == FrontendOptions::IK_PreprocessedObjC ||
+ IK == FrontendOptions::IK_PreprocessedObjCXX) {
+ Opts.ObjC1 = Opts.ObjC2 = 1;
+ }
+
+ LangStandard::Kind LangStd = LangStandard::lang_unspecified;
+ if (const Arg *A = Args.getLastArg(OPT_std_EQ)) {
+ LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args))
+#define LANGSTANDARD(id, name, desc, features) \
+ .Case(name, LangStandard::lang_##id)
+#include "clang/Frontend/LangStandards.def"
+ .Default(LangStandard::lang_unspecified);
+ if (LangStd == LangStandard::lang_unspecified)
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue(Args);
+ }
+
+ if (LangStd == LangStandard::lang_unspecified) {
+ // Based on the base language, pick one.
+ switch (IK) {
+ case FrontendOptions::IK_None:
+ case FrontendOptions::IK_AST:
+ assert(0 && "Invalid input kind!");
+ case FrontendOptions::IK_OpenCL:
+ LangStd = LangStandard::lang_opencl;
+ break;
+ case FrontendOptions::IK_Asm:
+ case FrontendOptions::IK_C:
+ case FrontendOptions::IK_PreprocessedC:
+ case FrontendOptions::IK_ObjC:
+ case FrontendOptions::IK_PreprocessedObjC:
+ LangStd = LangStandard::lang_gnu99;
+ break;
+ case FrontendOptions::IK_CXX:
+ case FrontendOptions::IK_PreprocessedCXX:
+ case FrontendOptions::IK_ObjCXX:
+ case FrontendOptions::IK_PreprocessedObjCXX:
+ LangStd = LangStandard::lang_gnucxx98;
+ break;
+ }
+ }
+
+ const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
+ Opts.BCPLComment = Std.hasBCPLComments();
+ Opts.C99 = Std.isC99();
+ Opts.CPlusPlus = Std.isCPlusPlus();
+ Opts.CPlusPlus0x = Std.isCPlusPlus0x();
+ Opts.Digraphs = Std.hasDigraphs();
+ Opts.GNUMode = Std.isGNUMode();
+ Opts.GNUInline = !Std.isC99();
+ Opts.HexFloats = Std.hasHexFloats();
+ Opts.ImplicitInt = Std.hasImplicitInt();
+
+ // OpenCL has some additional defaults.
+ if (LangStd == LangStandard::lang_opencl) {
+ Opts.OpenCL = 1;
+ Opts.AltiVec = 1;
+ Opts.CXXOperatorNames = 1;
+ Opts.LaxVectorConversions = 1;
+ }
+
+ // OpenCL and C++ both have bool, true, false keywords.
+ Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
+
+ if (Opts.CPlusPlus)
+ Opts.CXXOperatorNames = !Args.hasArg(OPT_fno_operator_names);
+
+ if (Args.hasArg(OPT_fobjc_gc_only))
+ Opts.setGCMode(LangOptions::GCOnly);
+ else if (Args.hasArg(OPT_fobjc_gc))
+ Opts.setGCMode(LangOptions::HybridGC);
+
+ if (Args.hasArg(OPT_print_ivar_layout))
+ Opts.ObjCGCBitmapPrint = 1;
+
+ if (Args.hasArg(OPT_faltivec))
+ Opts.AltiVec = 1;
+
+ if (Args.hasArg(OPT_pthread))
+ Opts.POSIXThreads = 1;
+
+ llvm::StringRef Vis = getLastArgValue(Args, OPT_fvisibility,
+ "default");
+ if (Vis == "default")
+ Opts.setVisibilityMode(LangOptions::Default);
+ else if (Vis == "hidden")
+ Opts.setVisibilityMode(LangOptions::Hidden);
+ else if (Vis == "protected")
+ Opts.setVisibilityMode(LangOptions::Protected);
+ else
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis;
+
+ Opts.OverflowChecking = Args.hasArg(OPT_ftrapv);
+
+ // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs
+ // is specified, or -std is set to a conforming mode.
+ Opts.Trigraphs = !Opts.GNUMode;
+ if (Args.hasArg(OPT_trigraphs))
+ Opts.Trigraphs = 1;
+
+ Opts.DollarIdents = !Opts.AsmPreprocessor;
+ if (Args.hasArg(OPT_fdollars_in_identifiers))
+ Opts.DollarIdents = 1;
+
+ Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings);
+ Opts.Microsoft = Args.hasArg(OPT_fms_extensions);
+ Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
+ 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.Blocks = Args.hasArg(OPT_fblocks);
+ Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char);
+ Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
+ Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
+ Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
+ Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);
+ Opts.AccessControl = Args.hasArg(OPT_faccess_control);
+ Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);
+ Opts.MathErrno = !Args.hasArg(OPT_fno_math_errno);
+ Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 99,
+ Diags);
+ Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime);
+ Opts.ObjCConstantStringClass = getLastArgValue(Args,
+ OPT_fconstant_string_class);
+ Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi);
+ Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls);
+ Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags);
+ Opts.Static = Args.hasArg(OPT_static_define);
+ Opts.OptimizeSize = 0;
+
+ // FIXME: Eliminate this dependency.
+ unsigned Opt =
+ Args.hasArg(OPT_Os) ? 2 : getLastArgIntValue(Args, OPT_O, 0, Diags);
+ Opts.Optimize = Opt != 0;
+
+ // This is the __NO_INLINE__ define, which just depends on things like the
+ // optimization level and -fno-inline, not actually whether the backend has
+ // inlining enabled.
+ //
+ // FIXME: This is affected by other options (-fno-inline).
+ Opts.NoInline = !Opt;
+
+ unsigned SSP = getLastArgIntValue(Args, OPT_stack_protector, 0, Diags);
+ switch (SSP) {
+ default:
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_stack_protector)->getAsString(Args) << SSP;
+ break;
+ case 0: Opts.setStackProtectorMode(LangOptions::SSPOff); break;
+ case 1: Opts.setStackProtectorMode(LangOptions::SSPOn); break;
+ case 2: Opts.setStackProtectorMode(LangOptions::SSPReq); break;
+ }
+}
+
+static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args) {
+ using namespace cc1options;
+ Opts.ImplicitPCHInclude = getLastArgValue(Args, OPT_include_pch);
+ Opts.ImplicitPTHInclude = getLastArgValue(Args, OPT_include_pth);
+ if (const Arg *A = Args.getLastArg(OPT_token_cache))
+ Opts.TokenCache = A->getValue(Args);
+ else
+ Opts.TokenCache = Opts.ImplicitPTHInclude;
+ Opts.UsePredefines = !Args.hasArg(OPT_undef);
+
+ // Add macros from the command line.
+ for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ if (it->getOption().matches(OPT_D))
+ Opts.addMacroDef(it->getValue(Args));
+ else
+ Opts.addMacroUndef(it->getValue(Args));
+ }
+
+ Opts.MacroIncludes = getAllArgValues(Args, OPT_imacros);
+
+ // Add the ordered list of -includes.
+ for (arg_iterator it = Args.filtered_begin(OPT_include, OPT_include_pch,
+ OPT_include_pth),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ // 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.
+ if (OriginalFile.empty())
+ exit(1);
+
+ Opts.Includes.push_back(OriginalFile);
+ } else
+ Opts.Includes.push_back(it->getValue(Args));
+ }
+}
+
+static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
+ ArgList &Args) {
+ using namespace cc1options;
+ Opts.ShowCPP = !Args.hasArg(OPT_dM);
+ Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD);
+ Opts.ShowLineMarkers = !Args.hasArg(OPT_P);
+ Opts.ShowComments = Args.hasArg(OPT_C);
+ Opts.ShowMacroComments = Args.hasArg(OPT_CC);
+}
+
+static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
+ using namespace cc1options;
+ Opts.ABI = getLastArgValue(Args, OPT_target_abi);
+ Opts.CPU = getLastArgValue(Args, OPT_mcpu);
+ Opts.Triple = getLastArgValue(Args, OPT_triple);
+ Opts.Features = getAllArgValues(Args, OPT_target_feature);
+
+ // Use the host triple if unspecified.
+ if (Opts.Triple.empty())
+ Opts.Triple = llvm::sys::getHostTriple();
+}
+
+//
+
+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());
+ unsigned MissingArgIndex, MissingArgCount;
+ llvm::OwningPtr<InputArgList> Args(
+ Opts->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount));
+
+ // Check for missing argument error.
+ if (MissingArgCount)
+ Diags.Report(diag::err_drv_missing_argument)
+ << Args->getArgString(MissingArgIndex) << MissingArgCount;
+
+ // Issue errors on unknown arguments.
+ for (arg_iterator it = Args->filtered_begin(OPT_UNKNOWN),
+ ie = Args->filtered_end(); it != ie; ++it)
+ Diags.Report(diag::err_drv_unknown_argument) << it->getAsString(*Args);
+
+ ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags);
+ ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, Diags);
+ ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args);
+ ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags);
+ FrontendOptions::InputKind DashX =
+ ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags);
+ ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args,
+ Argv0, MainAddr);
+ if (DashX != FrontendOptions::IK_AST)
+ ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags);
+ ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args);
+ ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args);
+ ParseTargetArgs(Res.getTargetOpts(), *Args);
+}
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index c7f9359..478c339 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -21,14 +21,13 @@
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/StringSet.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN DependencyFileCallback : public PPCallbacks {
+class DependencyFileCallback : public PPCallbacks {
std::vector<std::string> Files;
llvm::StringSet<> FilesSet;
const Preprocessor *PP;
diff --git a/lib/Frontend/DiagChecker.cpp b/lib/Frontend/DiagChecker.cpp
index 26bb6cc..e7a66b1 100644
--- a/lib/Frontend/DiagChecker.cpp
+++ b/lib/Frontend/DiagChecker.cpp
@@ -149,7 +149,8 @@ static void FindExpectedDiags(Preprocessor &PP,
FileID FID = PP.getSourceManager().getMainFileID();
// Create a lexer to lex all the tokens of the main file in raw mode.
- Lexer RawLex(FID, PP.getSourceManager(), PP.getLangOptions());
+ const llvm::MemoryBuffer *FromFile = PP.getSourceManager().getBuffer(FID);
+ Lexer RawLex(FID, FromFile, PP.getSourceManager(), PP.getLangOptions());
// Return comments as tokens, this is how we find expected diagnostics.
RawLex.SetCommentRetentionState(true);
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index ff63a0d..91c946c 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -21,7 +21,7 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang;
-FrontendAction::FrontendAction() : Instance(0), CurrentTimer(0) {}
+FrontendAction::FrontendAction() : Instance(0) {}
FrontendAction::~FrontendAction() {}
@@ -144,8 +144,11 @@ void FrontendAction::Execute() {
return;
}
- llvm::TimeRegion Timer(CurrentTimer);
- ExecuteAction();
+ if (CI.hasFrontendTimer()) {
+ llvm::TimeRegion Timer(CI.getFrontendTimer());
+ ExecuteAction();
+ }
+ else ExecuteAction();
}
void FrontendAction::EndSourceFile() {
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 7a7537b..27e194e 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -170,7 +170,8 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
OS.reset(CI.createDefaultOutputFile(true, InFile, "bc"));
return CreateBackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(),
- CI.getCodeGenOpts(), CI.getTargetOpts(), InFile,
+ CI.getCodeGenOpts(), CI.getTargetOpts(),
+ CI.getFrontendOpts().ShowTimers, InFile,
OS.take(), CI.getLLVMContext());
}
@@ -192,14 +193,15 @@ void DumpRawTokensAction::ExecuteAction() {
SourceManager &SM = PP.getSourceManager();
// Start lexing the specified input file.
- Lexer RawLex(SM.getMainFileID(), SM, PP.getLangOptions());
+ const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID());
+ Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions());
RawLex.SetKeepWhitespaceMode(true);
Token RawTok;
RawLex.LexFromRawLexer(RawTok);
while (RawTok.isNot(tok::eof)) {
PP.DumpToken(RawTok, true);
- fprintf(stderr, "\n");
+ llvm::errs() << "\n";
RawLex.LexFromRawLexer(RawTok);
}
}
@@ -212,7 +214,7 @@ void DumpTokensAction::ExecuteAction() {
do {
PP.Lex(Tok);
PP.DumpToken(Tok, true);
- fprintf(stderr, "\n");
+ llvm::errs() << "\n";
} while (Tok.isNot(tok::eof));
}
@@ -222,8 +224,7 @@ void GeneratePTHAction::ExecuteAction() {
CI.getFrontendOpts().OutputFile == "-") {
// FIXME: Don't fail this way.
// FIXME: Verify that we can actually seek in the given file.
- llvm::errs() << "ERROR: PTH requires an seekable file for output!\n";
- ::exit(1);
+ llvm::llvm_report_error("PTH requires a seekable file for output!");
}
llvm::raw_fd_ostream *OS =
CI.createDefaultOutputFile(true, getCurrentFile());
diff --git a/lib/Frontend/GeneratePCH.cpp b/lib/Frontend/GeneratePCH.cpp
index 0e4f83f..6251bac 100644
--- a/lib/Frontend/GeneratePCH.cpp
+++ b/lib/Frontend/GeneratePCH.cpp
@@ -20,16 +20,13 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/FileManager.h"
#include "llvm/Bitcode/BitstreamWriter.h"
-#include "llvm/System/Path.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
using namespace clang;
-using namespace llvm;
namespace {
- class VISIBILITY_HIDDEN PCHGenerator : public SemaConsumer {
+ class PCHGenerator : public SemaConsumer {
const Preprocessor &PP;
const char *isysroot;
llvm::raw_ostream *Out;
@@ -62,7 +59,7 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
// Write the PCH contents into a buffer
std::vector<unsigned char> Buffer;
- BitstreamWriter Stream(Buffer);
+ llvm::BitstreamWriter Stream(Buffer);
PCHWriter Writer(Stream);
// Emit the PCH file
diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp
index 3ba7abf..93421ca 100644
--- a/lib/Frontend/HTMLDiagnostics.cpp
+++ b/lib/Frontend/HTMLDiagnostics.cpp
@@ -21,7 +21,6 @@
#include "clang/Rewrite/HTMLRewrite.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
@@ -34,7 +33,7 @@ using namespace clang;
namespace {
-class VISIBILITY_HIDDEN HTMLDiagnostics : public PathDiagnosticClient {
+class HTMLDiagnostics : public PathDiagnosticClient {
llvm::sys::Path Directory, FilePrefix;
bool createdDir, noDir;
const Preprocessor &PP;
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index d19ae98..a40a569 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -170,9 +170,8 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base,
const char *Dir32,
const char *Dir64,
const llvm::Triple &triple) {
- // Add the common dirs
+ // Add the base dir
AddPath(Base, System, true, false, false);
- AddPath(Base + "/backward", System, true, false, false);
// Add the multilib dirs
llvm::Triple::ArchType arch = triple.getArch();
@@ -181,6 +180,9 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base,
AddPath(Base + "/" + ArchDir + "/" + Dir64, System, true, false, false);
else
AddPath(Base + "/" + ArchDir + "/" + Dir32, System, true, false, false);
+
+ // Add the backward dir
+ AddPath(Base + "/backward", System, true, false, false);
}
void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(const std::string &Base,
@@ -194,7 +196,15 @@ void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(const std::string &Base,
// FIXME: This probably should goto to some platform utils place.
#ifdef _MSC_VER
+
// Read registry string.
+ // This also supports a means to look for high-versioned keys by use
+ // of a $VERSION placeholder in the key path.
+ // $VERSION in the key path is a placeholder for the version number,
+ // causing the highest value path to be searched for and used.
+ // I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
+ // There can be additional characters in the component. Only the numberic
+ // characters are compared.
bool getSystemRegistryString(const char *keyPath, const char *valueName,
char *value, size_t maxLength) {
HKEY hRootKey = NULL;
@@ -202,6 +212,7 @@ bool getSystemRegistryString(const char *keyPath, const char *valueName,
const char* subKey = NULL;
DWORD valueType;
DWORD valueSize = maxLength - 1;
+ long lResult;
bool returnValue = false;
if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) {
hRootKey = HKEY_CLASSES_ROOT;
@@ -221,13 +232,80 @@ bool getSystemRegistryString(const char *keyPath, const char *valueName,
}
else
return(false);
- long lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey);
- if (lResult == ERROR_SUCCESS) {
- lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
- (LPBYTE)value, &valueSize);
- if (lResult == ERROR_SUCCESS)
- returnValue = true;
- RegCloseKey(hKey);
+ const char *placeHolder = strstr(subKey, "$VERSION");
+ char bestName[256];
+ bestName[0] = '\0';
+ // If we have a $VERSION placeholder, do the highest-version search.
+ if (placeHolder) {
+ const char *keyEnd = placeHolder - 1;
+ const char *nextKey = placeHolder;
+ // Find end of previous key.
+ while ((keyEnd > subKey) && (*keyEnd != '\\'))
+ keyEnd--;
+ // Find end of key containing $VERSION.
+ while (*nextKey && (*nextKey != '\\'))
+ nextKey++;
+ size_t partialKeyLength = keyEnd - subKey;
+ char partialKey[256];
+ if (partialKeyLength > sizeof(partialKey))
+ partialKeyLength = sizeof(partialKey);
+ strncpy(partialKey, subKey, partialKeyLength);
+ partialKey[partialKeyLength] = '\0';
+ HKEY hTopKey = NULL;
+ lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ, &hTopKey);
+ if (lResult == ERROR_SUCCESS) {
+ char keyName[256];
+ 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);
+ }
+ size = sizeof(keyName) - 1;
+ }
+ // If we found the highest versioned key, open the key and get the value.
+ if (bestIndex != -1) {
+ // Append rest of key.
+ strncat(bestName, nextKey, sizeof(bestName) - 1);
+ bestName[sizeof(bestName) - 1] = '\0';
+ // Open the chosen key path remainder.
+ lResult = RegOpenKeyEx(hTopKey, bestName, 0, KEY_READ, &hKey);
+ if (lResult == ERROR_SUCCESS) {
+ lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
+ (LPBYTE)value, &valueSize);
+ if (lResult == ERROR_SUCCESS)
+ returnValue = true;
+ RegCloseKey(hKey);
+ }
+ }
+ RegCloseKey(hTopKey);
+ }
+ }
+ else {
+ lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey);
+ if (lResult == ERROR_SUCCESS) {
+ lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
+ (LPBYTE)value, &valueSize);
+ if (lResult == ERROR_SUCCESS)
+ returnValue = true;
+ RegCloseKey(hKey);
+ }
}
return(returnValue);
}
@@ -240,35 +318,13 @@ bool getSystemRegistryString(const char *, const char *, char *, size_t) {
// Get Visual Studio installation directory.
bool getVisualStudioDir(std::string &path) {
+ char vsIDEInstallDir[256];
// Try the Windows registry first.
- char vs80IDEInstallDir[256];
- char vs90IDEInstallDir[256];
- const char* vsIDEInstallDir = NULL;
- bool has80 = getSystemRegistryString(
- "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0",
- "InstallDir", vs80IDEInstallDir, sizeof(vs80IDEInstallDir) - 1);
- bool has90 = getSystemRegistryString(
- "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0",
- "InstallDir", vs90IDEInstallDir, sizeof(vs90IDEInstallDir) - 1);
+ bool hasVCDir = getSystemRegistryString(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
+ "InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1);
// If we have both vc80 and vc90, pick version we were compiled with.
- if (has80 && has90) {
- #ifdef _MSC_VER
- #if (_MSC_VER >= 1500) // VC90
- vsIDEInstallDir = vs90IDEInstallDir;
- #elif (_MSC_VER == 1400) // VC80
- vsIDEInstallDir = vs80IDEInstallDir;
- #else
- vsIDEInstallDir = vs90IDEInstallDir;
- #endif
- #else
- vsIDEInstallDir = vs90IDEInstallDir;
- #endif
- }
- else if (has90)
- vsIDEInstallDir = vs90IDEInstallDir;
- else if (has80)
- vsIDEInstallDir = vs80IDEInstallDir;
- if (vsIDEInstallDir && *vsIDEInstallDir) {
+ if (hasVCDir && vsIDEInstallDir[0]) {
char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE");
if (p)
*p = '\0';
@@ -307,6 +363,21 @@ bool getVisualStudioDir(std::string &path) {
return(false);
}
+ // Get Windows SDK installation directory.
+bool getWindowsSDKDir(std::string &path) {
+ char windowsSDKInstallDir[256];
+ // Try the Windows registry.
+ bool hasSDKDir = getSystemRegistryString(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
+ "InstallationFolder", windowsSDKInstallDir, sizeof(windowsSDKInstallDir) - 1);
+ // If we have both vc80 and vc90, pick version we were compiled with.
+ if (hasSDKDir && windowsSDKInstallDir[0]) {
+ path = windowsSDKInstallDir;
+ return(true);
+ }
+ return(false);
+}
+
void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) {
// FIXME: temporary hack: hard-coded paths.
llvm::StringRef CIncludeDirs(C_INCLUDE_DIRS);
@@ -324,10 +395,14 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) {
case llvm::Triple::Win32:
{
std::string VSDir;
+ std::string WindowsSDKDir;
if (getVisualStudioDir(VSDir)) {
AddPath(VSDir + "\\VC\\include", System, false, false, false);
- AddPath(VSDir + "\\VC\\PlatformSDK\\Include",
- System, false, false, false);
+ if (getWindowsSDKDir(WindowsSDKDir))
+ AddPath(WindowsSDKDir, System, false, false, false);
+ else
+ AddPath(VSDir + "\\VC\\PlatformSDK\\Include",
+ System, false, false, false);
}
else {
// Default install paths.
@@ -489,6 +564,9 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang,
const llvm::Triple &triple) {
+ if (Lang.CPlusPlus)
+ AddDefaultCPlusPlusIncludePaths(triple);
+
AddDefaultCIncludePaths(triple);
// Add the default framework include paths on Darwin.
@@ -496,9 +574,6 @@ void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang,
AddPath("/System/Library/Frameworks", System, true, false, true);
AddPath("/Library/Frameworks", System, true, false, true);
}
-
- if (Lang.CPlusPlus)
- AddDefaultCPlusPlusIncludePaths(triple);
}
/// RemoveDuplicates - If there are duplicate directory entries in the specified
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index b77c240..972c21f 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -388,13 +388,20 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Buf);
DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Buf);
+ DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Buf);
+ DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Buf);
DefineTypeWidth("__INTMAX_WIDTH__", TI.getIntMaxType(), TI, Buf);
DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Buf);
+ DefineTypeWidth("__PTRDIFF_WIDTH__", TI.getPtrDiffType(0), TI, Buf);
DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Buf);
DefineTypeWidth("__INTPTR_WIDTH__", TI.getIntPtrType(), TI, Buf);
DefineType("__SIZE_TYPE__", TI.getSizeType(), Buf);
+ DefineTypeWidth("__SIZE_WIDTH__", TI.getSizeType(), TI, Buf);
DefineType("__WCHAR_TYPE__", TI.getWCharType(), Buf);
+ DefineTypeWidth("__WCHAR_WIDTH__", TI.getWCharType(), TI, Buf);
DefineType("__WINT_TYPE__", TI.getWIntType(), Buf);
+ DefineTypeWidth("__WINT_WIDTH__", TI.getWIntType(), TI, Buf);
+ DefineTypeWidth("__SIG_ATOMIC_WIDTH__", TI.getSigAtomicType(), TI, Buf);
DefineFloatMacros(Buf, "FLT", &TI.getFloatFormat());
DefineFloatMacros(Buf, "DBL", &TI.getDoubleFormat());
diff --git a/lib/Frontend/LangStandards.cpp b/lib/Frontend/LangStandards.cpp
new file mode 100644
index 0000000..771a58c
--- /dev/null
+++ b/lib/Frontend/LangStandards.cpp
@@ -0,0 +1,44 @@
+//===--- LangStandards.cpp - Language Standard Definitions ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/LangStandard.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
+using namespace clang;
+using namespace clang::frontend;
+
+#define LANGSTANDARD(id, name, desc, features) \
+ static 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!");
+ case lang_unspecified:
+ llvm::llvm_report_error("getLangStandardForKind() on unspecified kind");
+#define LANGSTANDARD(id, name, desc, features) \
+ case lang_##id: return Lang_##id;
+#include "clang/Frontend/LangStandards.def"
+ }
+}
+
+const LangStandard *LangStandard::getLangStandardForName(llvm::StringRef Name) {
+ Kind K = llvm::StringSwitch<Kind>(Name)
+#define LANGSTANDARD(id, name, desc, features) \
+ .Case(name, lang_##id)
+#include "clang/Frontend/LangStandards.def"
+ .Default(lang_unspecified);
+ if (K == lang_unspecified)
+ return 0;
+
+ return &getLangStandardForKind(K);
+}
+
+
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index c9679b7..cb96bcb 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -31,7 +31,6 @@
#include "clang/Basic/Version.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamReader.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/System/Path.h"
@@ -357,7 +356,7 @@ Expr *PCHReader::ReadTypeExpr() {
namespace {
-class VISIBILITY_HIDDEN PCHMethodPoolLookupTrait {
+class PCHMethodPoolLookupTrait {
PCHReader &Reader;
public:
@@ -465,7 +464,7 @@ typedef OnDiskChainedHashTable<PCHMethodPoolLookupTrait>
PCHMethodPoolLookupTable;
namespace {
-class VISIBILITY_HIDDEN PCHIdentifierLookupTrait {
+class PCHIdentifierLookupTrait {
PCHReader &Reader;
// If we know the IdentifierInfo in advance, it is here and we will
@@ -676,7 +675,7 @@ bool PCHReader::ParseLineTable(llvm::SmallVectorImpl<uint64_t> &Record) {
namespace {
-class VISIBILITY_HIDDEN PCHStatData {
+class PCHStatData {
public:
const bool hasStat;
const ino_t ino;
@@ -692,7 +691,7 @@ public:
: hasStat(false), ino(0), dev(0), mode(0), mtime(0), size(0) {}
};
-class VISIBILITY_HIDDEN PCHStatLookupTrait {
+class PCHStatLookupTrait {
public:
typedef const char *external_key_type;
typedef const char *internal_key_type;
@@ -740,7 +739,7 @@ class VISIBILITY_HIDDEN PCHStatLookupTrait {
///
/// This cache is very similar to the stat cache used by pretokenized
/// headers.
-class VISIBILITY_HIDDEN PCHStatCache : public StatSysCallCache {
+class PCHStatCache : public StatSysCallCache {
typedef OnDiskChainedHashTable<PCHStatLookupTrait> CacheTy;
CacheTy *Cache;
@@ -1554,6 +1553,12 @@ void PCHReader::InitializeContext(ASTContext &Ctx) {
if (unsigned ObjCClassRedef
= SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS_REDEFINITION])
Context->ObjCClassRedefinitionType = GetType(ObjCClassRedef);
+#if 0
+ // FIXME. Accommodate for this in several PCH/Index tests
+ if (unsigned ObjCSelRedef
+ = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SEL_REDEFINITION])
+ Context->ObjCSelRedefinitionType = GetType(ObjCSelRedef);
+#endif
if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_DESCRIPTOR])
Context->setBlockDescriptorType(GetType(String));
if (unsigned String
@@ -2155,6 +2160,7 @@ QualType PCHReader::GetType(pch::TypeID ID) {
case pch::PREDEF_TYPE_CHAR32_ID: T = Context->Char32Ty; break;
case pch::PREDEF_TYPE_OBJC_ID: T = Context->ObjCBuiltinIdTy; break;
case pch::PREDEF_TYPE_OBJC_CLASS: T = Context->ObjCBuiltinClassTy; break;
+ case pch::PREDEF_TYPE_OBJC_SEL: T = Context->ObjCBuiltinSelTy; break;
}
assert(!T.isNull() && "Unknown predefined type");
@@ -2583,6 +2589,10 @@ PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
return Context->DeclarationNames.getCXXOperatorName(
(OverloadedOperatorKind)Record[Idx++]);
+ case DeclarationName::CXXLiteralOperatorName:
+ return Context->DeclarationNames.getCXXLiteralOperatorName(
+ GetIdentifierInfo(Record, Idx));
+
case DeclarationName::CXXUsingDirective:
return DeclarationName::getUsingDirectiveName();
}
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index 6a92a2d..03f3b4767 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -441,6 +441,7 @@ Attr *PCHReader::ReadAttributes() {
SIMPLE_ATTR(AnalyzerNoReturn);
STRING_ATTR(Annotate);
STRING_ATTR(AsmLabel);
+ SIMPLE_ATTR(BaseCheck);
case Attr::Blocks:
New = ::new (*Context) BlocksAttr(
@@ -461,6 +462,7 @@ Attr *PCHReader::ReadAttributes() {
SIMPLE_ATTR(Deprecated);
UNSIGNED_ATTR(Destructor);
SIMPLE_ATTR(FastCall);
+ SIMPLE_ATTR(Final);
case Attr::Format: {
std::string Type = ReadString(Record, Idx);
@@ -484,6 +486,7 @@ Attr *PCHReader::ReadAttributes() {
}
SIMPLE_ATTR(GNUInline);
+ SIMPLE_ATTR(Hiding);
case Attr::IBOutletKind:
New = ::new (*Context) IBOutletAttr();
@@ -517,6 +520,7 @@ Attr *PCHReader::ReadAttributes() {
SIMPLE_ATTR(CFReturnsRetained);
SIMPLE_ATTR(NSReturnsRetained);
SIMPLE_ATTR(Overloadable);
+ SIMPLE_ATTR(Override);
SIMPLE_ATTR(Packed);
UNSIGNED_ATTR(PragmaPack);
SIMPLE_ATTR(Pure);
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index 01af67d..00734a0 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -177,6 +177,7 @@ unsigned PCHStmtReader::VisitLabelStmt(LabelStmt *S) {
unsigned PCHStmtReader::VisitIfStmt(IfStmt *S) {
VisitStmt(S);
+ S->setConditionVariable(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
S->setCond(cast<Expr>(StmtStack[StmtStack.size() - 3]));
S->setThen(StmtStack[StmtStack.size() - 2]);
S->setElse(StmtStack[StmtStack.size() - 1]);
@@ -187,6 +188,7 @@ unsigned PCHStmtReader::VisitIfStmt(IfStmt *S) {
unsigned PCHStmtReader::VisitSwitchStmt(SwitchStmt *S) {
VisitStmt(S);
+ S->setConditionVariable(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
S->setCond(cast<Expr>(StmtStack[StmtStack.size() - 2]));
S->setBody(StmtStack.back());
S->setSwitchLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
@@ -208,6 +210,7 @@ unsigned PCHStmtReader::VisitSwitchStmt(SwitchStmt *S) {
unsigned PCHStmtReader::VisitWhileStmt(WhileStmt *S) {
VisitStmt(S);
+ S->setConditionVariable(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
S->setCond(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2]));
S->setBody(StmtStack.back());
S->setWhileLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
@@ -228,6 +231,7 @@ unsigned PCHStmtReader::VisitForStmt(ForStmt *S) {
VisitStmt(S);
S->setInit(StmtStack[StmtStack.size() - 4]);
S->setCond(cast_or_null<Expr>(StmtStack[StmtStack.size() - 3]));
+ S->setConditionVariable(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
S->setInc(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2]));
S->setBody(StmtStack.back());
S->setForLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 8a45ebc..e79f9c9 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -33,7 +33,6 @@
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamWriter.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/System/Path.h"
#include <cstdio>
@@ -44,7 +43,7 @@ using namespace clang;
//===----------------------------------------------------------------------===//
namespace {
- class VISIBILITY_HIDDEN PCHTypeWriter {
+ class PCHTypeWriter {
PCHWriter &Writer;
PCHWriter::RecordData &Record;
@@ -781,7 +780,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
namespace {
// Trait used for the on-disk hash table of stat cache results.
-class VISIBILITY_HIDDEN PCHStatCacheTrait {
+class PCHStatCacheTrait {
public:
typedef const char * key_type;
typedef key_type key_type_ref;
@@ -1359,7 +1358,7 @@ uint64_t PCHWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
namespace {
// Trait used for the on-disk hash table used in the method pool.
-class VISIBILITY_HIDDEN PCHMethodPoolTrait {
+class PCHMethodPoolTrait {
PCHWriter &Writer;
public:
@@ -1561,7 +1560,7 @@ void PCHWriter::WriteMethodPool(Sema &SemaRef) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN PCHIdentifierTableTrait {
+class PCHIdentifierTableTrait {
PCHWriter &Writer;
Preprocessor &PP;
@@ -1764,6 +1763,9 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
AddString(cast<AsmLabelAttr>(Attr)->getLabel(), Record);
break;
+ case Attr::BaseCheck:
+ break;
+
case Attr::Blocks:
Record.push_back(cast<BlocksAttr>(Attr)->getType()); // FIXME: stable
break;
@@ -1792,6 +1794,7 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
break;
case Attr::FastCall:
+ case Attr::Final:
break;
case Attr::Format: {
@@ -1816,6 +1819,7 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
}
case Attr::GNUInline:
+ case Attr::Hiding:
case Attr::IBOutletKind:
case Attr::Malloc:
case Attr::NoDebug:
@@ -1836,6 +1840,7 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
case Attr::CFReturnsRetained:
case Attr::NSReturnsRetained:
case Attr::Overloadable:
+ case Attr::Override:
break;
case Attr::PragmaPack:
@@ -1989,6 +1994,10 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
AddTypeRef(Context.getsigjmp_bufType(), Record);
AddTypeRef(Context.ObjCIdRedefinitionType, Record);
AddTypeRef(Context.ObjCClassRedefinitionType, Record);
+#if 0
+ // FIXME. Accommodate for this in several PCH/Indexer tests
+ AddTypeRef(Context.ObjCSelRedefinitionType, Record);
+#endif
AddTypeRef(Context.getRawBlockdescriptorType(), Record);
AddTypeRef(Context.getRawBlockdescriptorExtendedType(), Record);
Stream.EmitRecord(pch::SPECIAL_TYPES, Record);
@@ -2204,6 +2213,7 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
case BuiltinType::Dependent: ID = pch::PREDEF_TYPE_DEPENDENT_ID; break;
case BuiltinType::ObjCId: ID = pch::PREDEF_TYPE_OBJC_ID; break;
case BuiltinType::ObjCClass: ID = pch::PREDEF_TYPE_OBJC_CLASS; break;
+ case BuiltinType::ObjCSel: ID = pch::PREDEF_TYPE_OBJC_SEL; break;
case BuiltinType::UndeducedAuto:
assert(0 && "Should not see undeduced auto here");
break;
@@ -2274,6 +2284,10 @@ void PCHWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) {
Record.push_back(Name.getCXXOverloadedOperator());
break;
+ case DeclarationName::CXXLiteralOperatorName:
+ AddIdentifierRef(Name.getCXXLiteralIdentifier(), Record);
+ break;
+
case DeclarationName::CXXUsingDirective:
// No extra data to emit
break;
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index 78a56db..27b83ed 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -170,6 +170,7 @@ void PCHStmtWriter::VisitLabelStmt(LabelStmt *S) {
void PCHStmtWriter::VisitIfStmt(IfStmt *S) {
VisitStmt(S);
+ Writer.AddDeclRef(S->getConditionVariable(), Record);
Writer.WriteSubStmt(S->getCond());
Writer.WriteSubStmt(S->getThen());
Writer.WriteSubStmt(S->getElse());
@@ -180,6 +181,7 @@ void PCHStmtWriter::VisitIfStmt(IfStmt *S) {
void PCHStmtWriter::VisitSwitchStmt(SwitchStmt *S) {
VisitStmt(S);
+ Writer.AddDeclRef(S->getConditionVariable(), Record);
Writer.WriteSubStmt(S->getCond());
Writer.WriteSubStmt(S->getBody());
Writer.AddSourceLocation(S->getSwitchLoc(), Record);
@@ -191,6 +193,7 @@ void PCHStmtWriter::VisitSwitchStmt(SwitchStmt *S) {
void PCHStmtWriter::VisitWhileStmt(WhileStmt *S) {
VisitStmt(S);
+ Writer.AddDeclRef(S->getConditionVariable(), Record);
Writer.WriteSubStmt(S->getCond());
Writer.WriteSubStmt(S->getBody());
Writer.AddSourceLocation(S->getWhileLoc(), Record);
@@ -211,6 +214,7 @@ void PCHStmtWriter::VisitForStmt(ForStmt *S) {
VisitStmt(S);
Writer.WriteSubStmt(S->getInit());
Writer.WriteSubStmt(S->getCond());
+ Writer.AddDeclRef(S->getConditionVariable(), Record);
Writer.WriteSubStmt(S->getInc());
Writer.WriteSubStmt(S->getBody());
Writer.AddSourceLocation(S->getForLoc(), Record);
diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp
index 6bcf39a..80ee2c2 100644
--- a/lib/Frontend/PlistDiagnostics.cpp
+++ b/lib/Frontend/PlistDiagnostics.cpp
@@ -16,10 +16,8 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Casting.h"
-#include "llvm/System/Path.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
using namespace clang;
@@ -32,7 +30,7 @@ namespace clang {
}
namespace {
- class VISIBILITY_HIDDEN PlistDiagnostics : public PathDiagnosticClient {
+ class PlistDiagnostics : public PathDiagnosticClient {
std::vector<const PathDiagnostic*> BatchedDiags;
const std::string OutputFile;
const LangOptions &LangOpts;
diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp
index deb5498..c5dc979 100644
--- a/lib/Frontend/PrintParserCallbacks.cpp
+++ b/lib/Frontend/PrintParserCallbacks.cpp
@@ -305,14 +305,16 @@ namespace {
}
virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc,
- FullExprArg CondVal, StmtArg ThenVal,
+ FullExprArg CondVal, DeclPtrTy CondVar,
+ StmtArg ThenVal,
SourceLocation ElseLoc,
StmtArg ElseVal) {
Out << __FUNCTION__ << "\n";
return StmtEmpty();
}
- virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond) {
+ virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond,
+ DeclPtrTy CondVar) {
Out << __FUNCTION__ << "\n";
return StmtEmpty();
}
@@ -325,7 +327,8 @@ namespace {
}
virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
- FullExprArg Cond, StmtArg Body) {
+ FullExprArg Cond, DeclPtrTy CondVar,
+ StmtArg Body) {
Out << __FUNCTION__ << "\n";
return StmtEmpty();
}
@@ -338,8 +341,10 @@ namespace {
}
virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc,
SourceLocation LParenLoc,
- StmtArg First, ExprArg Second,
- ExprArg Third, SourceLocation RParenLoc,
+ StmtArg First, FullExprArg Second,
+ DeclPtrTy SecondVar,
+ FullExprArg Third,
+ SourceLocation RParenLoc,
StmtArg Body) {
Out << __FUNCTION__ << "\n";
return StmtEmpty();
diff --git a/lib/Frontend/RewriteMacros.cpp b/lib/Frontend/RewriteMacros.cpp
index b5d59c0..0bcbd4f 100644
--- a/lib/Frontend/RewriteMacros.cpp
+++ b/lib/Frontend/RewriteMacros.cpp
@@ -65,7 +65,8 @@ static void LexRawTokensFromMainFile(Preprocessor &PP,
// Create a lexer to lex all the tokens of the main file in raw mode. Even
// though it is in raw mode, it will not return comments.
- Lexer RawLex(SM.getMainFileID(), SM, PP.getLangOptions());
+ const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID());
+ Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions());
// Switch on comment lexing because we really do want them.
RawLex.SetCommentRetentionState(true);
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index 06955e5..710fa55 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -2627,7 +2627,7 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
std::string Name = "_OBJC_PROTOCOL_" + Exp->getProtocol()->getNameAsString();
IdentifierInfo *ID = &Context->Idents.get(Name);
VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
- ID, QualType()/*UNUSED*/, 0, VarDecl::Extern);
+ ID, getProtocolType(), 0, VarDecl::Extern);
DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, getProtocolType(), SourceLocation());
Expr *DerefExpr = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf,
Context->getPointerType(DRE->getType()),
diff --git a/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp
index 4a3c0bf..c0977b5 100644
--- a/lib/Frontend/StmtXML.cpp
+++ b/lib/Frontend/StmtXML.cpp
@@ -17,7 +17,6 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -25,7 +24,7 @@ using namespace clang;
//===----------------------------------------------------------------------===//
namespace {
- class VISIBILITY_HIDDEN StmtXML : public StmtVisitor<StmtXML> {
+ class StmtXML : public StmtVisitor<StmtXML> {
DocumentXML& Doc;
//static const char *getOpcodeStr(UnaryOperator::Opcode Op);
@@ -61,8 +60,6 @@ namespace {
Doc.PrintDecl(*DI);
}
} else {
- if (CXXConditionDeclExpr* CCDE = dyn_cast<CXXConditionDeclExpr>(S))
- Doc.PrintDecl(CCDE->getVarDecl());
for (Stmt::child_iterator i = S->child_begin(), e = S->child_end();
i != e; ++i)
DumpSubTree(*i);
diff --git a/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp
index 34bc3c7..fdf2ec8 100644
--- a/lib/Frontend/TextDiagnosticBuffer.cpp
+++ b/lib/Frontend/TextDiagnosticBuffer.cpp
@@ -20,20 +20,29 @@ using namespace clang;
///
void TextDiagnosticBuffer::HandleDiagnostic(Diagnostic::Level Level,
const DiagnosticInfo &Info) {
- llvm::SmallString<100> StrC;
- Info.FormatDiagnostic(StrC);
- std::string Str(StrC.begin(), StrC.end());
+ llvm::SmallString<100> Buf;
+ Info.FormatDiagnostic(Buf);
switch (Level) {
default: assert(0 && "Diagnostic not handled during diagnostic buffering!");
case Diagnostic::Note:
- Notes.push_back(std::make_pair(Info.getLocation(), Str));
+ Notes.push_back(std::make_pair(Info.getLocation(), Buf.str()));
break;
case Diagnostic::Warning:
- Warnings.push_back(std::make_pair(Info.getLocation(), Str));
+ Warnings.push_back(std::make_pair(Info.getLocation(), Buf.str()));
break;
case Diagnostic::Error:
case Diagnostic::Fatal:
- Errors.push_back(std::make_pair(Info.getLocation(), Str));
+ Errors.push_back(std::make_pair(Info.getLocation(), Buf.str()));
break;
}
}
+
+void TextDiagnosticBuffer::FlushDiagnostics(Diagnostic &Diags) const {
+ // FIXME: Flush the diagnostics in order.
+ for (const_iterator it = err_begin(), ie = err_end(); it != ie; ++it)
+ Diags.Report(Diags.getCustomDiagID(Diagnostic::Error, it->second.c_str()));
+ for (const_iterator it = warn_begin(), ie = warn_end(); it != ie; ++it)
+ Diags.Report(Diags.getCustomDiagID(Diagnostic::Warning,it->second.c_str()));
+ for (const_iterator it = note_begin(), ie = note_end(); it != ie; ++it)
+ Diags.Report(Diags.getCustomDiagID(Diagnostic::Note, it->second.c_str()));
+}
diff --git a/lib/Frontend/VerifyDiagnosticsClient.cpp b/lib/Frontend/VerifyDiagnosticsClient.cpp
index 2891aec..99ec910 100644
--- a/lib/Frontend/VerifyDiagnosticsClient.cpp
+++ b/lib/Frontend/VerifyDiagnosticsClient.cpp
@@ -164,12 +164,14 @@ static void FindExpectedDiags(Preprocessor &PP,
DiagList &ExpectedNotes) {
// Create a raw lexer to pull all the comments out of the main file. We don't
// want to look in #include'd headers for expected-error strings.
- FileID FID = PP.getSourceManager().getMainFileID();
- if (PP.getSourceManager().getMainFileID().isInvalid())
+ SourceManager &SM = PP.getSourceManager();
+ FileID FID = SM.getMainFileID();
+ if (SM.getMainFileID().isInvalid())
return;
// Create a lexer to lex all the tokens of the main file in raw mode.
- Lexer RawLex(FID, PP.getSourceManager(), PP.getLangOptions());
+ const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
+ Lexer RawLex(FID, FromFile, SM, PP.getLangOptions());
// Return comments as tokens, this is how we find expected diagnostics.
RawLex.SetCommentRetentionState(true);
diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h
index ccaf349..15b6eaa 100644
--- a/lib/Headers/stdint.h
+++ b/lib/Headers/stdint.h
@@ -214,18 +214,20 @@ typedef __uint_least8_t uint_fast8_t;
/* C99 7.18.1.4 Integer types capable of holding object pointers.
*/
#define __stdint_join3(a,b,c) a ## b ## c
-#define __stdint_exjoin3(a,b,c) __stdint_join3(a,b,c)
+
+#define __intn_t(n) __stdint_join3( int, n, _t)
+#define __uintn_t(n) __stdint_join3(uint, n, _t)
#ifndef __intptr_t_defined
-typedef __stdint_exjoin3( int, __INTPTR_WIDTH__, _t) intptr_t;
+typedef __intn_t(__INTPTR_WIDTH__) intptr_t;
#define __intptr_t_defined
#endif
-typedef __stdint_exjoin3(uint, __INTPTR_WIDTH__, _t) uintptr_t;
+typedef __uintn_t(__INTPTR_WIDTH__) uintptr_t;
/* C99 7.18.1.5 Greatest-width integer types.
*/
-typedef __stdint_exjoin3( int, __INTMAX_WIDTH__, _t) intmax_t;
-typedef __stdint_exjoin3(uint, __INTMAX_WIDTH__, _t) uintmax_t;
+typedef __intn_t(__INTMAX_WIDTH__) intmax_t;
+typedef __uintn_t(__INTMAX_WIDTH__) uintmax_t;
/* C99 7.18.4 Macros for minimum-width integer constants.
*
@@ -602,57 +604,44 @@ typedef __stdint_exjoin3(uint, __INTMAX_WIDTH__, _t) uintmax_t;
/* C99 7.18.2.4 Limits of integer types capable of holding object pointers. */
/* C99 7.18.3 Limits of other integer types. */
+#define __INTN_MIN(n) __stdint_join3( INT, n, _MIN)
+#define __INTN_MAX(n) __stdint_join3( INT, n, _MAX)
+#define __UINTN_MAX(n) __stdint_join3(UINT, n, _MAX)
-#define INTPTR_MIN __stdint_exjoin3( INT, __INTPTR_WIDTH__, _MIN)
-#define INTPTR_MAX __stdint_exjoin3( INT, __INTPTR_WIDTH__, _MAX)
-#define UINTPTR_MAX __stdint_exjoin3(UINT, __INTPTR_WIDTH__, _MAX)
-
-#if __POINTER_WIDTH__ == 64
-
-#define PTRDIFF_MIN INT64_MIN
-#define PTRDIFF_MAX INT64_MAX
-#define SIZE_MAX UINT64_MAX
-
-#elif __POINTER_WIDTH__ == 32
-
-#define PTRDIFF_MIN INT32_MIN
-#define PTRDIFF_MAX INT32_MAX
-#define SIZE_MAX UINT32_MAX
-
-#elif __POINTER_WIDTH__ == 16
-
-#define PTRDIFF_MIN INT16_MIN
-#define PTRDIFF_MAX INT16_MAX
-#define SIZE_MAX UINT16_MAX
-
-#else
-#error "unknown or unset pointer width!"
-#endif
+#define INTPTR_MIN __INTN_MIN(__INTPTR_WIDTH__)
+#define INTPTR_MAX __INTN_MAX(__INTPTR_WIDTH__)
+#define UINTPTR_MAX __UINTN_MAX(__INTPTR_WIDTH__)
+#define PTRDIFF_MIN __INTN_MIN(__PTRDIFF_WIDTH__)
+#define PTRDIFF_MAX __INTN_MAX(__PTRDIFF_WIDTH__)
+#define SIZE_MAX __UINTN_MAX(__SIZE_WIDTH__)
/* C99 7.18.2.5 Limits of greatest-width integer types. */
-#define INTMAX_MIN __stdint_exjoin3( INT, __INTMAX_WIDTH__, _MIN)
-#define INTMAX_MAX __stdint_exjoin3( INT, __INTMAX_WIDTH__, _MAX)
-#define UINTMAX_MAX __stdint_exjoin3(UINT, __INTMAX_WIDTH__, _MAX)
+#define INTMAX_MIN __INTN_MIN(__INTMAX_WIDTH__)
+#define INTMAX_MAX __INTN_MAX(__INTMAX_WIDTH__)
+#define UINTMAX_MAX __UINTN_MAX(__INTMAX_WIDTH__)
/* C99 7.18.3 Limits of other integer types. */
-#define SIG_ATOMIC_MIN INT32_MIN
-#define SIG_ATOMIC_MAX INT32_MAX
-#define WINT_MIN INT32_MIN
-#define WINT_MAX INT32_MAX
+#define SIG_ATOMIC_MIN __INTN_MIN(__SIG_ATOMIC_WIDTH__)
+#define SIG_ATOMIC_MAX __INTN_MAX(__SIG_ATOMIC_WIDTH__)
+#define WINT_MIN __INTN_MIN(__WINT_WIDTH__)
+#define WINT_MAX __INTN_MAX(__WINT_WIDTH__)
/* FIXME: if we ever support a target with unsigned wchar_t, this should be
* 0 .. Max.
*/
#ifndef WCHAR_MAX
-#define WCHAR_MAX __WCHAR_MAX__
+#define WCHAR_MAX __INTN_MAX(__WCHAR_WIDTH__)
#endif
#ifndef WCHAR_MIN
-#define WCHAR_MIN (-__WCHAR_MAX__-1)
+#define WCHAR_MIN __INTN_MIN(__WCHAR_WIDTH__)
#endif
/* 7.18.4.2 Macros for greatest-width integer constants. */
-#define INTMAX_C(v) __stdint_exjoin3( INT, __INTMAX_WIDTH__, _C(v))
-#define UINTMAX_C(v) __stdint_exjoin3(UINT, __INTMAX_WIDTH__, _C(v))
+#define __INTN_C(n, v) __stdint_join3( INT, n, _C(v))
+#define __UINTN_C(n, v) __stdint_join3(UINT, n, _C(v))
+
+#define INTMAX_C(v) __INTN_C(__INTMAX_WIDTH__, v)
+#define UINTMAX_C(v) __UINTN_C(__INTMAX_WIDTH__, v)
#endif /* __STDC_HOSTED__ */
#endif /* __CLANG_STDINT_H */
diff --git a/lib/Index/Analyzer.cpp b/lib/Index/Analyzer.cpp
index 300a469..fb3529d 100644
--- a/lib/Index/Analyzer.cpp
+++ b/lib/Index/Analyzer.cpp
@@ -23,7 +23,6 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprObjC.h"
#include "llvm/ADT/SmallSet.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
using namespace idx;
@@ -33,7 +32,7 @@ namespace {
// DeclEntityAnalyzer Implementation
//===----------------------------------------------------------------------===//
-class VISIBILITY_HIDDEN DeclEntityAnalyzer : public TranslationUnitHandler {
+class DeclEntityAnalyzer : public TranslationUnitHandler {
Entity Ent;
TULocationHandler &TULocHandler;
@@ -57,7 +56,7 @@ public:
// RefEntityAnalyzer Implementation
//===----------------------------------------------------------------------===//
-class VISIBILITY_HIDDEN RefEntityAnalyzer : public TranslationUnitHandler {
+class RefEntityAnalyzer : public TranslationUnitHandler {
Entity Ent;
TULocationHandler &TULocHandler;
@@ -87,7 +86,7 @@ public:
/// \brief Accepts an ObjC method and finds all message expressions that this
/// method may respond to.
-class VISIBILITY_HIDDEN RefSelectorAnalyzer : public TranslationUnitHandler {
+class RefSelectorAnalyzer : public TranslationUnitHandler {
Program &Prog;
TULocationHandler &TULocHandler;
@@ -219,7 +218,7 @@ public:
/// \brief Accepts an ObjC message expression and finds all methods that may
/// respond to it.
-class VISIBILITY_HIDDEN MessageAnalyzer : public TranslationUnitHandler {
+class MessageAnalyzer : public TranslationUnitHandler {
Program &Prog;
TULocationHandler &TULocHandler;
diff --git a/lib/Index/DeclReferenceMap.cpp b/lib/Index/DeclReferenceMap.cpp
index 366cf1b..d6e30ab 100644
--- a/lib/Index/DeclReferenceMap.cpp
+++ b/lib/Index/DeclReferenceMap.cpp
@@ -15,13 +15,12 @@
#include "clang/Index/DeclReferenceMap.h"
#include "clang/Index/ASTLocation.h"
#include "ASTVisitor.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
using namespace idx;
namespace {
-class VISIBILITY_HIDDEN RefMapper : public ASTVisitor<RefMapper> {
+class RefMapper : public ASTVisitor<RefMapper> {
DeclReferenceMap::MapTy &Map;
public:
diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp
index ed905f3..c7379f7 100644
--- a/lib/Index/ResolveLocation.cpp
+++ b/lib/Index/ResolveLocation.cpp
@@ -19,14 +19,13 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Lex/Lexer.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
using namespace idx;
namespace {
/// \brief Base for the LocResolver classes. Mostly does source range checking.
-class VISIBILITY_HIDDEN LocResolverBase {
+class LocResolverBase {
protected:
ASTContext &Ctx;
SourceLocation Loc;
@@ -83,7 +82,7 @@ public:
/// \brief Searches a statement for the ASTLocation that corresponds to a source
/// location.
-class VISIBILITY_HIDDEN StmtLocResolver : public LocResolverBase,
+class StmtLocResolver : public LocResolverBase,
public StmtVisitor<StmtLocResolver,
ASTLocation > {
Decl * const Parent;
@@ -100,7 +99,7 @@ public:
/// \brief Searches a declaration for the ASTLocation that corresponds to a
/// source location.
-class VISIBILITY_HIDDEN DeclLocResolver : public LocResolverBase,
+class DeclLocResolver : public LocResolverBase,
public DeclVisitor<DeclLocResolver,
ASTLocation > {
public:
diff --git a/lib/Index/SelectorMap.cpp b/lib/Index/SelectorMap.cpp
index 325b371..0f11e31 100644
--- a/lib/Index/SelectorMap.cpp
+++ b/lib/Index/SelectorMap.cpp
@@ -14,13 +14,12 @@
#include "clang/Index/SelectorMap.h"
#include "ASTVisitor.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
using namespace idx;
namespace {
-class VISIBILITY_HIDDEN SelMapper : public ASTVisitor<SelMapper> {
+class SelMapper : public ASTVisitor<SelMapper> {
SelectorMap::SelMethMapTy &SelMethMap;
SelectorMap::SelRefMapTy &SelRefMap;
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index f4a4432..52a7a04 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -95,13 +95,11 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
/// with the specified preprocessor managing the lexing process. This lexer
/// assumes that the associated file buffer and Preprocessor objects will
/// outlive it, so it doesn't take ownership of either of them.
-Lexer::Lexer(FileID FID, Preprocessor &PP)
+Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP)
: PreprocessorLexer(&PP, FID),
FileLoc(PP.getSourceManager().getLocForStartOfFile(FID)),
Features(PP.getLangOptions()) {
- const llvm::MemoryBuffer *InputFile = PP.getSourceManager().getBuffer(FID);
-
InitLexer(InputFile->getBufferStart(), InputFile->getBufferStart(),
InputFile->getBufferEnd());
@@ -129,9 +127,9 @@ Lexer::Lexer(SourceLocation fileloc, const LangOptions &features,
/// Lexer constructor - Create a new raw lexer object. This object is only
/// suitable for calls to 'LexRawToken'. This lexer assumes that the text
/// range will outlive it, so it doesn't take ownership of it.
-Lexer::Lexer(FileID FID, const SourceManager &SM, const LangOptions &features)
+Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *FromFile,
+ const SourceManager &SM, const LangOptions &features)
: FileLoc(SM.getLocForStartOfFile(FID)), Features(features) {
- const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
InitLexer(FromFile->getBufferStart(), FromFile->getBufferStart(),
FromFile->getBufferEnd());
@@ -163,7 +161,8 @@ Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc,
// Create the lexer as if we were going to lex the file normally.
FileID SpellingFID = SM.getFileID(SpellingLoc);
- Lexer *L = new Lexer(SpellingFID, PP);
+ const llvm::MemoryBuffer *InputFile = SM.getBuffer(SpellingFID);
+ Lexer *L = new Lexer(SpellingFID, InputFile, PP);
// Now that the lexer is created, change the start/end locations so that we
// just lex the subsection of the file that we want. This is lexing from a
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 42dd75e..ab66942 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -375,46 +375,34 @@ NumericLiteralParser(const char *begin, const char *end,
continue; // Success.
case 'i':
if (PP.getLangOptions().Microsoft) {
+ if (isFPConstant || isUnsigned || isLong || isLongLong) break;
+
// Allow i8, i16, i32, i64, and i128.
if (s + 1 != ThisTokEnd) {
switch (s[1]) {
case '8':
s += 2; // i8 suffix
isMicrosoftInteger = true;
- continue;
+ break;
case '1':
- s += 2;
- if (s == ThisTokEnd) break;
- if (*s == '6') s++; // i16 suffix
- else if (*s == '2') {
- if (++s == ThisTokEnd) break;
- if (*s == '8') s++; // i128 suffix
+ if (s + 2 == ThisTokEnd) break;
+ if (s[2] == '6') s += 3; // i16 suffix
+ else if (s[2] == '2') {
+ if (s + 3 == ThisTokEnd) break;
+ if (s[3] == '8') s += 4; // i128 suffix
}
isMicrosoftInteger = true;
- continue;
+ break;
case '3':
- s += 2;
- if (s == ThisTokEnd) break;
- if (*s == '2') s++; // i32 suffix
+ if (s + 2 == ThisTokEnd) break;
+ if (s[2] == '2') s += 3; // i32 suffix
isMicrosoftInteger = true;
- continue;
+ break;
case '6':
- s += 2;
- if (s == ThisTokEnd) break;
- if (*s == '4') s++; // i64 suffix
+ if (s + 2 == ThisTokEnd) break;
+ if (s[2] == '4') s += 3; // i64 suffix
isMicrosoftInteger = true;
- continue;
- case 'f': // FP Suffix for "float"
- case 'F':
- if (!isFPConstant) break; // Error for integer constant.
- if (isFloat || isLong) break; // FF, LF invalid.
- isFloat = true;
- if (isImaginary) break; // Cannot be repeated.
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin),
- diag::ext_imaginary_constant);
- isImaginary = true;
- s++;
- continue; // Success.
+ break;
default:
break;
}
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index dc7d95e..9caca33 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -16,6 +16,7 @@
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/APInt.h"
using namespace clang;
@@ -1111,7 +1112,9 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
}
// Finally, if all is good, enter the new file!
- EnterSourceFile(FID, CurDir);
+ if (EnterSourceFile(FID, CurDir))
+ Diag(FilenameTok, diag::err_pp_error_opening_file)
+ << std::string(SourceMgr.getFileEntryForID(FID)->getName());
}
/// HandleIncludeNextDirective - Implements #include_next.
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index 41ed991..8a61d7b 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -63,9 +63,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. Return true
-/// on failure.
-void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir) {
+/// start lexing tokens from it instead of the current buffer.
+bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir) {
assert(CurTokenLexer == 0 && "Cannot #include a file inside a macro!");
++NumEnteredSourceFiles;
@@ -73,10 +72,19 @@ void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir) {
MaxIncludeStackDepth = IncludeMacroStack.size();
if (PTH) {
- if (PTHLexer *PL = PTH->CreateLexer(FID))
- return EnterSourceFileWithPTH(PL, CurDir);
+ if (PTHLexer *PL = PTH->CreateLexer(FID)) {
+ EnterSourceFileWithPTH(PL, CurDir);
+ return false;
+ }
}
- EnterSourceFileWithLexer(new Lexer(FID, *this), CurDir);
+
+ // Get the MemoryBuffer for this FID, if it fails, we fail.
+ const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID);
+ if (InputFile == 0)
+ return true;
+
+ EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir);
+ return false;
}
/// EnterSourceFileWithLexer - Add a source file to the top of the include stack
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index d6a73cc..a64008a 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -285,7 +285,7 @@ SourceLocation PTHLexer::getSourceLocation() {
/// to map from FileEntry objects managed by FileManager to offsets within
/// the PTH file.
namespace {
-class VISIBILITY_HIDDEN PTHFileData {
+class PTHFileData {
const uint32_t TokenOff;
const uint32_t PPCondOff;
public:
@@ -297,7 +297,7 @@ public:
};
-class VISIBILITY_HIDDEN PTHFileLookupCommonTrait {
+class PTHFileLookupCommonTrait {
public:
typedef std::pair<unsigned char, const char*> internal_key_type;
@@ -318,7 +318,7 @@ public:
}
};
-class VISIBILITY_HIDDEN PTHFileLookupTrait : public PTHFileLookupCommonTrait {
+class PTHFileLookupTrait : public PTHFileLookupCommonTrait {
public:
typedef const FileEntry* external_key_type;
typedef PTHFileData data_type;
@@ -340,7 +340,7 @@ public:
}
};
-class VISIBILITY_HIDDEN PTHStringLookupTrait {
+class PTHStringLookupTrait {
public:
typedef uint32_t
data_type;
@@ -597,7 +597,7 @@ PTHLexer *PTHManager::CreateLexer(FileID FID) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN PTHStatData {
+class PTHStatData {
public:
const bool hasStat;
const ino_t ino;
@@ -613,7 +613,7 @@ public:
: hasStat(false), ino(0), dev(0), mode(0), mtime(0), size(0) {}
};
-class VISIBILITY_HIDDEN PTHStatLookupTrait : public PTHFileLookupCommonTrait {
+class PTHStatLookupTrait : public PTHFileLookupCommonTrait {
public:
typedef const char* external_key_type; // const char*
typedef PTHStatData data_type;
@@ -646,7 +646,7 @@ public:
}
};
-class VISIBILITY_HIDDEN PTHStatCache : public StatSysCallCache {
+class PTHStatCache : public StatSysCallCache {
typedef OnDiskChainedHashTable<PTHStatLookupTrait> CacheTy;
CacheTy Cache;
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index dde4bc8..df48e3a 100644
--- a/lib/Parse/AttributeList.cpp
+++ b/lib/Parse/AttributeList.cpp
@@ -17,11 +17,13 @@
using namespace clang;
AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc,
+ IdentifierInfo *sName, SourceLocation sLoc,
IdentifierInfo *pName, SourceLocation pLoc,
ActionBase::ExprTy **ExprList, unsigned numArgs,
- AttributeList *n, bool declspec)
- : AttrName(aName), AttrLoc(aLoc), ParmName(pName), ParmLoc(pLoc),
- NumArgs(numArgs), Next(n), DeclspecAttribute(declspec) {
+ AttributeList *n, bool declspec, bool cxx0x)
+ : AttrName(aName), AttrLoc(aLoc), ScopeName(sName), ScopeLoc(sLoc),
+ ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(n),
+ DeclspecAttribute(declspec), CXX0XAttribute(cxx0x) {
if (numArgs == 0)
Args = 0;
@@ -59,13 +61,16 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("mode", AT_mode)
.Case("used", AT_used)
.Case("alias", AT_alias)
+ .Case("align", AT_aligned)
+ .Case("final", AT_final)
.Case("cdecl", AT_cdecl)
.Case("const", AT_const)
- .Case("packed", AT_packed)
- .Case("malloc", AT_malloc)
+ .Case("blocks", AT_blocks)
.Case("format", AT_format)
+ .Case("hiding", AT_hiding)
+ .Case("malloc", AT_malloc)
+ .Case("packed", AT_packed)
.Case("unused", AT_unused)
- .Case("blocks", AT_blocks)
.Case("aligned", AT_aligned)
.Case("cleanup", AT_cleanup)
.Case("nodebug", AT_nodebug)
@@ -76,15 +81,17 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("section", AT_section)
.Case("stdcall", AT_stdcall)
.Case("annotate", AT_annotate)
- .Case("noreturn", AT_noreturn)
- .Case("noinline", AT_noinline)
.Case("fastcall", AT_fastcall)
.Case("iboutlet", AT_IBOutlet)
+ .Case("noreturn", AT_noreturn)
+ .Case("noinline", AT_noinline)
+ .Case("override", AT_override)
.Case("sentinel", AT_sentinel)
.Case("NSObject", AT_nsobject)
.Case("dllimport", AT_dllimport)
.Case("dllexport", AT_dllexport)
.Case("may_alias", IgnoredAttribute) // FIXME: TBAA
+ .Case("base_check", AT_base_check)
.Case("deprecated", AT_deprecated)
.Case("visibility", AT_visibility)
.Case("destructor", AT_destructor)
@@ -103,6 +110,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("transparent_union", AT_transparent_union)
.Case("analyzer_noreturn", AT_analyzer_noreturn)
.Case("warn_unused_result", AT_warn_unused_result)
+ .Case("carries_dependency", AT_carries_dependency)
.Case("ns_returns_retained", AT_ns_returns_retained)
.Case("cf_returns_retained", AT_cf_returns_retained)
.Case("reqd_work_group_size", AT_reqd_wg_size)
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index 7681eac..aa0b89b 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -144,7 +144,7 @@ void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
Action::TypeTy *
MinimalAction::getTypeName(IdentifierInfo &II, SourceLocation Loc,
Scope *S, const CXXScopeSpec *SS,
- bool isClassName) {
+ bool isClassName, TypeTy *ObjectType) {
if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>())
if (TI->isTypeName)
return TI;
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index c34653e..b9314d2 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -37,7 +37,8 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D,
FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true, move(TemplateParams));
else // FIXME: pass template information through
FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D,
- move(TemplateParams), 0, 0);
+ move(TemplateParams), 0, 0,
+ /*IsDefinition*/true);
HandleMemberFunctionDefaultArgs(D, FnD);
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 2bfda30..b13dc73 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1,3 +1,4 @@
+
//===--- ParseDecl.cpp - Declaration Parsing ------------------------------===//
//
// The LLVM Compiler Infrastructure
@@ -45,7 +46,7 @@ Action::TypeResult Parser::ParseTypeName(SourceRange *Range) {
return Actions.ActOnTypeName(CurScope, DeclaratorInfo);
}
-/// ParseAttributes - Parse a non-empty attributes list.
+/// ParseGNUAttributes - Parse a non-empty attributes list.
///
/// [GNU] attributes:
/// attribute
@@ -81,8 +82,8 @@ Action::TypeResult Parser::ParseTypeName(SourceRange *Range) {
/// attributes are very simple in practice. Until we find a bug, I don't see
/// a pressing need to implement the 2 token lookahead.
-AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
- assert(Tok.is(tok::kw___attribute) && "Not an attribute list!");
+AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) {
+ assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!");
AttributeList *CurrAttr = 0;
@@ -121,7 +122,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
if (Tok.is(tok::r_paren)) {
// __attribute__(( mode(byte) ))
ConsumeParen(); // ignore the right paren loc for now
- CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc,
ParmName, ParmLoc, 0, 0, CurrAttr);
} else if (Tok.is(tok::comma)) {
ConsumeToken();
@@ -145,8 +146,10 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
}
if (ArgExprsOk && Tok.is(tok::r_paren)) {
ConsumeParen(); // ignore the right paren loc for now
- CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName,
- ParmLoc, ArgExprs.take(), ArgExprs.size(), CurrAttr);
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
+ AttrNameLoc, ParmName, ParmLoc,
+ ArgExprs.take(), ArgExprs.size(),
+ CurrAttr);
}
}
} else { // not an identifier
@@ -155,7 +158,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
// parse a possibly empty comma separated list of expressions
// __attribute__(( nonnull() ))
ConsumeParen(); // ignore the right paren loc for now
- CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc,
0, SourceLocation(), 0, 0, CurrAttr);
break;
case tok::kw_char:
@@ -175,7 +178,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
// If it's a builtin type name, eat it and expect a rparen
// __attribute__(( vec_type_hint(char) ))
ConsumeToken();
- CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc,
0, SourceLocation(), 0, 0, CurrAttr);
if (Tok.is(tok::r_paren))
ConsumeParen();
@@ -203,20 +206,21 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
if (ArgExprsOk && Tok.is(tok::r_paren)) {
ConsumeParen(); // ignore the right paren loc for now
CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
- SourceLocation(), ArgExprs.take(), ArgExprs.size(),
+ AttrNameLoc, 0, SourceLocation(), ArgExprs.take(),
+ ArgExprs.size(),
CurrAttr);
}
break;
}
}
} else {
- CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc,
0, SourceLocation(), 0, 0, CurrAttr);
}
}
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
SkipUntil(tok::r_paren, false);
- SourceLocation Loc = Tok.getLocation();;
+ SourceLocation Loc = Tok.getLocation();
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
SkipUntil(tok::r_paren, false);
}
@@ -254,15 +258,15 @@ AttributeList* Parser::ParseMicrosoftDeclSpec(AttributeList *CurrAttr) {
OwningExprResult ArgExpr(ParseAssignmentExpression());
if (!ArgExpr.isInvalid()) {
ExprTy* ExprList = ArgExpr.take();
- CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
SourceLocation(), &ExprList, 1,
CurrAttr, true);
}
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
SkipUntil(tok::r_paren, false);
} else {
- CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, SourceLocation(),
- 0, 0, CurrAttr, true);
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc,
+ 0, SourceLocation(), 0, 0, CurrAttr, true);
}
}
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
@@ -281,7 +285,7 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) {
if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64))
// FIXME: Support these properly!
continue;
- CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
SourceLocation(), 0, 0, CurrAttr, true);
}
return CurrAttr;
@@ -304,26 +308,36 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) {
/// others... [FIXME]
///
Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
- SourceLocation &DeclEnd) {
+ SourceLocation &DeclEnd,
+ CXX0XAttributeList Attr) {
DeclPtrTy SingleDecl;
switch (Tok.getKind()) {
case tok::kw_template:
case tok::kw_export:
+ if (Attr.HasAttr)
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd);
break;
case tok::kw_namespace:
+ if (Attr.HasAttr)
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
SingleDecl = ParseNamespace(Context, DeclEnd);
break;
case tok::kw_using:
- SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd);
+ SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd, Attr);
break;
case tok::kw_static_assert:
+ if (Attr.HasAttr)
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
break;
default:
- return ParseSimpleDeclaration(Context, DeclEnd);
+ return ParseSimpleDeclaration(Context, DeclEnd, Attr.AttrList);
}
-
+
// This routine returns a DeclGroup, if the thing we parsed only contains a
// single decl, convert it now.
return Actions.ConvertDeclToDeclGroup(SingleDecl);
@@ -337,9 +351,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
/// If RequireSemi is false, this does not check for a ';' at the end of the
/// declaration.
Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
- SourceLocation &DeclEnd) {
+ SourceLocation &DeclEnd,
+ AttributeList *Attr) {
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this);
+ if (Attr)
+ DS.AddAttributes(Attr);
ParseDeclarationSpecifiers(DS);
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
@@ -422,7 +439,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// short x, __attribute__((common)) var; -> declarator
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
D.AddAttributes(AttrList, Loc);
}
@@ -491,7 +508,7 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D,
// If attributes are present, parse them.
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
D.AddAttributes(AttrList, Loc);
}
@@ -988,7 +1005,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// GNU attributes support.
case tok::kw___attribute:
- DS.AddAttributes(ParseAttributes());
+ DS.AddAttributes(ParseGNUAttributes());
continue;
// Microsoft declspec support.
@@ -1522,7 +1539,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) {
// Attributes are only allowed here on successive declarators.
if (!FirstDeclarator && Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
DeclaratorInfo.D.AddAttributes(AttrList, Loc);
}
@@ -1543,7 +1560,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) {
// If attributes exist after the declarator, parse them.
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
DeclaratorInfo.D.AddAttributes(AttrList, Loc);
}
@@ -1667,7 +1684,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
AttributeList *AttrList = 0;
// If attributes exist after struct contents, parse them.
if (Tok.is(tok::kw___attribute))
- AttrList = ParseAttributes();
+ AttrList = ParseGNUAttributes();
Actions.ActOnFields(CurScope,
RecordLoc, TagDecl, FieldDecls.data(), FieldDecls.size(),
@@ -1702,7 +1719,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
AttributeList *Attr = 0;
// If attributes exist after tag, parse them.
if (Tok.is(tok::kw___attribute))
- Attr = ParseAttributes();
+ Attr = ParseGNUAttributes();
CXXScopeSpec SS;
if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, 0, false)) {
@@ -1833,7 +1850,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) {
AttributeList *Attr = 0;
// If attributes exist after the identifier list, parse them.
if (Tok.is(tok::kw___attribute))
- Attr = ParseAttributes();
+ Attr = ParseGNUAttributes(); // FIXME: where do they do?
Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl,
EnumConstantDecls.data(), EnumConstantDecls.size(),
@@ -2049,8 +2066,20 @@ bool Parser::isDeclarationSpecifier() {
/// [GNU] attributes [ only if AttributesAllowed=true ]
/// type-qualifier-list type-qualifier
/// [GNU] type-qualifier-list attributes [ only if AttributesAllowed=true ]
+/// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq
+/// if CXX0XAttributesAllowed = true
///
-void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) {
+void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed,
+ bool CXX0XAttributesAllowed) {
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+ SourceLocation Loc = Tok.getLocation();
+ CXX0XAttributeList Attr = ParseCXX0XAttributes();
+ if (CXX0XAttributesAllowed)
+ DS.AddAttributes(Attr.AttrList);
+ else
+ Diag(Loc, diag::err_attributes_not_allowed);
+ }
+
while (1) {
bool isInvalid = false;
const char *PrevSpec = 0;
@@ -2075,14 +2104,14 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) {
case tok::kw___cdecl:
case tok::kw___stdcall:
case tok::kw___fastcall:
- if (AttributesAllowed) {
+ if (GNUAttributesAllowed) {
DS.AddAttributes(ParseMicrosoftTypeAttributes());
continue;
}
goto DoneWithTypeQuals;
case tok::kw___attribute:
- if (AttributesAllowed) {
- DS.AddAttributes(ParseAttributes());
+ if (GNUAttributesAllowed) {
+ DS.AddAttributes(ParseGNUAttributes());
continue; // do *not* consume the next token!
}
// otherwise, FALL THROUGH!
@@ -2221,7 +2250,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
//
// [GNU] Retricted references are allowed.
// [GNU] Attributes on references are allowed.
- ParseTypeQualifierListOpt(DS);
+ // [C++0x] Attributes on references are not allowed.
+ ParseTypeQualifierListOpt(DS, true, false);
D.ExtendWithDeclSpec(DS);
if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) {
@@ -2362,6 +2392,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
assert(D.isPastIdentifier() &&
"Haven't past the location of the identifier yet?");
+ // Don't parse attributes unless we have an identifier.
+ if (D.getIdentifier() && getLang().CPlusPlus
+ && isCXX0XAttributeSpecifier(true)) {
+ SourceLocation AttrEndLoc;
+ CXX0XAttributeList Attr = ParseCXX0XAttributes();
+ D.AddAttributes(Attr.AttrList, AttrEndLoc);
+ }
+
while (1) {
if (Tok.is(tok::l_paren)) {
// The paren may be part of a C++ direct initializer, eg. "int x(1);".
@@ -2413,7 +2451,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
AttributeList *AttrList = 0;
bool RequiresArg = false;
if (Tok.is(tok::kw___attribute)) {
- AttrList = ParseAttributes();
+ AttrList = ParseGNUAttributes();
// We require that the argument list (if this is a non-grouping paren) be
// present even if the attribute list was empty.
@@ -2618,7 +2656,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// Parse GNU attributes, if present.
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
ParmDecl.AddAttributes(AttrList, Loc);
}
@@ -2722,6 +2760,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
bool hasAnyExceptionSpec = false;
llvm::SmallVector<TypeTy*, 2> Exceptions;
llvm::SmallVector<SourceRange, 2> ExceptionRanges;
+
if (getLang().CPlusPlus) {
// Parse cv-qualifier-seq[opt].
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
@@ -2842,6 +2881,12 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
// This code does a fast path to handle some of the most obvious cases.
if (Tok.getKind() == tok::r_square) {
SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+ //FIXME: Use these
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier(true)) {
+ Attr = ParseCXX0XAttributes();
+ }
+
// Remember that we parsed the empty array type.
OwningExprResult NumElements(Actions);
D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0,
@@ -2855,6 +2900,11 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
ConsumeToken();
SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+ //FIXME: Use these
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+ Attr = ParseCXX0XAttributes();
+ }
// If there was an error parsing the assignment-expression, recover.
if (ExprRes.isInvalid())
@@ -2922,6 +2972,12 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+ //FIXME: Use these
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+ Attr = ParseCXX0XAttributes();
+ }
+
// Remember that we parsed a array type, and remember its features.
D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(),
StaticLoc.isValid(), isStar,
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 914bfc9..505a4d8 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -69,7 +69,7 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
attrTok = Tok;
// FIXME: save these somewhere.
- AttrList = ParseAttributes();
+ AttrList = ParseGNUAttributes();
}
if (Tok.is(tok::equal)) {
@@ -97,8 +97,12 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
PP.getSourceManager(),
"parsing namespace");
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof))
- ParseExternalDeclaration();
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+ Attr = ParseCXX0XAttributes();
+ ParseExternalDeclaration(Attr);
+ }
// Leave the namespace scope.
NamespaceScope.Exit();
@@ -175,15 +179,27 @@ Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) {
Tok.is(tok::l_brace)? Tok.getLocation()
: SourceLocation());
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+ Attr = ParseCXX0XAttributes();
+ }
+
if (Tok.isNot(tok::l_brace)) {
- ParseDeclarationOrFunctionDefinition();
+ ParseDeclarationOrFunctionDefinition(Attr.AttrList);
return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec,
SourceLocation());
}
+ if (Attr.HasAttr)
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
+
SourceLocation LBrace = ConsumeBrace();
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
- ParseExternalDeclaration();
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+ Attr = ParseCXX0XAttributes();
+ ParseExternalDeclaration(Attr);
}
SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace);
@@ -193,7 +209,8 @@ Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) {
/// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or
/// using-directive. Assumes that current token is 'using'.
Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
- SourceLocation &DeclEnd) {
+ SourceLocation &DeclEnd,
+ CXX0XAttributeList Attr) {
assert(Tok.is(tok::kw_using) && "Not using token");
// Eat 'using'.
@@ -206,9 +223,14 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
if (Tok.is(tok::kw_namespace))
// Next token after 'using' is 'namespace' so it must be using-directive
- return ParseUsingDirective(Context, UsingLoc, DeclEnd);
+ return ParseUsingDirective(Context, UsingLoc, DeclEnd, Attr.AttrList);
+
+ if (Attr.HasAttr)
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
// Otherwise, it must be using-declaration.
+ // Ignore illegal attributes (the caller should already have issued an error.
return ParseUsingDeclaration(Context, UsingLoc, DeclEnd);
}
@@ -224,7 +246,8 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
///
Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
SourceLocation UsingLoc,
- SourceLocation &DeclEnd) {
+ SourceLocation &DeclEnd,
+ AttributeList *Attr) {
assert(Tok.is(tok::kw_namespace) && "Not 'namespace' token");
// Eat 'namespace'.
@@ -239,7 +262,6 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
// Parse (optional) nested-name-specifier.
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
- AttributeList *AttrList = 0;
IdentifierInfo *NamespcName = 0;
SourceLocation IdentLoc = SourceLocation();
@@ -257,17 +279,20 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
IdentLoc = ConsumeToken();
// Parse (optional) attributes (most likely GNU strong-using extension).
- if (Tok.is(tok::kw___attribute))
- AttrList = ParseAttributes();
+ bool GNUAttr = false;
+ if (Tok.is(tok::kw___attribute)) {
+ GNUAttr = true;
+ Attr = addAttributeLists(Attr, ParseGNUAttributes());
+ }
// Eat ';'.
DeclEnd = Tok.getLocation();
ExpectAndConsume(tok::semi,
- AttrList ? diag::err_expected_semi_after_attribute_list :
+ GNUAttr ? diag::err_expected_semi_after_attribute_list :
diag::err_expected_semi_after_namespace_name, "", tok::semi);
return Actions.ActOnUsingDirective(CurScope, UsingLoc, NamespcLoc, SS,
- IdentLoc, NamespcName, AttrList);
+ IdentLoc, NamespcName, Attr);
}
/// ParseUsingDeclaration - Parse C++ using-declaration. Assumes that
@@ -323,7 +348,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
// Parse (optional) attributes (most likely GNU strong-using extension).
if (Tok.is(tok::kw___attribute))
- AttrList = ParseAttributes();
+ AttrList = ParseGNUAttributes();
// Eat ';'.
DeclEnd = Tok.getLocation();
@@ -538,14 +563,20 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
ConsumeToken();
}
- AttributeList *Attr = 0;
+ AttributeList *AttrList = 0;
// If attributes exist after tag, parse them.
if (Tok.is(tok::kw___attribute))
- Attr = ParseAttributes();
+ AttrList = ParseGNUAttributes();
// If declspecs exist after tag, parse them.
if (Tok.is(tok::kw___declspec))
- Attr = ParseMicrosoftDeclSpec(Attr);
+ AttrList = ParseMicrosoftDeclSpec(AttrList);
+
+ // If C++0x attributes exist here, parse them.
+ // FIXME: Are we consistent with the ordering of parsing of different
+ // styles of attributes?
+ if (isCXX0XAttributeSpecifier())
+ AttrList = addAttributeLists(AttrList, ParseCXX0XAttributes().AttrList);
if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_pod)) {
// GNU libstdc++ 4.2 uses __is_pod as the name of a struct template, but
@@ -683,7 +714,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
Diag(StartLoc, diag::err_anon_type_definition)
<< DeclSpec::getSpecifierName(TagType);
- // Skip the rest of this declarator, up until the comma or semicolon.
SkipUntil(tok::comma, true);
if (TemplateId)
@@ -720,7 +750,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->RAngleLoc,
- Attr);
+ AttrList);
} else if (TUK == Action::TUK_Reference) {
TypeResult
= Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
@@ -775,7 +805,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->RAngleLoc,
- Attr,
+ AttrList,
Action::MultiTemplateParamsArg(Actions,
TemplateParams? &(*TemplateParams)[0] : 0,
TemplateParams? TemplateParams->size() : 0));
@@ -793,7 +823,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateInfo.ExternLoc,
TemplateInfo.TemplateLoc,
TagType, StartLoc, SS, Name,
- NameLoc, Attr);
+ NameLoc, AttrList);
} else {
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
TUK == Action::TUK_Definition) {
@@ -804,7 +834,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Declaration or definition of a class type
TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TUK, StartLoc, SS,
- Name, NameLoc, Attr, AS,
+ Name, NameLoc, AttrList, AS,
Action::MultiTemplateParamsArg(Actions,
TemplateParams? &(*TemplateParams)[0] : 0,
TemplateParams? TemplateParams->size() : 0),
@@ -1055,8 +1085,18 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return ParseCXXClassMemberDeclaration(AS, TemplateInfo);
}
+ CXX0XAttributeList AttrList;
+ // Optional C++0x attribute-specifier
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+ AttrList = ParseCXX0XAttributes();
+ }
+
if (Tok.is(tok::kw_using)) {
// FIXME: Check for template aliases
+
+ if (AttrList.HasAttr)
+ Diag(AttrList.Range.getBegin(), diag::err_attributes_not_allowed)
+ << AttrList.Range;
// Eat 'using'.
SourceLocation UsingLoc = ConsumeToken();
@@ -1077,6 +1117,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// decl-specifier-seq:
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this);
+ DS.AddAttributes(AttrList.AttrList);
ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class);
Action::MultiTemplateParamsArg TemplateParams(Actions,
@@ -1103,6 +1144,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return;
}
+ // If attributes exist after the declarator, but before an '{', parse them.
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
+ DeclaratorInfo.AddAttributes(AttrList, Loc);
+ }
+
// function-definition:
if (Tok.is(tok::l_brace)
|| (DeclaratorInfo.isFunctionDeclarator() &&
@@ -1139,7 +1187,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
bool Deleted = false;
while (1) {
-
// member-declarator:
// declarator pure-specifier[opt]
// declarator constant-initializer[opt]
@@ -1177,7 +1224,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// If attributes exist after the declarator, parse them.
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
DeclaratorInfo.AddAttributes(AttrList, Loc);
}
@@ -1197,6 +1244,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
move(TemplateParams),
BitfieldSize.release(),
Init.release(),
+ /*IsDefinition*/Deleted,
Deleted);
}
if (ThisDecl)
@@ -1227,7 +1275,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// Attributes are only allowed on the second declarator.
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
DeclaratorInfo.AddAttributes(AttrList, Loc);
}
@@ -1326,7 +1374,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
AttributeList *AttrList = 0;
// If attributes exist after class contents, parse them.
if (Tok.is(tok::kw___attribute))
- AttrList = ParseAttributes(); // FIXME: where should I put them?
+ AttrList = ParseGNUAttributes(); // FIXME: where should I put them?
Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl,
LBraceLoc, RBraceLoc);
@@ -1573,3 +1621,173 @@ void Parser::PopParsingClass() {
ClassStack.top()->NestedClasses.push_back(Victim);
Victim->TemplateScope = CurScope->getParent()->isTemplateParamScope();
}
+
+/// ParseCXX0XAttributes - Parse a C++0x attribute-specifier. Currently only
+/// parses standard attributes.
+///
+/// [C++0x] attribute-specifier:
+/// '[' '[' attribute-list ']' ']'
+///
+/// [C++0x] attribute-list:
+/// attribute[opt]
+/// attribute-list ',' attribute[opt]
+///
+/// [C++0x] attribute:
+/// attribute-token attribute-argument-clause[opt]
+///
+/// [C++0x] attribute-token:
+/// identifier
+/// attribute-scoped-token
+///
+/// [C++0x] attribute-scoped-token:
+/// attribute-namespace '::' identifier
+///
+/// [C++0x] attribute-namespace:
+/// identifier
+///
+/// [C++0x] attribute-argument-clause:
+/// '(' balanced-token-seq ')'
+///
+/// [C++0x] balanced-token-seq:
+/// balanced-token
+/// balanced-token-seq balanced-token
+///
+/// [C++0x] balanced-token:
+/// '(' balanced-token-seq ')'
+/// '[' balanced-token-seq ']'
+/// '{' balanced-token-seq '}'
+/// any token but '(', ')', '[', ']', '{', or '}'
+CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) {
+ assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)
+ && "Not a C++0x attribute list");
+
+ SourceLocation StartLoc = Tok.getLocation(), Loc;
+ AttributeList *CurrAttr = 0;
+
+ ConsumeBracket();
+ ConsumeBracket();
+
+ if (Tok.is(tok::comma)) {
+ Diag(Tok.getLocation(), diag::err_expected_ident);
+ ConsumeToken();
+ }
+
+ while (Tok.is(tok::identifier) || Tok.is(tok::comma)) {
+ // attribute not present
+ if (Tok.is(tok::comma)) {
+ ConsumeToken();
+ continue;
+ }
+
+ IdentifierInfo *ScopeName = 0, *AttrName = Tok.getIdentifierInfo();
+ SourceLocation ScopeLoc, AttrLoc = ConsumeToken();
+
+ // scoped attribute
+ if (Tok.is(tok::coloncolon)) {
+ ConsumeToken();
+
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_expected_ident);
+ SkipUntil(tok::r_square, tok::comma, true, true);
+ continue;
+ }
+
+ ScopeName = AttrName;
+ ScopeLoc = AttrLoc;
+
+ AttrName = Tok.getIdentifierInfo();
+ AttrLoc = ConsumeToken();
+ }
+
+ bool AttrParsed = false;
+ // No scoped names are supported; ideally we could put all non-standard
+ // attributes into namespaces.
+ if (!ScopeName) {
+ switch(AttributeList::getKind(AttrName))
+ {
+ // No arguments
+ case AttributeList::AT_base_check:
+ case AttributeList::AT_carries_dependency:
+ case AttributeList::AT_final:
+ case AttributeList::AT_hiding:
+ case AttributeList::AT_noreturn:
+ case AttributeList::AT_override: {
+ if (Tok.is(tok::l_paren)) {
+ Diag(Tok.getLocation(), diag::err_cxx0x_attribute_forbids_arguments)
+ << AttrName->getName();
+ break;
+ }
+
+ CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc, 0,
+ SourceLocation(), 0, 0, CurrAttr, false,
+ true);
+ AttrParsed = true;
+ break;
+ }
+
+ // One argument; must be a type-id or assignment-expression
+ case AttributeList::AT_aligned: {
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok.getLocation(), diag::err_cxx0x_attribute_requires_arguments)
+ << AttrName->getName();
+ break;
+ }
+ SourceLocation ParamLoc = ConsumeParen();
+
+ OwningExprResult ArgExpr = ParseCXX0XAlignArgument(ParamLoc);
+
+ MatchRHSPunctuation(tok::r_paren, ParamLoc);
+
+ ExprVector ArgExprs(Actions);
+ ArgExprs.push_back(ArgExpr.release());
+ CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc,
+ 0, ParamLoc, ArgExprs.take(), 1, CurrAttr,
+ false, true);
+
+ AttrParsed = true;
+ break;
+ }
+
+ // Silence warnings
+ default: break;
+ }
+ }
+
+ // Skip the entire parameter clause, if any
+ if (!AttrParsed && Tok.is(tok::l_paren)) {
+ ConsumeParen();
+ // SkipUntil maintains the balancedness of tokens.
+ SkipUntil(tok::r_paren, false);
+ }
+ }
+
+ if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
+ SkipUntil(tok::r_square, false);
+ Loc = Tok.getLocation();
+ if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
+ SkipUntil(tok::r_square, false);
+
+ CXX0XAttributeList Attr (CurrAttr, SourceRange(StartLoc, Loc), true);
+ return Attr;
+}
+
+/// ParseCXX0XAlignArgument - Parse the argument to C++0x's [[align]]
+/// attribute.
+///
+/// FIXME: Simply returns an alignof() expression if the argument is a
+/// type. Ideally, the type should be propagated directly into Sema.
+///
+/// [C++0x] 'align' '(' type-id ')'
+/// [C++0x] 'align' '(' assignment-expression ')'
+Parser::OwningExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) {
+ if (isTypeIdInParens()) {
+ EnterExpressionEvaluationContext Unevaluated(Actions,
+ Action::Unevaluated);
+ SourceLocation TypeLoc = Tok.getLocation();
+ TypeTy *Ty = ParseTypeName().get();
+ SourceRange TypeRange(Start, Tok.getLocation());
+ return Actions.ActOnSizeOfAlignOfExpr(TypeLoc, false, true, Ty,
+ TypeRange);
+ } else
+ return ParseConstantExpression();
+}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index d2b3b84..f780cf1 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -413,12 +413,12 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
///
Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
- bool parseParenAsExprList){
+ TypeTy *TypeOfCast) {
bool NotCastExpr;
OwningExprResult Res = ParseCastExpression(isUnaryExpression,
isAddressOfOperand,
NotCastExpr,
- parseParenAsExprList);
+ TypeOfCast);
if (NotCastExpr)
Diag(Tok, diag::err_expected_expression);
return move(Res);
@@ -538,7 +538,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
bool &NotCastExpr,
- bool parseParenAsExprList){
+ TypeTy *TypeOfCast) {
OwningExprResult Res(Actions);
tok::TokenKind SavedKind = Tok.getKind();
NotCastExpr = false;
@@ -563,7 +563,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
SourceLocation LParenLoc = Tok.getLocation();
SourceLocation RParenLoc;
Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
- parseParenAsExprList, CastTy, RParenLoc);
+ TypeOfCast, CastTy, RParenLoc);
if (Res.isInvalid()) return move(Res);
switch (ParenExprType) {
@@ -1047,7 +1047,8 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
// operands.
EnterExpressionEvaluationContext Unevaluated(Actions,
Action::Unevaluated);
- Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, false,
+ Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/,
+ 0/*TypeOfCast*/,
CastTy, RParenLoc);
CastRange = SourceRange(LParenLoc, RParenLoc);
@@ -1304,7 +1305,7 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() {
///
Parser::OwningExprResult
Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
- bool parseAsExprList, TypeTy *&CastTy,
+ TypeTy *TypeOfCast, TypeTy *&CastTy,
SourceLocation &RParenLoc) {
assert(Tok.is(tok::l_paren) && "Not a paren expr!");
GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
@@ -1315,7 +1316,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) {
Diag(Tok, diag::ext_gnu_statement_expr);
- OwningStmtResult Stmt(ParseCompoundStatement(true));
+ OwningStmtResult Stmt(ParseCompoundStatement(0, true));
ExprType = CompoundStmt;
// If the substmt parsed correctly, build the AST node.
@@ -1365,7 +1366,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// Parse the cast-expression that follows it next.
// TODO: For cast expression with CastTy.
- Result = ParseCastExpression(false, false, true);
+ Result = ParseCastExpression(false, false, CastTy);
if (!Result.isInvalid())
Result = Actions.ActOnCastExpr(CurScope, OpenLoc, CastTy, RParenLoc,
move(Result));
@@ -1374,15 +1375,15 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
return ExprError();
- } else if (parseAsExprList) {
+ } else if (TypeOfCast) {
// Parse the expression-list.
ExprVector ArgExprs(Actions);
CommaLocsTy CommaLocs;
if (!ParseExpressionList(ArgExprs, CommaLocs)) {
ExprType = SimpleExpr;
- Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
- move_arg(ArgExprs));
+ Result = Actions.ActOnParenOrParenListExpr(OpenLoc, Tok.getLocation(),
+ move_arg(ArgExprs), TypeOfCast);
}
} else {
Result = ParseExpression();
@@ -1503,7 +1504,7 @@ void Parser::ParseBlockId() {
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
DeclaratorInfo.AddAttributes(AttrList, Loc);
}
@@ -1565,7 +1566,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() {
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
ParamInfo.AddAttributes(AttrList, Loc);
}
@@ -1586,7 +1587,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() {
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
ParamInfo.AddAttributes(AttrList, Loc);
}
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index b2ecc9e..52003e6 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -124,7 +124,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
break;
}
- if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId) {
+ if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId &&
+ TemplateName.getKind() != UnqualifiedId::IK_LiteralOperatorId) {
Diag(TemplateName.getSourceRange().getBegin(),
diag::err_id_after_template_in_nested_name_spec)
<< TemplateName.getSourceRange();
@@ -148,7 +149,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
TPA.Commit();
TemplateTy Template
= Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName,
- ObjectType);
+ ObjectType, EnteringContext);
if (!Template)
break;
if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
@@ -326,6 +327,24 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
/*ObjectType=*/0,
Name))
return ExprError();
+
+ // This is only the direct operand of an & operator if it is not
+ // followed by a postfix-expression suffix.
+ if (isAddressOfOperand) {
+ switch (Tok.getKind()) {
+ case tok::l_square:
+ case tok::l_paren:
+ case tok::arrow:
+ case tok::period:
+ case tok::plusplus:
+ case tok::minusminus:
+ isAddressOfOperand = false;
+ break;
+
+ default:
+ break;
+ }
+ }
return Actions.ActOnIdExpression(CurScope, SS, Name, Tok.is(tok::l_paren),
isAddressOfOperand);
@@ -531,7 +550,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
CommaLocs.data(), RParenLoc);
}
-/// ParseCXXCondition - if/switch/while/for condition expression.
+/// ParseCXXCondition - if/switch/while condition expression.
///
/// condition:
/// expression
@@ -539,11 +558,20 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
/// '=' assignment-expression
///
-Parser::OwningExprResult Parser::ParseCXXCondition() {
- if (!isCXXConditionDeclaration())
- return ParseExpression(); // expression
-
- SourceLocation StartLoc = Tok.getLocation();
+/// \param ExprResult if the condition was parsed as an expression, the
+/// parsed expression.
+///
+/// \param DeclResult if the condition was parsed as a declaration, the
+/// parsed declaration.
+///
+/// \returns true if there was a parsing, false otherwise.
+bool Parser::ParseCXXCondition(OwningExprResult &ExprResult,
+ DeclPtrTy &DeclResult) {
+ if (!isCXXConditionDeclaration()) {
+ ExprResult = ParseExpression(); // expression
+ DeclResult = DeclPtrTy();
+ return ExprResult.isInvalid();
+ }
// type-specifier-seq
DeclSpec DS;
@@ -559,7 +587,7 @@ Parser::OwningExprResult Parser::ParseCXXCondition() {
OwningExprResult AsmLabel(ParseSimpleAsm(&Loc));
if (AsmLabel.isInvalid()) {
SkipUntil(tok::semi);
- return ExprError();
+ return true;
}
DeclaratorInfo.setAsmLabel(AsmLabel.release());
DeclaratorInfo.SetRangeEnd(Loc);
@@ -568,21 +596,28 @@ Parser::OwningExprResult Parser::ParseCXXCondition() {
// If attributes are present, parse them.
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
DeclaratorInfo.AddAttributes(AttrList, Loc);
}
+ // Type-check the declaration itself.
+ Action::DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(CurScope,
+ DeclaratorInfo);
+ DeclResult = Dcl.get();
+ ExprResult = ExprError();
+
// '=' assignment-expression
- if (Tok.isNot(tok::equal))
- return ExprError(Diag(Tok, diag::err_expected_equal_after_declarator));
- SourceLocation EqualLoc = ConsumeToken();
- OwningExprResult AssignExpr(ParseAssignmentExpression());
- if (AssignExpr.isInvalid())
- return ExprError();
-
- return Actions.ActOnCXXConditionDeclarationExpr(CurScope, StartLoc,
- DeclaratorInfo,EqualLoc,
- move(AssignExpr));
+ if (Tok.is(tok::equal)) {
+ SourceLocation EqualLoc = ConsumeToken();
+ OwningExprResult AssignExpr(ParseAssignmentExpression());
+ if (!AssignExpr.isInvalid())
+ Actions.AddInitializerToDecl(DeclResult, move(AssignExpr));
+ } else {
+ // FIXME: C++0x allows a braced-init-list
+ Diag(Tok, diag::err_expected_equal_after_declarator);
+ }
+
+ return false;
}
/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
@@ -757,6 +792,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
switch (Id.getKind()) {
case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_OperatorFunctionId:
+ case UnqualifiedId::IK_LiteralOperatorId:
TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, EnteringContext,
Template);
break;
@@ -774,7 +810,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
TemplateName.setIdentifier(Name, NameLoc);
if (ObjectType) {
Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS,
- TemplateName, ObjectType);
+ TemplateName, ObjectType,
+ EnteringContext);
TNK = TNK_Dependent_template_name;
if (!Template.get())
return true;
@@ -813,7 +850,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
return true;
if (Id.getKind() == UnqualifiedId::IK_Identifier ||
- Id.getKind() == UnqualifiedId::IK_OperatorFunctionId) {
+ Id.getKind() == UnqualifiedId::IK_OperatorFunctionId ||
+ Id.getKind() == UnqualifiedId::IK_LiteralOperatorId) {
// Form a parsed representation of the template-id to be stored in the
// UnqualifiedId.
TemplateIdAnnotation *TemplateId
@@ -996,6 +1034,26 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations);
return false;
}
+
+ // Parse a literal-operator-id.
+ //
+ // literal-operator-id: [C++0x 13.5.8]
+ // operator "" identifier
+
+ if (getLang().CPlusPlus0x && Tok.is(tok::string_literal)) {
+ if (Tok.getLength() != 2)
+ Diag(Tok.getLocation(), diag::err_operator_string_not_empty);
+ ConsumeStringToken();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_expected_ident);
+ return true;
+ }
+
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ Result.setLiteralOperatorId(II, KeywordLoc, ConsumeToken());
+ return false;
+ }
// Parse a conversion-function-id.
//
@@ -1010,7 +1068,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// Parse the type-specifier-seq.
DeclSpec DS;
- if (ParseCXXTypeSpecifierSeq(DS))
+ if (ParseCXXTypeSpecifierSeq(DS)) // FIXME: ObjectType?
return true;
// Parse the conversion-declarator, which is merely a sequence of
@@ -1111,12 +1169,13 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result))
return true;
- // If we have an operator-function-id and the next token is a '<', we may
- // have a
+ // If we have an operator-function-id or a literal-operator-id and the next
+ // token is a '<', we may have a
//
// template-id:
// operator-function-id < template-argument-list[opt] >
- if (Result.getKind() == UnqualifiedId::IK_OperatorFunctionId &&
+ if ((Result.getKind() == UnqualifiedId::IK_OperatorFunctionId ||
+ Result.getKind() == UnqualifiedId::IK_LiteralOperatorId) &&
Tok.is(tok::less))
return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(),
EnteringContext, ObjectType,
@@ -1152,7 +1211,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
// Note that this is a destructor name.
Action::TypeTy *Ty = Actions.getTypeName(*ClassName, ClassNameLoc,
- CurScope, &SS);
+ CurScope, &SS, false, ObjectType);
if (!Ty) {
if (ObjectType)
Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 5ba1dd1..295625a 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -282,7 +282,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
// FIXME: as the name implies, this rule allows function definitions.
// We could pass a flag or check for functions during semantic analysis.
- allTUVariables.push_back(ParseDeclarationOrFunctionDefinition());
+ allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(0));
continue;
}
@@ -759,7 +759,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// If attributes exist after the method, parse them.
AttributeList *MethodAttrs = 0;
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
- MethodAttrs = ParseAttributes();
+ MethodAttrs = ParseGNUAttributes();
Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
DeclPtrTy Result
@@ -791,7 +791,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// If attributes exist before the argument name, parse them.
ArgInfo.ArgAttrs = 0;
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
- ArgInfo.ArgAttrs = ParseAttributes();
+ ArgInfo.ArgAttrs = ParseGNUAttributes();
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); // missing argument name.
@@ -835,7 +835,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// If attributes exist after the method, parse them.
AttributeList *MethodAttrs = 0;
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
- MethodAttrs = ParseAttributes();
+ MethodAttrs = ParseGNUAttributes();
if (KeyIdents.size() == 0)
return DeclPtrTy();
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 7637382..c87010e 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -78,6 +78,10 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
const char *SemiError = 0;
OwningStmtResult Res(Actions);
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+ Attr = ParseCXX0XAttributes();
+
// Cases in this switch statement should fall through if the parser expects
// the token to end in a semicolon (in which case SemiError should be set),
// or they directly 'return;' if not.
@@ -98,14 +102,15 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
case tok::identifier:
if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement
// identifier ':' statement
- return ParseLabeledStatement();
+ return ParseLabeledStatement(Attr.AttrList);
}
// PASS THROUGH.
default: {
if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd);
+ DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd,
+ Attr);
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
}
@@ -114,6 +119,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
return StmtError();
}
+ // FIXME: Use the attributes
// expression[opt] ';'
OwningExprResult Expr(ParseExpression());
if (Expr.isInvalid()) {
@@ -129,47 +135,50 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
}
case tok::kw_case: // C99 6.8.1: labeled-statement
- return ParseCaseStatement();
+ return ParseCaseStatement(Attr.AttrList);
case tok::kw_default: // C99 6.8.1: labeled-statement
- return ParseDefaultStatement();
+ return ParseDefaultStatement(Attr.AttrList);
case tok::l_brace: // C99 6.8.2: compound-statement
- return ParseCompoundStatement();
+ return ParseCompoundStatement(Attr.AttrList);
case tok::semi: // C99 6.8.3p3: expression[opt] ';'
return Actions.ActOnNullStmt(ConsumeToken());
case tok::kw_if: // C99 6.8.4.1: if-statement
- return ParseIfStatement();
+ return ParseIfStatement(Attr.AttrList);
case tok::kw_switch: // C99 6.8.4.2: switch-statement
- return ParseSwitchStatement();
+ return ParseSwitchStatement(Attr.AttrList);
case tok::kw_while: // C99 6.8.5.1: while-statement
- return ParseWhileStatement();
+ return ParseWhileStatement(Attr.AttrList);
case tok::kw_do: // C99 6.8.5.2: do-statement
- Res = ParseDoStatement();
+ Res = ParseDoStatement(Attr.AttrList);
SemiError = "do/while";
break;
case tok::kw_for: // C99 6.8.5.3: for-statement
- return ParseForStatement();
+ return ParseForStatement(Attr.AttrList);
case tok::kw_goto: // C99 6.8.6.1: goto-statement
- Res = ParseGotoStatement();
+ Res = ParseGotoStatement(Attr.AttrList);
SemiError = "goto";
break;
case tok::kw_continue: // C99 6.8.6.2: continue-statement
- Res = ParseContinueStatement();
+ Res = ParseContinueStatement(Attr.AttrList);
SemiError = "continue";
break;
case tok::kw_break: // C99 6.8.6.3: break-statement
- Res = ParseBreakStatement();
+ Res = ParseBreakStatement(Attr.AttrList);
SemiError = "break";
break;
case tok::kw_return: // C99 6.8.6.4: return-statement
- Res = ParseReturnStatement();
+ Res = ParseReturnStatement(Attr.AttrList);
SemiError = "return";
break;
case tok::kw_asm: {
+ if (Attr.HasAttr)
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
bool msAsm = false;
Res = ParseAsmStatement(msAsm);
if (msAsm) return move(Res);
@@ -178,7 +187,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
}
case tok::kw_try: // C++ 15: try-block
- return ParseCXXTryBlock();
+ return ParseCXXTryBlock(Attr.AttrList);
}
// If we reached this code, the statement must end in a semicolon.
@@ -202,7 +211,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
/// identifier ':' statement
/// [GNU] identifier ':' attributes[opt] statement
///
-Parser::OwningStmtResult Parser::ParseLabeledStatement() {
+Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) {
assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() &&
"Not an identifier!");
@@ -215,10 +224,8 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement() {
SourceLocation ColonLoc = ConsumeToken();
// Read label attributes, if present.
- Action::AttrTy *AttrList = 0;
if (Tok.is(tok::kw___attribute))
- // TODO: save these somewhere.
- AttrList = ParseAttributes();
+ Attr = addAttributeLists(Attr, ParseGNUAttributes());
OwningStmtResult SubStmt(ParseStatement());
@@ -236,8 +243,9 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement() {
/// 'case' constant-expression ':' statement
/// [GNU] 'case' constant-expression '...' constant-expression ':' statement
///
-Parser::OwningStmtResult Parser::ParseCaseStatement() {
+Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) {
assert(Tok.is(tok::kw_case) && "Not a case stmt!");
+ // FIXME: Use attributes?
// It is very very common for code to contain many case statements recursively
// nested, as in (but usually without indentation):
@@ -354,7 +362,8 @@ Parser::OwningStmtResult Parser::ParseCaseStatement() {
/// 'default' ':' statement
/// Note that this does not parse the 'statement' at the end.
///
-Parser::OwningStmtResult Parser::ParseDefaultStatement() {
+Parser::OwningStmtResult Parser::ParseDefaultStatement(AttributeList *Attr) {
+ //FIXME: Use attributes?
assert(Tok.is(tok::kw_default) && "Not a default stmt!");
SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'.
@@ -408,7 +417,9 @@ Parser::OwningStmtResult Parser::ParseDefaultStatement() {
/// [OMP] barrier-directive
/// [OMP] flush-directive
///
-Parser::OwningStmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
+Parser::OwningStmtResult Parser::ParseCompoundStatement(AttributeList *Attr,
+ bool isStmtExpr) {
+ //FIXME: Use attributes?
assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
// Enter a scope to hold everything within the compound stmt. Compound
@@ -449,6 +460,10 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
while (Tok.is(tok::kw___extension__))
ConsumeToken();
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+ Attr = ParseCXX0XAttributes();
+
// If this is the start of a declaration, parse it as such.
if (isDeclarationStatement()) {
// __extension__ silences extension warnings in the subdeclaration.
@@ -456,7 +471,8 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
ExtensionRAIIObject O(Diags);
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext,DeclEnd);
+ DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext, DeclEnd,
+ Attr);
R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd);
} else {
// Otherwise this was a unary __extension__ marker.
@@ -467,6 +483,7 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
continue;
}
+ // FIXME: Use attributes?
// Eat the semicolon at the end of stmt and convert the expr into a
// statement.
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
@@ -500,22 +517,22 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
/// should try to recover harder. It returns false if the condition is
/// successfully parsed. Note that a successful parse can still have semantic
/// errors in the condition.
-bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp,
- bool OnlyAllowCondition,
- SourceLocation *LParenLocPtr,
- SourceLocation *RParenLocPtr) {
+bool Parser::ParseParenExprOrCondition(OwningExprResult &ExprResult,
+ DeclPtrTy &DeclResult) {
+ bool ParseError = false;
+
SourceLocation LParenLoc = ConsumeParen();
- if (LParenLocPtr) *LParenLocPtr = LParenLoc;
-
- if (getLang().CPlusPlus)
- CondExp = ParseCXXCondition();
- else
- CondExp = ParseExpression();
+ if (getLang().CPlusPlus)
+ ParseError = ParseCXXCondition(ExprResult, DeclResult);
+ else {
+ ExprResult = ParseExpression();
+ DeclResult = DeclPtrTy();
+ }
// If the parser was confused by the condition and we don't have a ')', try to
// recover by skipping ahead to a semi and bailing out. If condexp is
// semantically invalid but we have well formed code, keep going.
- if (CondExp.isInvalid() && Tok.isNot(tok::r_paren)) {
+ if (ExprResult.isInvalid() && !DeclResult.get() && Tok.isNot(tok::r_paren)) {
SkipUntil(tok::semi);
// Skipping may have stopped if it found the containing ')'. If so, we can
// continue parsing the if statement.
@@ -524,8 +541,7 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp,
}
// Otherwise the condition is valid or the rparen is present.
- SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- if (RParenLocPtr) *RParenLocPtr = RPLoc;
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
return false;
}
@@ -537,7 +553,8 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp,
/// [C++] 'if' '(' condition ')' statement
/// [C++] 'if' '(' condition ')' statement 'else' statement
///
-Parser::OwningStmtResult Parser::ParseIfStatement() {
+Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
assert(Tok.is(tok::kw_if) && "Not an if stmt!");
SourceLocation IfLoc = ConsumeToken(); // eat the 'if'.
@@ -565,7 +582,8 @@ Parser::OwningStmtResult Parser::ParseIfStatement() {
// Parse the condition.
OwningExprResult CondExp(Actions);
- if (ParseParenExprOrCondition(CondExp))
+ DeclPtrTy CondVar;
+ if (ParseParenExprOrCondition(CondExp, CondVar))
return StmtError();
FullExprArg FullCondExp(Actions.FullExpr(CondExp));
@@ -632,7 +650,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement() {
// If the condition was invalid, discard the if statement. We could recover
// better by replacing it with a valid expr, but don't do that yet.
- if (CondExp.isInvalid())
+ if (CondExp.isInvalid() && !CondVar.get())
return StmtError();
// If the then or else stmt is invalid and the other is valid (and present),
@@ -651,7 +669,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement() {
if (ElseStmt.isInvalid())
ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc);
- return Actions.ActOnIfStmt(IfLoc, FullCondExp, move(ThenStmt),
+ return Actions.ActOnIfStmt(IfLoc, FullCondExp, CondVar, move(ThenStmt),
ElseLoc, move(ElseStmt));
}
@@ -659,7 +677,8 @@ Parser::OwningStmtResult Parser::ParseIfStatement() {
/// switch-statement:
/// 'switch' '(' expression ')' statement
/// [C++] 'switch' '(' condition ')' statement
-Parser::OwningStmtResult Parser::ParseSwitchStatement() {
+Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
assert(Tok.is(tok::kw_switch) && "Not a switch stmt!");
SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'.
@@ -690,12 +709,13 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement() {
// Parse the condition.
OwningExprResult Cond(Actions);
- if (ParseParenExprOrCondition(Cond))
+ DeclPtrTy CondVar;
+ if (ParseParenExprOrCondition(Cond, CondVar))
return StmtError();
- OwningStmtResult Switch(Actions);
- if (!Cond.isInvalid())
- Switch = Actions.ActOnStartOfSwitchStmt(move(Cond));
+ FullExprArg FullCond(Actions.FullExpr(Cond));
+
+ OwningStmtResult Switch = Actions.ActOnStartOfSwitchStmt(FullCond, CondVar);
// C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do this
@@ -724,7 +744,7 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement() {
SwitchScope.Exit();
- if (Cond.isInvalid())
+ if (Cond.isInvalid() && !CondVar.get())
return StmtError();
return Actions.ActOnFinishSwitchStmt(SwitchLoc, move(Switch), move(Body));
@@ -734,7 +754,8 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement() {
/// while-statement: [C99 6.8.5.1]
/// 'while' '(' expression ')' statement
/// [C++] 'while' '(' condition ')' statement
-Parser::OwningStmtResult Parser::ParseWhileStatement() {
+Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
assert(Tok.is(tok::kw_while) && "Not a while stmt!");
SourceLocation WhileLoc = Tok.getLocation();
ConsumeToken(); // eat the 'while'.
@@ -769,7 +790,8 @@ Parser::OwningStmtResult Parser::ParseWhileStatement() {
// Parse the condition.
OwningExprResult Cond(Actions);
- if (ParseParenExprOrCondition(Cond))
+ DeclPtrTy CondVar;
+ if (ParseParenExprOrCondition(Cond, CondVar))
return StmtError();
FullExprArg FullCond(Actions.FullExpr(Cond));
@@ -795,17 +817,18 @@ Parser::OwningStmtResult Parser::ParseWhileStatement() {
InnerScope.Exit();
WhileScope.Exit();
- if (Cond.isInvalid() || Body.isInvalid())
+ if ((Cond.isInvalid() && !CondVar.get()) || Body.isInvalid())
return StmtError();
- return Actions.ActOnWhileStmt(WhileLoc, FullCond, move(Body));
+ return Actions.ActOnWhileStmt(WhileLoc, FullCond, CondVar, move(Body));
}
/// ParseDoStatement
/// do-statement: [C99 6.8.5.2]
/// 'do' statement 'while' '(' expression ')' ';'
/// Note: this lets the caller parse the end ';'.
-Parser::OwningStmtResult Parser::ParseDoStatement() {
+Parser::OwningStmtResult Parser::ParseDoStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
assert(Tok.is(tok::kw_do) && "Not a do stmt!");
SourceLocation DoLoc = ConsumeToken(); // eat the 'do'.
@@ -854,10 +877,9 @@ Parser::OwningStmtResult Parser::ParseDoStatement() {
}
// Parse the parenthesized condition.
- OwningExprResult Cond(Actions);
- SourceLocation LPLoc, RPLoc;
- ParseParenExprOrCondition(Cond, true, &LPLoc, &RPLoc);
-
+ SourceLocation LPLoc = ConsumeParen();
+ OwningExprResult Cond = ParseExpression();
+ SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LPLoc);
DoScope.Exit();
if (Cond.isInvalid() || Body.isInvalid())
@@ -880,7 +902,8 @@ Parser::OwningStmtResult Parser::ParseDoStatement() {
/// [C++] expression-statement
/// [C++] simple-declaration
///
-Parser::OwningStmtResult Parser::ParseForStatement() {
+Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
assert(Tok.is(tok::kw_for) && "Not a for stmt!");
SourceLocation ForLoc = ConsumeToken(); // eat the 'for'.
@@ -922,7 +945,8 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
bool ForEach = false;
OwningStmtResult FirstPart(Actions);
OwningExprResult SecondPart(Actions), ThirdPart(Actions);
-
+ DeclPtrTy SecondVar;
+
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(CurScope);
ConsumeToken();
@@ -937,13 +961,19 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode?
Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
+ AttributeList *AttrList = 0;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+ AttrList = ParseCXX0XAttributes().AttrList;
+
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd);
+ DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd,
+ AttrList);
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
if (Tok.is(tok::semi)) { // for (int x = 4;
ConsumeToken();
} else if ((ForEach = isTokIdentifier_in())) {
+ Actions.ActOnForEachDeclStmt(DG);
// ObjC: for (id x in expr)
ConsumeToken(); // consume 'in'
SecondPart = ParseExpression();
@@ -974,13 +1004,17 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
if (Tok.is(tok::semi)) { // for (...;;
// no second part.
} else {
- SecondPart =getLang().CPlusPlus ? ParseCXXCondition() : ParseExpression();
+ if (getLang().CPlusPlus)
+ ParseCXXCondition(SecondPart, SecondVar);
+ else
+ SecondPart = ParseExpression();
}
if (Tok.is(tok::semi)) {
ConsumeToken();
} else {
- if (!SecondPart.isInvalid()) Diag(Tok, diag::err_expected_semi_for);
+ if (!SecondPart.isInvalid() || SecondVar.get())
+ Diag(Tok, diag::err_expected_semi_for);
SkipUntil(tok::semi);
}
@@ -1019,8 +1053,9 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
if (!ForEach)
return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart),
- move(SecondPart), move(ThirdPart),
- RParenLoc, move(Body));
+ Actions.FullExpr(SecondPart), SecondVar,
+ Actions.FullExpr(ThirdPart), RParenLoc,
+ move(Body));
return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc,
move(FirstPart),
@@ -1035,7 +1070,8 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
///
/// Note: this lets the caller parse the end ';'.
///
-Parser::OwningStmtResult Parser::ParseGotoStatement() {
+Parser::OwningStmtResult Parser::ParseGotoStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
assert(Tok.is(tok::kw_goto) && "Not a goto stmt!");
SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'.
@@ -1068,7 +1104,8 @@ Parser::OwningStmtResult Parser::ParseGotoStatement() {
///
/// Note: this lets the caller parse the end ';'.
///
-Parser::OwningStmtResult Parser::ParseContinueStatement() {
+Parser::OwningStmtResult Parser::ParseContinueStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'.
return Actions.ActOnContinueStmt(ContinueLoc, CurScope);
}
@@ -1079,7 +1116,8 @@ Parser::OwningStmtResult Parser::ParseContinueStatement() {
///
/// Note: this lets the caller parse the end ';'.
///
-Parser::OwningStmtResult Parser::ParseBreakStatement() {
+Parser::OwningStmtResult Parser::ParseBreakStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'.
return Actions.ActOnBreakStmt(BreakLoc, CurScope);
}
@@ -1087,7 +1125,8 @@ Parser::OwningStmtResult Parser::ParseBreakStatement() {
/// ParseReturnStatement
/// jump-statement:
/// 'return' expression[opt] ';'
-Parser::OwningStmtResult Parser::ParseReturnStatement() {
+Parser::OwningStmtResult Parser::ParseReturnStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
assert(Tok.is(tok::kw_return) && "Not a return stmt!");
SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'.
@@ -1163,7 +1202,7 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) {
}
DeclSpec DS;
SourceLocation Loc = Tok.getLocation();
- ParseTypeQualifierListOpt(DS);
+ ParseTypeQualifierListOpt(DS, true, false);
// GNU asms accept, but warn, about type-qualifiers other than volatile.
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
@@ -1371,7 +1410,8 @@ Parser::DeclPtrTy Parser::ParseFunctionTryBlock(DeclPtrTy Decl) {
/// try-block:
/// 'try' compound-statement handler-seq
///
-Parser::OwningStmtResult Parser::ParseCXXTryBlock() {
+Parser::OwningStmtResult Parser::ParseCXXTryBlock(AttributeList* Attr) {
+ // FIXME: Add attributes?
assert(Tok.is(tok::kw_try) && "Expected 'try'");
SourceLocation TryLoc = ConsumeToken();
@@ -1393,11 +1433,17 @@ Parser::OwningStmtResult Parser::ParseCXXTryBlock() {
Parser::OwningStmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected_lbrace));
- OwningStmtResult TryBlock(ParseCompoundStatement());
+ // FIXME: Possible draft standard bug: attribute-specifier should be allowed?
+ OwningStmtResult TryBlock(ParseCompoundStatement(0));
if (TryBlock.isInvalid())
return move(TryBlock);
StmtVector Handlers(Actions);
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+ CXX0XAttributeList Attr = ParseCXX0XAttributes();
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
+ }
if (Tok.isNot(tok::kw_catch))
return StmtError(Diag(Tok, diag::err_expected_catch));
while (Tok.is(tok::kw_catch)) {
@@ -1457,7 +1503,8 @@ Parser::OwningStmtResult Parser::ParseCXXCatchBlock() {
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected_lbrace));
- OwningStmtResult Block(ParseCompoundStatement());
+ // FIXME: Possible draft standard bug: attribute-specifier should be allowed?
+ OwningStmtResult Block(ParseCompoundStatement(0));
if (Block.isInvalid())
return move(Block);
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 16b1c80..0dbf37c 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -16,7 +16,6 @@
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "clang/Parse/Template.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
/// \brief Parse a template declaration, explicit instantiation, or
@@ -34,7 +33,7 @@ Parser::ParseDeclarationStartingWithTemplate(unsigned Context,
/// \brief RAII class that manages the template parameter depth.
namespace {
- class VISIBILITY_HIDDEN TemplateParameterDepthCounter {
+ class TemplateParameterDepthCounter {
unsigned &Depth;
unsigned AddedLevels;
@@ -192,6 +191,10 @@ Parser::ParseSingleDeclarationAfterTemplate(
// Parse the declaration specifiers.
ParsingDeclSpec DS(*this);
+
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+ DS.AddAttributes(ParseCXX0XAttributes().AttrList);
+
ParseDeclarationSpecifiers(DS, TemplateInfo, AS);
if (Tok.is(tok::semi)) {
@@ -333,6 +336,40 @@ Parser::ParseTemplateParameterList(unsigned Depth,
return true;
}
+/// \brief Determine whether the parser is at the start of a template
+/// type parameter.
+bool Parser::isStartOfTemplateTypeParameter() {
+ if (Tok.is(tok::kw_class))
+ return true;
+
+ if (Tok.isNot(tok::kw_typename))
+ return false;
+
+ // C++ [temp.param]p2:
+ // There is no semantic difference between class and typename in a
+ // template-parameter. typename followed by an unqualified-id
+ // names a template type parameter. typename followed by a
+ // qualified-id denotes the type in a non-type
+ // parameter-declaration.
+ Token Next = NextToken();
+
+ // If we have an identifier, skip over it.
+ if (Next.getKind() == tok::identifier)
+ Next = GetLookAheadToken(2);
+
+ switch (Next.getKind()) {
+ case tok::equal:
+ case tok::comma:
+ case tok::greater:
+ case tok::greatergreater:
+ case tok::ellipsis:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
/// ParseTemplateParameter - Parse a template-parameter (C++ [temp.param]).
///
/// template-parameter: [C++ temp.param]
@@ -348,12 +385,8 @@ Parser::ParseTemplateParameterList(unsigned Depth,
/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression
Parser::DeclPtrTy
Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
- if (Tok.is(tok::kw_class) ||
- (Tok.is(tok::kw_typename) &&
- // FIXME: Next token has not been annotated!
- NextToken().isNot(tok::annot_typename))) {
+ if (isStartOfTemplateTypeParameter())
return ParseTypeParameter(Depth, Position);
- }
if (Tok.is(tok::kw_template))
return ParseTemplateTemplateParameter(Depth, Position);
@@ -851,7 +884,8 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
if (isEndOfTemplateArgument(Tok)) {
TemplateTy Template
= Actions.ActOnDependentTemplateName(TemplateLoc, SS, Name,
- /*ObjectType=*/0);
+ /*ObjectType=*/0,
+ /*EnteringContext=*/false);
if (Template.get())
return ParsedTemplateArgument(SS, Template, Name.StartLocation);
}
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 7ac2977..dabd065 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -55,12 +55,11 @@ bool Parser::isCXXDeclarationStatement() {
// using-declaration
// using-directive
case tok::kw_using:
- return true;
- case tok::kw_static_assert:
// static_assert-declaration
+ case tok::kw_static_assert:
return true;
- default:
// simple-declaration
+ default:
return isCXXSimpleDeclaration();
}
}
@@ -351,6 +350,89 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
return TPR == TPResult::True();
}
+/// isCXX0XAttributeSpecifier - returns true if this is a C++0x
+/// attribute-specifier. By default, unless in Obj-C++, only a cursory check is
+/// performed that will simply return true if a [[ is seen. Currently C++ has no
+/// syntactical ambiguities from this check, but it may inhibit error recovery.
+/// If CheckClosing is true, a check is made for closing ]] brackets.
+///
+/// If given, After is set to the token after the attribute-specifier so that
+/// appropriate parsing decisions can be made; it is left untouched if false is
+/// returned.
+///
+/// FIXME: If an error is in the closing ]] brackets, the program assumes
+/// the absence of an attribute-specifier, which can cause very yucky errors
+/// to occur.
+///
+/// [C++0x] attribute-specifier:
+/// '[' '[' attribute-list ']' ']'
+///
+/// [C++0x] attribute-list:
+/// attribute[opt]
+/// attribute-list ',' attribute[opt]
+///
+/// [C++0x] attribute:
+/// attribute-token attribute-argument-clause[opt]
+///
+/// [C++0x] attribute-token:
+/// identifier
+/// attribute-scoped-token
+///
+/// [C++0x] attribute-scoped-token:
+/// attribute-namespace '::' identifier
+///
+/// [C++0x] attribute-namespace:
+/// identifier
+///
+/// [C++0x] attribute-argument-clause:
+/// '(' balanced-token-seq ')'
+///
+/// [C++0x] balanced-token-seq:
+/// balanced-token
+/// balanced-token-seq balanced-token
+///
+/// [C++0x] balanced-token:
+/// '(' balanced-token-seq ')'
+/// '[' balanced-token-seq ']'
+/// '{' balanced-token-seq '}'
+/// any token but '(', ')', '[', ']', '{', or '}'
+bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing,
+ tok::TokenKind *After) {
+ if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square))
+ return false;
+
+ // No tentative parsing if we don't need to look for ]]
+ if (!CheckClosing && !getLang().ObjC1)
+ return true;
+
+ struct TentativeReverter {
+ TentativeParsingAction PA;
+
+ TentativeReverter (Parser& P)
+ : PA(P)
+ {}
+ ~TentativeReverter () {
+ PA.Revert();
+ }
+ } R(*this);
+
+ // Opening brackets were checked for above.
+ ConsumeBracket();
+ ConsumeBracket();
+
+ // SkipUntil will handle balanced tokens, which are guaranteed in attributes.
+ SkipUntil(tok::r_square, false);
+
+ if (Tok.isNot(tok::r_square))
+ return false;
+ ConsumeBracket();
+
+ if (After)
+ *After = Tok.getKind();
+
+ return true;
+}
+
/// declarator:
/// direct-declarator
/// ptr-operator declarator
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index a915274..e321564 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -355,7 +355,10 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
return true;
}
- Result = ParseExternalDeclaration();
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+ Attr = ParseCXX0XAttributes();
+ Result = ParseExternalDeclaration(Attr);
return false;
}
@@ -396,7 +399,7 @@ void Parser::ParseTranslationUnit() {
/// ';'
///
/// [C++0x/GNU] 'extern' 'template' declaration
-Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
+Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) {
DeclPtrTy SingleDecl;
switch (Tok.getKind()) {
case tok::semi:
@@ -418,9 +421,13 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
// __extension__ silences extension warnings in the subexpression.
ExtensionRAIIObject O(Diags); // Use RAII to do this.
ConsumeToken();
- return ParseExternalDeclaration();
+ return ParseExternalDeclaration(Attr);
}
case tok::kw_asm: {
+ if (Attr.HasAttr)
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
+
OwningExprResult Result(ParseSimpleAsm());
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
@@ -449,7 +456,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
case tok::code_completion:
Actions.CodeCompleteOrdinaryName(CurScope);
ConsumeToken();
- return ParseExternalDeclaration();
+ return ParseExternalDeclaration(Attr);
case tok::kw_using:
case tok::kw_namespace:
case tok::kw_typedef:
@@ -459,7 +466,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
// A function definition cannot start with a these keywords.
{
SourceLocation DeclEnd;
- return ParseDeclaration(Declarator::FileContext, DeclEnd);
+ return ParseDeclaration(Declarator::FileContext, DeclEnd, Attr);
}
case tok::kw_extern:
if (getLang().CPlusPlus && NextToken().is(tok::kw_template)) {
@@ -477,7 +484,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
default:
// We can't tell whether this is a function-definition or declaration yet.
- return ParseDeclarationOrFunctionDefinition();
+ return ParseDeclarationOrFunctionDefinition(Attr.AttrList);
}
// This routine returns a DeclGroup, if the thing we parsed only contains a
@@ -525,9 +532,13 @@ bool Parser::isStartOfFunctionDefinition() {
/// [OMP] threadprivate-directive [TODO]
///
Parser::DeclGroupPtrTy
-Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
+Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr,
+ AccessSpecifier AS) {
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this);
+ if (Attr)
+ DS.AddAttributes(Attr);
+
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
@@ -719,7 +730,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
// If attributes are present, parse them.
if (Tok.is(tok::kw___attribute))
// FIXME: attach attributes too.
- AttrList = ParseAttributes();
+ AttrList = ParseGNUAttributes();
// Ask the actions module to compute the type for this declarator.
Action::DeclPtrTy Param =
diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp
index b4bf419..342b0e6 100644
--- a/lib/Rewrite/HTMLRewrite.cpp
+++ b/lib/Rewrite/HTMLRewrite.cpp
@@ -353,7 +353,8 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
RewriteBuffer &RB = R.getEditBuffer(FID);
const SourceManager &SM = PP.getSourceManager();
- Lexer L(FID, SM, PP.getLangOptions());
+ const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
+ Lexer L(FID, FromFile, SM, PP.getLangOptions());
const char *BufferStart = L.getBufferStart();
// Inform the preprocessor that we want to retain comments as tokens, so we
@@ -444,7 +445,8 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
const SourceManager &SM = PP.getSourceManager();
std::vector<Token> TokenStream;
- Lexer L(FID, SM, PP.getLangOptions());
+ const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
+ Lexer L(FID, FromFile, SM, PP.getLangOptions());
// Lex all the tokens in raw mode, to avoid entering #includes or expanding
// macros.
diff --git a/lib/Rewrite/TokenRewriter.cpp b/lib/Rewrite/TokenRewriter.cpp
index 0effbb1..789d53f 100644
--- a/lib/Rewrite/TokenRewriter.cpp
+++ b/lib/Rewrite/TokenRewriter.cpp
@@ -23,7 +23,8 @@ TokenRewriter::TokenRewriter(FileID FID, SourceManager &SM,
ScratchBuf.reset(new ScratchBuffer(SM));
// Create a lexer to lex all the tokens of the main file in raw mode.
- Lexer RawLex(FID, SM, LangOpts);
+ const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
+ Lexer RawLex(FID, FromFile, SM, LangOpts);
// Return all comments and whitespace as tokens.
RawLex.SetKeepWhitespaceMode(true);
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index a9d8301..91b16d3 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -14,10 +14,10 @@
#include "clang/AST/DeclCXX.h"
#include "clang/Parse/Scope.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang-c/Index.h"
#include "Sema.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstring>
@@ -210,306 +210,111 @@ CodeCompletionString *CodeCompletionString::Clone() const {
return Result;
}
-namespace {
- // Escape a string for XML-like formatting.
- struct EscapedString {
- EscapedString(llvm::StringRef Str) : Str(Str) { }
-
- llvm::StringRef Str;
- };
-
- llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, EscapedString EStr) {
- llvm::StringRef Str = EStr.Str;
- while (!Str.empty()) {
- // Find the next escaped character.
- llvm::StringRef::size_type Pos = Str.find_first_of("<>&\"'");
-
- // Print everything before that escaped character.
- OS << Str.substr(0, Pos);
+static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) {
+ OS.write((const char *)&Value, sizeof(unsigned));
+}
- // If we didn't find any escaped characters, we're done.
- if (Pos == llvm::StringRef::npos)
- break;
-
- // Print the appropriate escape sequence.
- switch (Str[Pos]) {
- case '<': OS << "&lt;"; break;
- case '>': OS << "&gt;"; break;
- case '&': OS << "&amp;"; break;
- case '"': OS << "&quot;"; break;
- case '\'': OS << "&apos;"; break;
- }
-
- // Remove everything up to and including that escaped character.
- Str = Str.substr(Pos + 1);
- }
-
- return OS;
- }
-
- /// \brief Remove XML-like escaping from a string.
- std::string UnescapeString(llvm::StringRef Str) {
- using llvm::StringRef;
-
- std::string Result;
- llvm::raw_string_ostream OS(Result);
-
- while (!Str.empty()) {
- StringRef::size_type Amp = Str.find('&');
- OS << Str.substr(0, Amp);
-
- if (Amp == StringRef::npos)
- break;
-
- StringRef::size_type Semi = Str.substr(Amp).find(';');
- if (Semi == StringRef::npos) {
- // Malformed input; do the best we can.
- OS << '&';
- Str = Str.substr(Amp + 1);
- continue;
- }
-
- char Unescaped = llvm::StringSwitch<char>(Str.substr(Amp + 1, Semi - 1))
- .Case("lt", '<')
- .Case("gt", '>')
- .Case("amp", '&')
- .Case("quot", '"')
- .Case("apos", '\'')
- .Default('\0');
-
- if (Unescaped)
- OS << Unescaped;
- else
- OS << Str.substr(Amp, Semi + 1);
- Str = Str.substr(Amp + Semi + 1);
- }
-
- return OS.str();
- }
+static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
+ unsigned &Value) {
+ if (Memory + sizeof(unsigned) > MemoryEnd)
+ return true;
+
+ memmove(&Value, Memory, sizeof(unsigned));
+ Memory += sizeof(unsigned);
+ return false;
}
void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const {
+ // Write the number of chunks.
+ WriteUnsigned(OS, size());
+
for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
+ WriteUnsigned(OS, C->Kind);
+
switch (C->Kind) {
case CK_TypedText:
- OS << "<typed-text>" << EscapedString(C->Text) << "</>";
- break;
case CK_Text:
- OS << "<text>" << EscapedString(C->Text) << "</>";
- break;
- case CK_Optional:
- OS << "<optional>";
- C->Optional->Serialize(OS);
- OS << "</>";
- break;
case CK_Placeholder:
- OS << "<placeholder>" << EscapedString(C->Text) << "</>";
- break;
case CK_Informative:
- OS << "<informative>" << EscapedString(C->Text) << "</>";
+ case CK_CurrentParameter: {
+ const char *Text = C->Text;
+ unsigned StrLen = strlen(Text);
+ WriteUnsigned(OS, StrLen);
+ OS.write(Text, StrLen);
break;
- case CK_CurrentParameter:
- OS << "<current-parameter>" << EscapedString(C->Text) << "</>";
+ }
+
+ case CK_Optional:
+ C->Optional->Serialize(OS);
break;
+
case CK_LeftParen:
- OS << "<lparen/>";
- break;
case CK_RightParen:
- OS << "<rparen/>";
- break;
case CK_LeftBracket:
- OS << "<lbracket/>";
- break;
case CK_RightBracket:
- OS << "<rbracket/>";
- break;
case CK_LeftBrace:
- OS << "<lbrace/>";
- break;
case CK_RightBrace:
- OS << "<rbrace/>";
- break;
case CK_LeftAngle:
- OS << "<langle/>";
- break;
case CK_RightAngle:
- OS << "<rangle/>";
- break;
case CK_Comma:
- OS << "<comma/>";
break;
- }
+ }
}
}
-/// \brief Parse the next XML-ish tag of the form <blah>.
-///
-/// \param Str the string in which we're looking for the next tag.
-///
-/// \param TagPos if successful, will be set to the start of the tag we found.
-///
-/// \param Standalone will indicate whether this is a "standalone" tag that
-/// has no associated data, e.g., <comma/>.
-///
-/// \param Terminator will indicate whether this is a terminating tag (that is
-/// or starts with '/').
-///
-/// \returns the tag itself, without the angle brackets.
-static llvm::StringRef ParseNextTag(llvm::StringRef Str,
- llvm::StringRef::size_type &StartTag,
- llvm::StringRef::size_type &AfterTag,
- bool &Standalone, bool &Terminator) {
- using llvm::StringRef;
-
- Standalone = false;
- Terminator = false;
- AfterTag = StringRef::npos;
-
- // Find the starting '<'.
- StartTag = Str.find('<');
- if (StartTag == StringRef::npos)
- return llvm::StringRef();
-
- // Find the corresponding '>'.
- llvm::StringRef::size_type EndTag = Str.substr(StartTag).find('>');
- if (EndTag == StringRef::npos)
- return llvm::StringRef();
- AfterTag = StartTag + EndTag + 1;
-
- // Determine whether this is a terminating tag.
- if (Str[StartTag + 1] == '/') {
- Terminator = true;
- Str = Str.substr(1);
- --EndTag;
- }
-
- // Determine whether this is a standalone tag.
- if (!Terminator && Str[StartTag + EndTag - 1] == '/') {
- Standalone = true;
- if (EndTag > 1)
- --EndTag;
- }
-
- return Str.substr(StartTag + 1, EndTag - 1);
-}
+CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str,
+ const char *StrEnd) {
+ if (Str == StrEnd || *Str == 0)
+ return 0;
-CodeCompletionString *CodeCompletionString::Deserialize(llvm::StringRef &Str) {
- using llvm::StringRef;
-
CodeCompletionString *Result = new CodeCompletionString;
-
- do {
- // Parse the next tag.
- StringRef::size_type StartTag, AfterTag;
- bool Standalone, Terminator;
- StringRef Tag = ParseNextTag(Str, StartTag, AfterTag, Standalone,
- Terminator);
-
- if (StartTag == StringRef::npos)
+ unsigned NumBlocks;
+ if (ReadUnsigned(Str, StrEnd, NumBlocks))
+ return Result;
+
+ for (unsigned I = 0; I != NumBlocks; ++I) {
+ if (Str + 1 >= StrEnd)
break;
-
- // Figure out what kind of chunk we have.
- const unsigned UnknownKind = 10000;
- unsigned Kind = llvm::StringSwitch<unsigned>(Tag)
- .Case("typed-text", CK_TypedText)
- .Case("text", CK_Text)
- .Case("optional", CK_Optional)
- .Case("placeholder", CK_Placeholder)
- .Case("informative", CK_Informative)
- .Case("current-parameter", CK_CurrentParameter)
- .Case("lparen", CK_LeftParen)
- .Case("rparen", CK_RightParen)
- .Case("lbracket", CK_LeftBracket)
- .Case("rbracket", CK_RightBracket)
- .Case("lbrace", CK_LeftBrace)
- .Case("rbrace", CK_RightBrace)
- .Case("langle", CK_LeftAngle)
- .Case("rangle", CK_RightAngle)
- .Case("comma", CK_Comma)
- .Default(UnknownKind);
-
- // If we've hit a terminator tag, we're done.
- if (Terminator)
+
+ // Parse the next kind.
+ unsigned KindValue;
+ if (ReadUnsigned(Str, StrEnd, KindValue))
+ return Result;
+
+ switch (ChunkKind Kind = (ChunkKind)KindValue) {
+ case CK_TypedText:
+ case CK_Text:
+ case CK_Placeholder:
+ case CK_Informative:
+ case CK_CurrentParameter: {
+ unsigned StrLen;
+ if (ReadUnsigned(Str, StrEnd, StrLen) || (Str + StrLen > StrEnd))
+ return Result;
+
+ Result->AddChunk(Chunk(Kind, StringRef(Str, StrLen)));
+ Str += StrLen;
break;
-
- // Consume the tag.
- Str = Str.substr(AfterTag);
-
- // Handle standalone tags now, since they don't need to be matched to
- // anything.
- if (Standalone) {
- // Ignore anything we don't know about.
- if (Kind == UnknownKind)
- continue;
-
- switch ((ChunkKind)Kind) {
- case CK_TypedText:
- case CK_Text:
- case CK_Optional:
- case CK_Placeholder:
- case CK_Informative:
- case CK_CurrentParameter:
- // There is no point in creating empty chunks of these kinds.
- break;
-
- case CK_LeftParen:
- case CK_RightParen:
- case CK_LeftBracket:
- case CK_RightBracket:
- case CK_LeftBrace:
- case CK_RightBrace:
- case CK_LeftAngle:
- case CK_RightAngle:
- case CK_Comma:
- Result->AddChunk(Chunk((ChunkKind)Kind));
- break;
- }
-
- continue;
}
-
- if (Kind == CK_Optional) {
- // Deserialize the optional code-completion string.
- std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str));
+
+ case CK_Optional: {
+ std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str, StrEnd));
Result->AddOptionalChunk(Optional);
+ break;
}
-
- StringRef EndTag = ParseNextTag(Str, StartTag, AfterTag, Standalone,
- Terminator);
- if (StartTag == StringRef::npos || !Terminator || Standalone)
- break; // Parsing failed; just give up.
-
- if (EndTag.empty() || Tag == EndTag) {
- // Found the matching end tag. Add this chunk based on the text
- // between the tags, then consume that input.
- StringRef Text = Str.substr(0, StartTag);
- switch ((ChunkKind)Kind) {
- case CK_TypedText:
- case CK_Text:
- case CK_Placeholder:
- case CK_Informative:
- case CK_CurrentParameter:
- case CK_LeftParen:
- case CK_RightParen:
- case CK_LeftBracket:
- case CK_RightBracket:
- case CK_LeftBrace:
- case CK_RightBrace:
- case CK_LeftAngle:
- case CK_RightAngle:
- case CK_Comma:
- Result->AddChunk(Chunk((ChunkKind)Kind, UnescapeString(Text)));
- break;
-
- case CK_Optional:
- // We've already added the optional chunk.
- break;
- }
+
+ case CK_LeftParen:
+ case CK_RightParen:
+ case CK_LeftBracket:
+ case CK_RightBracket:
+ case CK_LeftBrace:
+ case CK_RightBrace:
+ case CK_LeftAngle:
+ case CK_RightAngle:
+ case CK_Comma:
+ Result->AddChunk(Chunk(Kind));
+ break;
}
-
- // Remove this tag.
- Str = Str.substr(AfterTag);
- } while (!Str.empty());
+ };
return Result;
}
@@ -633,62 +438,110 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
unsigned NumResults) {
// Print the results.
for (unsigned I = 0; I != NumResults; ++I) {
- OS << "COMPLETION:" << Results[I].Rank << ":";
+ CXCursorKind Kind = CXCursor_NotImplemented;
+
switch (Results[I].Kind) {
- case Result::RK_Declaration:
- if (RecordDecl *Record = dyn_cast<RecordDecl>(Results[I].Declaration)) {
- if (Record->isStruct())
- OS << "Struct:";
- else if (Record->isUnion())
- OS << "Union:";
- else
- OS << "Class:";
- } else if (ObjCMethodDecl *Method
- = dyn_cast<ObjCMethodDecl>(Results[I].Declaration)) {
- if (Method->isInstanceMethod())
- OS << "ObjCInstanceMethod:";
- else
- OS << "ObjCClassMethod:";
- } else {
- OS << Results[I].Declaration->getDeclKindName() << ":";
- }
- if (CodeCompletionString *CCS
- = Results[I].CreateCodeCompletionString(SemaRef)) {
- CCS->Serialize(OS);
- delete CCS;
- } else {
- OS << "<typed-text>"
- << Results[I].Declaration->getNameAsString()
- << "</>";
- }
+ case Result::RK_Declaration:
+ switch (Results[I].Declaration->getKind()) {
+ case Decl::Record:
+ case Decl::CXXRecord:
+ case Decl::ClassTemplateSpecialization: {
+ RecordDecl *Record = cast<RecordDecl>(Results[I].Declaration);
+ if (Record->isStruct())
+ Kind = CXCursor_StructDecl;
+ else if (Record->isUnion())
+ Kind = CXCursor_UnionDecl;
+ else
+ Kind = CXCursor_ClassDecl;
+ break;
+ }
+
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl *Method = cast<ObjCMethodDecl>(Results[I].Declaration);
+ if (Method->isInstanceMethod())
+ Kind = CXCursor_ObjCInstanceMethodDecl;
+ else
+ Kind = CXCursor_ObjCClassMethodDecl;
+ break;
+ }
- OS << '\n';
+ case Decl::Typedef:
+ Kind = CXCursor_TypedefDecl;
break;
- case Result::RK_Keyword:
- OS << "Keyword:<typed-text>" << Results[I].Keyword << "</>\n";
+ case Decl::Enum:
+ Kind = CXCursor_EnumDecl;
break;
- case Result::RK_Macro: {
- OS << "Macro:";
- if (CodeCompletionString *CCS
- = Results[I].CreateCodeCompletionString(SemaRef)) {
- CCS->Serialize(OS);
- delete CCS;
- } else {
- OS << "<typed-text>" << Results[I].Macro->getName() << "</>";
- }
- OS << '\n';
+ case Decl::Field:
+ Kind = CXCursor_FieldDecl;
+ break;
+
+ case Decl::EnumConstant:
+ Kind = CXCursor_EnumConstantDecl;
+ break;
+
+ case Decl::Function:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ Kind = CXCursor_FunctionDecl;
+ break;
+
+ case Decl::Var:
+ Kind = CXCursor_VarDecl;
+ break;
+
+ case Decl::ParmVar:
+ Kind = CXCursor_ParmDecl;
+ break;
+
+ case Decl::ObjCInterface:
+ Kind = CXCursor_ObjCInterfaceDecl;
+ break;
+
+ case Decl::ObjCCategory:
+ Kind = CXCursor_ObjCCategoryDecl;
+ break;
+
+ case Decl::ObjCProtocol:
+ Kind = CXCursor_ObjCProtocolDecl;
break;
- }
- case Result::RK_Pattern: {
- OS << "Pattern:";
- Results[I].Pattern->Serialize(OS);
- OS << '\n';
+ case Decl::ObjCProperty:
+ Kind = CXCursor_ObjCPropertyDecl;
+ break;
+
+ case Decl::ObjCIvar:
+ Kind = CXCursor_ObjCIvarDecl;
+ break;
+
+ case Decl::ObjCImplementation:
+ Kind = CXCursor_ObjCClassDefn;
+ break;
+
+ case Decl::ObjCCategoryImpl:
+ Kind = CXCursor_ObjCCategoryDefn;
+ break;
+
+ default:
break;
}
+ break;
+
+ case Result::RK_Keyword:
+ case Result::RK_Macro:
+ case Result::RK_Pattern:
+ Kind = CXCursor_NotImplemented;
+ break;
}
+
+ WriteUnsigned(OS, Kind);
+ CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef);
+ assert(CCS && "No code-completion string?");
+ CCS->Serialize(OS);
+ delete CCS;
}
// Once we've printed the code-completion results, suppress remaining
@@ -703,13 +556,12 @@ CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
OverloadCandidate *Candidates,
unsigned NumCandidates) {
for (unsigned I = 0; I != NumCandidates; ++I) {
- if (CodeCompletionString *CCS
- = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) {
- OS << "OVERLOAD:";
- CCS->Serialize(OS);
- OS << '\n';
- delete CCS;
- }
+ WriteUnsigned(OS, CXCursor_NotImplemented);
+ CodeCompletionString *CCS
+ = Candidates[I].CreateSignatureString(CurrentArg, SemaRef);
+ assert(CCS && "No code-completion string?");
+ CCS->Serialize(OS);
+ delete CCS;
}
// Once we've printed the code-completion results, suppress remaining
diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h
index 10cc818..e2134a2 100644
--- a/lib/Sema/Lookup.h
+++ b/lib/Sema/Lookup.h
@@ -208,6 +208,15 @@ public:
return getResultKind() == Found;
}
+ /// Determines if the results are overloaded.
+ bool isOverloadedResult() const {
+ return getResultKind() == FoundOverloaded;
+ }
+
+ bool isUnresolvableResult() const {
+ return getResultKind() == FoundUnresolvedValue;
+ }
+
LookupResultKind getResultKind() const {
sanity();
return ResultKind;
@@ -280,6 +289,12 @@ public:
/// ambiguous and overloaded lookups.
NamedDecl *getAsSingleDecl(ASTContext &Context) const;
+ template <class DeclClass>
+ DeclClass *getAsSingle() const {
+ if (getResultKind() != Found) return 0;
+ return dyn_cast<DeclClass>(getFoundDecl());
+ }
+
/// \brief Fetch the unique decl found by this lookup. Asserts
/// that one was found.
///
@@ -368,14 +383,14 @@ public:
class Filter {
LookupResult &Results;
unsigned I;
- bool ErasedAny;
+ bool Changed;
#ifndef NDEBUG
bool CalledDone;
#endif
friend class LookupResult;
Filter(LookupResult &Results)
- : Results(Results), I(0), ErasedAny(false)
+ : Results(Results), I(0), Changed(false)
#ifndef NDEBUG
, CalledDone(false)
#endif
@@ -402,7 +417,12 @@ public:
void erase() {
Results.Decls[--I] = Results.Decls.back();
Results.Decls.pop_back();
- ErasedAny = true;
+ Changed = true;
+ }
+
+ void replace(NamedDecl *D) {
+ Results.Decls[I-1] = D;
+ Changed = true;
}
void done() {
@@ -411,7 +431,7 @@ public:
CalledDone = true;
#endif
- if (ErasedAny)
+ if (Changed)
Results.resolveKindAfterFilter();
}
};
@@ -438,15 +458,25 @@ private:
void sanity() const {
assert(ResultKind != NotFound || Decls.size() == 0);
assert(ResultKind != Found || Decls.size() == 1);
- assert(ResultKind == NotFound || ResultKind == Found ||
- ResultKind == FoundUnresolvedValue ||
- (ResultKind == Ambiguous && Ambiguity == AmbiguousBaseSubobjects)
- || Decls.size() > 1);
+ assert(ResultKind != FoundOverloaded || Decls.size() > 1 ||
+ (Decls.size() == 1 &&
+ isa<FunctionTemplateDecl>(Decls[0]->getUnderlyingDecl())));
+ assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved());
+ assert(ResultKind != Ambiguous || Decls.size() > 1 ||
+ (Decls.size() == 1 && Ambiguity == AmbiguousBaseSubobjects));
assert((Paths != NULL) == (ResultKind == Ambiguous &&
(Ambiguity == AmbiguousBaseSubobjectTypes ||
Ambiguity == AmbiguousBaseSubobjects)));
}
+ bool sanityCheckUnresolved() const {
+ for (DeclsTy::const_iterator I = Decls.begin(), E = Decls.end();
+ I != E; ++I)
+ if (isa<UnresolvedUsingValueDecl>(*I))
+ return true;
+ return false;
+ }
+
static void deletePaths(CXXBasePaths *);
// Results.
diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp
index 7b223a8..7c7df4b 100644
--- a/lib/Sema/ParseAST.cpp
+++ b/lib/Sema/ParseAST.cpp
@@ -90,8 +90,5 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
Decl::PrintStats();
Stmt::PrintStats();
Consumer->PrintStats();
-
- Decl::CollectingStats(false);
- Stmt::CollectingStats(false);
}
}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index fe2d744..f0812bf 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -299,17 +299,15 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
// Built-in ObjC types may already be set by PCHReader (hence isNull checks).
if (Context.getObjCSelType().isNull()) {
- // Synthesize "typedef struct objc_selector *SEL;"
- RecordDecl *SelTag = CreateStructDecl(Context, "objc_selector");
- PushOnScopeChains(SelTag, TUScope);
-
- QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag));
+ // Create the built-in typedef for 'SEL'.
+ QualType SelT = Context.getPointerType(Context.ObjCBuiltinSelTy);
DeclaratorInfo *SelInfo = Context.getTrivialDeclaratorInfo(SelT);
TypedefDecl *SelTypedef
= TypedefDecl::Create(Context, CurContext, SourceLocation(),
&Context.Idents.get("SEL"), SelInfo);
PushOnScopeChains(SelTypedef, TUScope);
Context.setObjCSelType(Context.getTypeDeclType(SelTypedef));
+ Context.ObjCSelRedefinitionType = Context.getObjCSelType();
}
// Synthesize "@class Protocol;
@@ -354,7 +352,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0),
PreDeclaratorDC(0), CurBlock(0), PackContext(0), ParsingDeclDepth(0),
IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0),
- GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated),
+ GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
NumSFINAEErrors(0), NonInstantiationEntries(0),
CurrentInstantiationScope(0)
@@ -365,6 +363,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
// Tell diagnostics how to render things from the AST library.
PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context);
+
+ ExprEvalContexts.push_back(
+ ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0));
}
/// Retrieves the width and signedness of the given integer type,
@@ -594,7 +595,7 @@ static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) {
/// Implements -Wconversion.
static void CheckImplicitConversion(Sema &S, Expr *E, QualType T) {
// Don't diagnose in unevaluated contexts.
- if (S.ExprEvalContext == Sema::Unevaluated)
+ if (S.ExprEvalContexts.back().Context == Sema::Unevaluated)
return;
// Don't diagnose for value-dependent expressions.
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index ad4c90b..b594ece 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -330,18 +330,49 @@ public:
/// have been declared.
bool GlobalNewDeleteDeclared;
- /// The current expression evaluation context.
- ExpressionEvaluationContext ExprEvalContext;
-
- typedef std::vector<std::pair<SourceLocation, Decl *> >
+ /// \brief The set of declarations that have been referenced within
+ /// a potentially evaluated expression.
+ typedef std::vector<std::pair<SourceLocation, Decl *> >
PotentiallyReferencedDecls;
- /// A stack of declarations, each element of which is a set of declarations
- /// that will be marked as referenced if the corresponding potentially
- /// potentially evaluated expression is potentially evaluated. Each element
- /// in the stack corresponds to a PotentiallyPotentiallyEvaluated expression
- /// evaluation context.
- std::list<PotentiallyReferencedDecls> PotentiallyReferencedDeclStack;
+ /// \brief Data structure used to record current or nested
+ /// expression evaluation contexts.
+ struct ExpressionEvaluationContextRecord {
+ /// \brief The expression evaluation context.
+ ExpressionEvaluationContext Context;
+
+ /// \brief The number of temporaries that were active when we
+ /// entered this expression evaluation context.
+ unsigned NumTemporaries;
+
+ /// \brief The set of declarations referenced within a
+ /// potentially potentially-evaluated context.
+ ///
+ /// When leaving a potentially potentially-evaluated context, each
+ /// of these elements will be as referenced if the corresponding
+ /// potentially potentially evaluated expression is potentially
+ /// evaluated.
+ PotentiallyReferencedDecls *PotentiallyReferenced;
+
+ ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
+ unsigned NumTemporaries)
+ : Context(Context), NumTemporaries(NumTemporaries),
+ PotentiallyReferenced(0) { }
+
+ void addReferencedDecl(SourceLocation Loc, Decl *Decl) {
+ if (!PotentiallyReferenced)
+ PotentiallyReferenced = new PotentiallyReferencedDecls;
+ PotentiallyReferenced->push_back(std::make_pair(Loc, Decl));
+ }
+
+ void Destroy() {
+ delete PotentiallyReferenced;
+ PotentiallyReferenced = 0;
+ }
+ };
+
+ /// A stack of expression evaluation contexts.
+ llvm::SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts;
/// \brief Whether the code handled by Sema should be considered a
/// complete translation unit or not.
@@ -428,13 +459,20 @@ public:
virtual void DeleteExpr(ExprTy *E);
virtual void DeleteStmt(StmtTy *S);
- OwningExprResult Owned(Expr* E) { return OwningExprResult(*this, E); }
+ OwningExprResult Owned(Expr* E) {
+ assert(!E || E->isRetained());
+ return OwningExprResult(*this, E);
+ }
OwningExprResult Owned(ExprResult R) {
if (R.isInvalid())
return ExprError();
+ assert(!R.get() || ((Expr*) R.get())->isRetained());
return OwningExprResult(*this, R.get());
}
- OwningStmtResult Owned(Stmt* S) { return OwningStmtResult(*this, S); }
+ OwningStmtResult Owned(Stmt* S) {
+ assert(!S || S->isRetained());
+ return OwningStmtResult(*this, S);
+ }
virtual void ActOnEndOfTranslationUnit();
@@ -485,7 +523,7 @@ public:
/// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo.
QualType CreateLocInfoType(QualType T, DeclaratorInfo *DInfo);
DeclarationName GetNameForDeclarator(Declarator &D);
- DeclarationName GetNameFromUnqualifiedId(UnqualifiedId &Name);
+ DeclarationName GetNameFromUnqualifiedId(const UnqualifiedId &Name);
static QualType GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo = 0);
bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
bool CheckDistantExceptionSpec(QualType T);
@@ -533,7 +571,8 @@ public:
virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
Scope *S, const CXXScopeSpec *SS,
- bool isClassName = false);
+ bool isClassName = false,
+ TypeTy *ObjectType = 0);
virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S);
virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II,
SourceLocation IILoc,
@@ -893,17 +932,13 @@ public:
bool SuppressUserConversions = false,
bool ForceRValue = false);
void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
- bool HasExplicitTemplateArgs,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr *Object, Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool ForceRValue = false);
void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
- bool HasExplicitTemplateArgs,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
@@ -939,9 +974,7 @@ public:
OverloadCandidateSet& CandidateSet);
void AddArgumentDependentLookupCandidates(DeclarationName Name,
Expr **Args, unsigned NumArgs,
- bool HasExplicitTemplateArgs,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
bool PartialOverloading = false);
bool isBetterOverloadCandidate(const OverloadCandidate& Cand1,
@@ -958,26 +991,23 @@ public:
bool Complain);
Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
- void AddOverloadedCallCandidates(NamedDecl *Callee,
+ void AddOverloadedCallCandidates(llvm::SmallVectorImpl<NamedDecl*>& Callees,
DeclarationName &UnqualifiedName,
- bool &ArgumentDependentLookup,
- bool HasExplicitTemplateArgs,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ bool ArgumentDependentLookup,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading = false);
- FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
+ FunctionDecl *ResolveOverloadedCallFn(Expr *Fn,
+ llvm::SmallVectorImpl<NamedDecl*> &Fns,
DeclarationName UnqualifiedName,
- bool HasExplicitTemplateArgs,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation *CommaLocs,
SourceLocation RParenLoc,
- bool &ArgumentDependentLookup);
+ bool ArgumentDependentLookup);
OwningExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc,
unsigned Opc,
@@ -1260,6 +1290,7 @@ public:
virtual OwningStmtResult ActOnDeclStmt(DeclGroupPtrTy Decl,
SourceLocation StartLoc,
SourceLocation EndLoc);
+ virtual void ActOnForEachDeclStmt(DeclGroupPtrTy Decl);
virtual OwningStmtResult ActOnCaseStmt(SourceLocation CaseLoc, ExprArg LHSVal,
SourceLocation DotDotDotLoc, ExprArg RHSVal,
SourceLocation ColonLoc);
@@ -1273,13 +1304,16 @@ public:
SourceLocation ColonLoc,
StmtArg SubStmt);
virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc,
- FullExprArg CondVal, StmtArg ThenVal,
+ FullExprArg CondVal, DeclPtrTy CondVar,
+ StmtArg ThenVal,
SourceLocation ElseLoc, StmtArg ElseVal);
- virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond);
+ virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond,
+ DeclPtrTy CondVar);
virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
StmtArg Switch, StmtArg Body);
virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
- FullExprArg Cond, StmtArg Body);
+ FullExprArg Cond,
+ DeclPtrTy CondVar, StmtArg Body);
virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
SourceLocation WhileLoc,
SourceLocation CondLParen, ExprArg Cond,
@@ -1287,8 +1321,10 @@ public:
virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc,
SourceLocation LParenLoc,
- StmtArg First, ExprArg Second,
- ExprArg Third, SourceLocation RParenLoc,
+ StmtArg First, FullExprArg Second,
+ DeclPtrTy SecondVar,
+ FullExprArg Third,
+ SourceLocation RParenLoc,
StmtArg Body);
virtual OwningStmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc,
SourceLocation LParenLoc,
@@ -1379,12 +1415,10 @@ public:
const PartialDiagnostic &PD,
bool Equality = false);
- virtual ExpressionEvaluationContext
+ virtual void
PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext);
- virtual void
- PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
- ExpressionEvaluationContext NewContext);
+ virtual void PopExpressionEvaluationContext();
void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
@@ -1396,10 +1430,19 @@ public:
UnqualifiedId &Name,
bool HasTrailingLParen,
bool IsAddressOfOperand);
+
+ OwningExprResult LookupInObjCMethod(LookupResult &R,
+ Scope *S,
+ IdentifierInfo *II);
+
+ OwningExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS,
+ DeclarationName Name,
+ SourceLocation NameLoc,
+ bool CheckForImplicitMember,
+ const TemplateArgumentListInfo *TemplateArgs);
OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty,
- SourceLocation Loc, bool TypeDependent,
- bool ValueDependent,
+ SourceLocation Loc,
const CXXScopeSpec *SS = 0);
VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
llvm::SmallVectorImpl<FieldDecl *> &Path);
@@ -1408,15 +1451,27 @@ public:
FieldDecl *Field,
Expr *BaseObjectExpr = 0,
SourceLocation OpLoc = SourceLocation());
- OwningExprResult ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
- DeclarationName Name,
- bool HasTrailingLParen,
- const CXXScopeSpec *SS,
- bool isAddressOfOperand = false);
- OwningExprResult BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
- bool HasTrailingLParen,
- const CXXScopeSpec *SS,
- bool isAddressOfOperand);
+ OwningExprResult BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs);
+ bool UseArgumentDependentLookup(const CXXScopeSpec &SS,
+ const LookupResult &R,
+ bool HasTrailingLParen);
+
+ OwningExprResult BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS,
+ DeclarationName Name,
+ SourceLocation NameLoc);
+ OwningExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
+ DeclarationName Name,
+ SourceLocation NameLoc,
+ const TemplateArgumentListInfo *TemplateArgs);
+
+ OwningExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ bool ADL);
+ OwningExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS,
+ SourceLocation Loc,
+ NamedDecl *D);
virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc,
tok::TokenKind Kind);
@@ -1424,9 +1479,10 @@ public:
virtual OwningExprResult ActOnCharacterConstant(const Token &);
virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R,
ExprArg Val);
- virtual OwningExprResult ActOnParenListExpr(SourceLocation L,
+ virtual OwningExprResult ActOnParenOrParenListExpr(SourceLocation L,
SourceLocation R,
- MultiExprArg Val);
+ MultiExprArg Val,
+ TypeTy *TypeOfCast=0);
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
/// fragments (e.g. "foo" "bar" L"baz").
@@ -1468,36 +1524,40 @@ public:
ExprArg Idx,
SourceLocation RLoc);
- OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base,
+ OwningExprResult BuildMemberReferenceExpr(ExprArg Base,
SourceLocation OpLoc,
- tok::TokenKind OpKind,
- SourceLocation MemberLoc,
- DeclarationName MemberName,
- DeclPtrTy ImplDecl,
- const CXXScopeSpec *SS = 0,
- NamedDecl *FirstQualifierInScope = 0) {
- // FIXME: Temporary helper while we migrate existing calls to
- // BuildMemberReferenceExpr to support explicitly-specified template
- // arguments.
- return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc,
- MemberName, false, SourceLocation(), 0, 0,
- SourceLocation(), ImplDecl, SS,
- FirstQualifierInScope);
- }
+ bool IsArrow,
+ const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
+ DeclarationName Name,
+ SourceLocation NameLoc,
+ const TemplateArgumentListInfo *TemplateArgs);
- OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base,
+ OwningExprResult BuildMemberReferenceExpr(ExprArg Base,
+ SourceLocation OpLoc, bool IsArrow,
+ const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs);
+
+ OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base,
+ bool IsArrow, SourceLocation OpLoc,
+ const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
+ DeclPtrTy ObjCImpDecl);
+
+ bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ const LookupResult &R);
+
+ OwningExprResult ActOnDependentMemberExpr(ExprArg Base,
+ bool IsArrow,
SourceLocation OpLoc,
- tok::TokenKind OpKind,
- SourceLocation MemberLoc,
- DeclarationName MemberName,
- bool HasExplicitTemplateArgs,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
- SourceLocation RAngleLoc,
- DeclPtrTy ImplDecl,
- const CXXScopeSpec *SS,
- NamedDecl *FirstQualifierInScope = 0);
+ const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
+ DeclarationName Name,
+ SourceLocation NameLoc,
+ const TemplateArgumentListInfo *TemplateArgs);
virtual OwningExprResult ActOnMemberAccessExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
@@ -1515,14 +1575,14 @@ public:
SourceLocation RParenLoc);
void DeconstructCallFunction(Expr *FnExpr,
- NamedDecl *&Function,
+ llvm::SmallVectorImpl<NamedDecl*>& Fns,
DeclarationName &Name,
NestedNameSpecifier *&Qualifier,
SourceRange &QualifierRange,
bool &ArgumentDependentLookup,
- bool &HasExplicitTemplateArguments,
- const TemplateArgumentLoc *&ExplicitTemplateArgs,
- unsigned &NumExplicitTemplateArgs);
+ bool &Overloaded,
+ bool &HasExplicitTemplateArgs,
+ TemplateArgumentListInfo &ExplicitTemplateArgs);
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
/// This provides the location of the left/right parens and a list of comma
@@ -1536,6 +1596,9 @@ public:
virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
TypeTy *Ty, SourceLocation RParenLoc,
ExprArg Op);
+ virtual bool TypeIsVectorType(TypeTy *Ty) {
+ return GetTypeFromParser(Ty)->isVectorType();
+ }
OwningExprResult MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg ME);
OwningExprResult ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
@@ -1868,15 +1931,10 @@ public:
bool UseGlobal, bool ArrayForm,
ExprArg Operand);
- /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
- /// C++ if/switch/while/for statement.
- /// e.g: "if (int x = f()) {...}"
- virtual OwningExprResult ActOnCXXConditionDeclarationExpr(Scope *S,
- SourceLocation StartLoc,
- Declarator &D,
- SourceLocation EqualLoc,
- ExprArg AssignExprVal);
-
+ virtual DeclResult ActOnCXXConditionDeclaration(Scope *S,
+ Declarator &D);
+ OwningExprResult CheckConditionVariable(VarDecl *ConditionVar);
+
/// ActOnUnaryTypeTrait - Parsed one of the unary type trait support
/// pseudo-functions.
virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
@@ -2028,7 +2086,7 @@ public:
Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
ExprTy *BitfieldWidth,
- ExprTy *Init,
+ ExprTy *Init, bool IsDefinition,
bool Deleted = false);
virtual MemInitResult ActOnMemInitializer(DeclPtrTy ConstructorD,
@@ -2093,14 +2151,12 @@ public:
void CheckConstructor(CXXConstructorDecl *Constructor);
QualType CheckDestructorDeclarator(Declarator &D,
FunctionDecl::StorageClass& SC);
- void CheckDestructor(CXXDestructorDecl *Destructor);
+ bool CheckDestructor(CXXDestructorDecl *Destructor);
void CheckConversionDeclarator(Declarator &D, QualType &R,
FunctionDecl::StorageClass& SC);
DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion);
- bool isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D,
- SourceLocation NameLoc, QualType &ThisType,
- QualType &MemberType);
+ bool isImplicitMemberReference(const LookupResult &R, QualType &ThisType);
//===--------------------------------------------------------------------===//
// C++ Derived Classes
@@ -2147,6 +2203,11 @@ public:
bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
const CXXMethodDecl *Old);
+ /// CheckOverridingFunctionAttributes - Checks whether attributes are
+ /// incompatible or prevent overriding.
+ bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old);
+
//===--------------------------------------------------------------------===//
// C++ Access Control
//
@@ -2190,6 +2251,9 @@ public:
//===--------------------------------------------------------------------===//
// C++ Templates [C++ 14]
//
+ void LookupTemplateName(LookupResult &R, Scope *S, const CXXScopeSpec &SS,
+ QualType ObjectType, bool EnteringContext);
+
virtual TemplateNameKind isTemplateName(Scope *S,
const CXXScopeSpec &SS,
UnqualifiedId &Name,
@@ -2235,8 +2299,19 @@ public:
SourceLocation LAngleLoc,
DeclPtrTy *Params, unsigned NumParams,
SourceLocation RAngleLoc);
+
+ /// \brief The context in which we are checking a template parameter
+ /// list.
+ enum TemplateParamListContext {
+ TPC_ClassTemplate,
+ TPC_FunctionTemplate,
+ TPC_ClassTemplateMember,
+ TPC_FriendFunctionTemplate
+ };
+
bool CheckTemplateParameterList(TemplateParameterList *NewParams,
- TemplateParameterList *OldParams);
+ TemplateParameterList *OldParams,
+ TemplateParamListContext TPC);
TemplateParameterList *
MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
const CXXScopeSpec &SS,
@@ -2251,15 +2326,12 @@ public:
TemplateParameterList *TemplateParams,
AccessSpecifier AS);
- void translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
- llvm::SmallVectorImpl<TemplateArgumentLoc> &TempArgs);
+ void translateTemplateArguments(const ASTTemplateArgsPtr &In,
+ TemplateArgumentListInfo &Out);
QualType CheckTemplateIdType(TemplateName Template,
SourceLocation TemplateLoc,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation RAngleLoc);
+ const TemplateArgumentListInfo &TemplateArgs);
virtual TypeResult
ActOnTemplateIdType(TemplateTy Template, SourceLocation TemplateLoc,
@@ -2272,26 +2344,20 @@ public:
DeclSpec::TST TagSpec,
SourceLocation TagLoc);
- OwningExprResult BuildTemplateIdExpr(NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- TemplateName Template,
- SourceLocation TemplateNameLoc,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation RAngleLoc);
-
- OwningExprResult ActOnTemplateIdExpr(const CXXScopeSpec &SS,
- TemplateTy Template,
- SourceLocation TemplateNameLoc,
- SourceLocation LAngleLoc,
- ASTTemplateArgsPtr TemplateArgs,
- SourceLocation RAngleLoc);
+ OwningExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ bool RequiresADL,
+ const TemplateArgumentListInfo &TemplateArgs);
+ OwningExprResult BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS,
+ DeclarationName Name,
+ SourceLocation NameLoc,
+ const TemplateArgumentListInfo &TemplateArgs);
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
const CXXScopeSpec &SS,
UnqualifiedId &Name,
- TypeTy *ObjectType);
+ TypeTy *ObjectType,
+ bool EnteringContext);
bool CheckClassTemplatePartialSpecializationArgs(
TemplateParameterList *TemplateParams,
@@ -2327,11 +2393,7 @@ public:
bool &SuppressNew);
bool CheckFunctionTemplateSpecialization(FunctionDecl *FD,
- bool HasExplicitTemplateArgs,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
- SourceLocation RAngleLoc,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous);
bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous);
@@ -2365,6 +2427,13 @@ public:
SourceLocation TemplateLoc,
Declarator &D);
+ TemplateArgumentLoc
+ SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
+ SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc,
+ Decl *Param,
+ TemplateArgumentListBuilder &Converted);
+
bool CheckTemplateArgument(NamedDecl *Param,
const TemplateArgumentLoc &Arg,
TemplateDecl *Template,
@@ -2374,10 +2443,7 @@ public:
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation RAngleLoc,
+ const TemplateArgumentListInfo &TemplateArgs,
bool PartialTemplateArgs,
TemplateArgumentListBuilder &Converted);
@@ -2603,8 +2669,7 @@ public:
TemplateDeductionResult
SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ const TemplateArgumentListInfo &ExplicitTemplateArgs,
llvm::SmallVectorImpl<TemplateArgument> &Deduced,
llvm::SmallVectorImpl<QualType> &ParamTypes,
QualType *FunctionType,
@@ -2618,18 +2683,14 @@ public:
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- bool HasExplicitTemplateArgs,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info);
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- bool HasExplicitTemplateArgs,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ArgFunctionType,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info);
@@ -3312,9 +3373,20 @@ public:
VariadicFunction,
VariadicBlock,
VariadicMethod,
- VariadicConstructor
+ VariadicConstructor,
+ VariadicDoesNotApply
};
+ /// GatherArgumentsForCall - Collector argument expressions for various
+ /// form of call prototypes.
+ bool GatherArgumentsForCall(SourceLocation CallLoc,
+ FunctionDecl *FDecl,
+ const FunctionProtoType *Proto,
+ unsigned FirstProtoArg,
+ Expr **Args, unsigned NumArgs,
+ llvm::SmallVector<Expr *, 8> &AllArgs,
+ VariadicCallType CallType = VariadicDoesNotApply);
+
// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
// will warn if the resulting type is not a POD type.
bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT);
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 6dbb442..b386adb 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -206,17 +206,6 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier),
CurContext);
- // Handle each declaration in an overload set separately.
- if (OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(R.Declaration)) {
- for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
- FEnd = Ovl->function_end();
- F != FEnd; ++F)
- MaybeAddResult(Result(*F, R.Rank, R.Qualifier), CurContext);
-
- return;
- }
-
Decl *CanonDecl = R.Declaration->getCanonicalDecl();
unsigned IDNS = CanonDecl->getIdentifierNamespace();
@@ -704,7 +693,7 @@ static void AddFunctionParameterChunks(ASTContext &Context,
Context.PrintingPolicy);
// Add the placeholder string.
- CCStr->AddPlaceholderChunk(PlaceholderStr.c_str());
+ CCStr->AddPlaceholderChunk(PlaceholderStr);
}
if (const FunctionProtoType *Proto
@@ -778,7 +767,7 @@ static void AddTemplateParameterChunks(ASTContext &Context,
CCStr->AddChunk(Chunk(CodeCompletionString::CK_Comma));
// Add the placeholder string.
- CCStr->AddPlaceholderChunk(PlaceholderStr.c_str());
+ CCStr->AddPlaceholderChunk(PlaceholderStr);
}
}
@@ -797,9 +786,9 @@ void AddQualifierToCompletionString(CodeCompletionString *Result,
Qualifier->print(OS, Context.PrintingPolicy);
}
if (QualifierIsInformative)
- Result->AddInformativeChunk(PrintedNNS.c_str());
+ Result->AddInformativeChunk(PrintedNNS);
else
- Result->AddTextChunk(PrintedNNS.c_str());
+ Result->AddTextChunk(PrintedNNS);
}
/// \brief If possible, create a new code completion string for the given
@@ -812,17 +801,26 @@ CodeCompletionString *
CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
typedef CodeCompletionString::Chunk Chunk;
- if (Kind == RK_Keyword)
- return 0;
+ if (Kind == RK_Pattern)
+ return Pattern->Clone();
+
+ CodeCompletionString *Result = new CodeCompletionString;
+
+ if (Kind == RK_Keyword) {
+ Result->AddTypedTextChunk(Keyword);
+ return Result;
+ }
if (Kind == RK_Macro) {
MacroInfo *MI = S.PP.getMacroInfo(Macro);
- if (!MI || !MI->isFunctionLike())
- return 0;
+ assert(MI && "Not a macro?");
+
+ Result->AddTypedTextChunk(Macro->getName());
+
+ if (!MI->isFunctionLike())
+ return Result;
// Format a function-like macro with placeholders for the arguments.
- CodeCompletionString *Result = new CodeCompletionString;
- Result->AddTypedTextChunk(Macro->getName().str().c_str());
Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
for (MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end();
A != AEnd; ++A) {
@@ -831,7 +829,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
if (!MI->isVariadic() || A != AEnd - 1) {
// Non-variadic argument.
- Result->AddPlaceholderChunk((*A)->getName().str().c_str());
+ Result->AddPlaceholderChunk((*A)->getName());
continue;
}
@@ -843,7 +841,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
else {
std::string Arg = (*A)->getName();
Arg += "...";
- Result->AddPlaceholderChunk(Arg.c_str());
+ Result->AddPlaceholderChunk(Arg);
}
}
Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen));
@@ -854,17 +852,15 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
NamedDecl *ND = Declaration;
if (StartsNestedNameSpecifier) {
- CodeCompletionString *Result = new CodeCompletionString;
- Result->AddTypedTextChunk(ND->getNameAsString().c_str());
+ Result->AddTypedTextChunk(ND->getNameAsString());
Result->AddTextChunk("::");
return Result;
}
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
- CodeCompletionString *Result = new CodeCompletionString;
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
S.Context);
- Result->AddTypedTextChunk(Function->getNameAsString().c_str());
+ Result->AddTypedTextChunk(Function->getNameAsString());
Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
AddFunctionParameterChunks(S.Context, Function, Result);
Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen));
@@ -872,11 +868,10 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
}
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) {
- CodeCompletionString *Result = new CodeCompletionString;
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
S.Context);
FunctionDecl *Function = FunTmpl->getTemplatedDecl();
- Result->AddTypedTextChunk(Function->getNameAsString().c_str());
+ Result->AddTypedTextChunk(Function->getNameAsString());
// Figure out which template parameters are deduced (or have default
// arguments).
@@ -926,10 +921,9 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
}
if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) {
- CodeCompletionString *Result = new CodeCompletionString;
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
S.Context);
- Result->AddTypedTextChunk(Template->getNameAsString().c_str());
+ Result->AddTypedTextChunk(Template->getNameAsString());
Result->AddChunk(Chunk(CodeCompletionString::CK_LeftAngle));
AddTemplateParameterChunks(S.Context, Template, Result);
Result->AddChunk(Chunk(CodeCompletionString::CK_RightAngle));
@@ -937,7 +931,6 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
}
if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) {
- CodeCompletionString *Result = new CodeCompletionString;
Selector Sel = Method->getSelector();
if (Sel.isUnarySelector()) {
Result->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName());
@@ -993,15 +986,12 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
return Result;
}
- if (Qualifier) {
- CodeCompletionString *Result = new CodeCompletionString;
+ if (Qualifier)
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
S.Context);
- Result->AddTypedTextChunk(ND->getNameAsString().c_str());
- return Result;
- }
-
- return 0;
+
+ Result->AddTypedTextChunk(ND->getNameAsString());
+ return Result;
}
CodeCompletionString *
@@ -1019,7 +1009,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
// highlighted ellipsis.
const FunctionType *FT = getFunctionType();
Result->AddTextChunk(
- FT->getResultType().getAsString(S.Context.PrintingPolicy).c_str());
+ FT->getResultType().getAsString(S.Context.PrintingPolicy));
Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "..."));
Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen));
@@ -1027,10 +1017,10 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
}
if (FDecl)
- Result->AddTextChunk(FDecl->getNameAsString().c_str());
+ Result->AddTextChunk(FDecl->getNameAsString());
else
Result->AddTextChunk(
- Proto->getResultType().getAsString(S.Context.PrintingPolicy).c_str());
+ Proto->getResultType().getAsString(S.Context.PrintingPolicy));
Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
unsigned NumParams = FDecl? FDecl->getNumParams() : Proto->getNumArgs();
@@ -1052,9 +1042,9 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
if (I == CurrentArg)
Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter,
- ArgString.c_str()));
+ ArgString));
else
- Result->AddTextChunk(ArgString.c_str());
+ Result->AddTextChunk(ArgString);
}
if (Proto && Proto->isVariadic()) {
@@ -1467,19 +1457,18 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
Expr::hasAnyTypeDependentArguments(Args, NumArgs))
return;
- NamedDecl *Function;
+ llvm::SmallVector<NamedDecl*,8> Fns;
DeclarationName UnqualifiedName;
NestedNameSpecifier *Qualifier;
SourceRange QualifierRange;
bool ArgumentDependentLookup;
+ bool Overloaded;
bool HasExplicitTemplateArgs;
- const TemplateArgumentLoc *ExplicitTemplateArgs;
- unsigned NumExplicitTemplateArgs;
+ TemplateArgumentListInfo ExplicitTemplateArgs;
- DeconstructCallFunction(Fn,
- Function, UnqualifiedName, Qualifier, QualifierRange,
- ArgumentDependentLookup, HasExplicitTemplateArgs,
- ExplicitTemplateArgs, NumExplicitTemplateArgs);
+ DeconstructCallFunction(Fn, Fns, UnqualifiedName, Qualifier, QualifierRange,
+ ArgumentDependentLookup, Overloaded,
+ HasExplicitTemplateArgs, ExplicitTemplateArgs);
// FIXME: What if we're calling something that isn't a function declaration?
@@ -1488,9 +1477,9 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
// Build an overload candidate set based on the functions we find.
OverloadCandidateSet CandidateSet;
- AddOverloadedCallCandidates(Function, UnqualifiedName,
- ArgumentDependentLookup, HasExplicitTemplateArgs,
- ExplicitTemplateArgs, NumExplicitTemplateArgs,
+ AddOverloadedCallCandidates(Fns, UnqualifiedName,
+ ArgumentDependentLookup,
+ (HasExplicitTemplateArgs ? &ExplicitTemplateArgs : 0),
Args, NumArgs,
CandidateSet,
/*PartialOverloading=*/true);
@@ -1968,8 +1957,10 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName,
if (!CDecl && FName->isStr("super")) {
// "super" may be the name of a variable, in which case we are
// probably calling an instance method.
- OwningExprResult Super = ActOnDeclarationNameExpr(S, FNameLoc, FName,
- false, 0, false);
+ CXXScopeSpec SS;
+ UnqualifiedId id;
+ id.setIdentifier(FName, FNameLoc);
+ OwningExprResult Super = ActOnIdExpression(S, SS, id, false, false);
return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(),
SelIdents, NumSelIdents);
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index b5109f8..520d7de 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -66,31 +66,68 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(DeclPtrTy Ptr) {
/// and then return NULL.
Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
Scope *S, const CXXScopeSpec *SS,
- bool isClassName) {
- // C++ [temp.res]p3:
- // A qualified-id that refers to a type and in which the
- // nested-name-specifier depends on a template-parameter (14.6.2)
- // shall be prefixed by the keyword typename to indicate that the
- // qualified-id denotes a type, forming an
- // elaborated-type-specifier (7.1.5.3).
- //
- // We therefore do not perform any name lookup if the result would
- // refer to a member of an unknown specialization.
- if (SS && isUnknownSpecialization(*SS)) {
- if (!isClassName)
+ bool isClassName,
+ TypeTy *ObjectTypePtr) {
+ // Determine where we will perform name lookup.
+ DeclContext *LookupCtx = 0;
+ if (ObjectTypePtr) {
+ QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
+ if (ObjectType->isRecordType())
+ LookupCtx = computeDeclContext(ObjectType);
+ } else if (SS && SS->isSet()) {
+ LookupCtx = computeDeclContext(*SS, false);
+
+ if (!LookupCtx) {
+ if (isDependentScopeSpecifier(*SS)) {
+ // C++ [temp.res]p3:
+ // A qualified-id that refers to a type and in which the
+ // nested-name-specifier depends on a template-parameter (14.6.2)
+ // shall be prefixed by the keyword typename to indicate that the
+ // qualified-id denotes a type, forming an
+ // elaborated-type-specifier (7.1.5.3).
+ //
+ // We therefore do not perform any name lookup if the result would
+ // refer to a member of an unknown specialization.
+ if (!isClassName)
+ return 0;
+
+ // We know from the grammar that this name refers to a type, so build a
+ // TypenameType node to describe the type.
+ // FIXME: Record somewhere that this TypenameType node has no "typename"
+ // keyword associated with it.
+ return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(),
+ II, SS->getRange()).getAsOpaquePtr();
+ }
+
+ return 0;
+ }
+
+ if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS))
return 0;
-
- // We know from the grammar that this name refers to a type, so build a
- // TypenameType node to describe the type.
- // FIXME: Record somewhere that this TypenameType node has no "typename"
- // keyword associated with it.
- return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(),
- II, SS->getRange()).getAsOpaquePtr();
}
-
+
LookupResult Result(*this, &II, NameLoc, LookupOrdinaryName);
- LookupParsedName(Result, S, SS, false);
-
+ if (LookupCtx) {
+ // Perform "qualified" name lookup into the declaration context we
+ // computed, which is either the type of the base of a member access
+ // expression or the declaration context associated with a prior
+ // nested-name-specifier.
+ LookupQualifiedName(Result, LookupCtx);
+
+ if (ObjectTypePtr && Result.empty()) {
+ // C++ [basic.lookup.classref]p3:
+ // If the unqualified-id is ~type-name, the type-name is looked up
+ // in the context of the entire postfix-expression. If the type T of
+ // the object expression is of a class type C, the type-name is also
+ // looked up in the scope of class C. At least one of the lookups shall
+ // find a name that refers to (possibly cv-qualified) T.
+ LookupName(Result, S);
+ }
+ } else {
+ // Perform unqualified name lookup.
+ LookupName(Result, S);
+ }
+
NamedDecl *IIDecl = 0;
switch (Result.getResultKind()) {
case LookupResult::NotFound:
@@ -364,37 +401,6 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
}
bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S) {
- if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) {
- // Look inside the overload set to determine if any of the declarations
- // are in scope. (Possibly) build a new overload set containing only
- // those declarations that are in scope.
- OverloadedFunctionDecl *NewOvl = 0;
- bool FoundInScope = false;
- for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
- FEnd = Ovl->function_end();
- F != FEnd; ++F) {
- NamedDecl *FD = F->get();
- if (!isDeclInScope(FD, Ctx, S)) {
- if (!NewOvl && F != Ovl->function_begin()) {
- NewOvl = OverloadedFunctionDecl::Create(Context,
- F->get()->getDeclContext(),
- F->get()->getDeclName());
- D = NewOvl;
- for (OverloadedFunctionDecl::function_iterator
- First = Ovl->function_begin();
- First != F; ++First)
- NewOvl->addOverload(*First);
- }
- } else {
- FoundInScope = true;
- if (NewOvl)
- NewOvl->addOverload(*F);
- }
- }
-
- return FoundInScope;
- }
-
return IdResolver.isDeclInScope(D, Ctx, Context, S);
}
@@ -644,7 +650,9 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) {
case 3:
if (!TypeID->isStr("SEL"))
break;
- Context.setObjCSelType(Context.getTypeDeclType(New));
+ Context.ObjCSelRedefinitionType = New->getUnderlyingType();
+ // Install the built-in type for 'SEL', ignoring the current definition.
+ New->setTypeForDecl(Context.getObjCSelType().getTypePtr());
return;
case 8:
if (!TypeID->isStr("Protocol"))
@@ -766,9 +774,6 @@ struct GNUCompatibleParamWarning {
///
/// Returns true if there was an error, false otherwise.
bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
- assert(!isa<OverloadedFunctionDecl>(OldD) &&
- "Cannot merge with an overloaded function declaration");
-
// Verify the old decl was also a function.
FunctionDecl *Old = 0;
if (FunctionTemplateDecl *OldFunctionTemplate
@@ -1718,22 +1723,26 @@ DeclarationName Sema::GetNameForDeclarator(Declarator &D) {
}
/// \brief Retrieves the canonicalized name from a parsed unqualified-id.
-DeclarationName Sema::GetNameFromUnqualifiedId(UnqualifiedId &Name) {
+DeclarationName Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) {
switch (Name.getKind()) {
case UnqualifiedId::IK_Identifier:
return DeclarationName(Name.Identifier);
case UnqualifiedId::IK_OperatorFunctionId:
return Context.DeclarationNames.getCXXOperatorName(
- Name.OperatorFunctionId.Operator);
-
+ Name.OperatorFunctionId.Operator);
+
+ case UnqualifiedId::IK_LiteralOperatorId:
+ return Context.DeclarationNames.getCXXLiteralOperatorName(
+ Name.Identifier);
+
case UnqualifiedId::IK_ConversionFunctionId: {
QualType Ty = GetTypeFromParser(Name.ConversionFunctionId);
if (Ty.isNull())
return DeclarationName();
return Context.DeclarationNames.getCXXConversionFunctionName(
- Context.getCanonicalType(Ty));
+ Context.getCanonicalType(Ty));
}
case UnqualifiedId::IK_ConstructorName: {
@@ -1742,7 +1751,7 @@ DeclarationName Sema::GetNameFromUnqualifiedId(UnqualifiedId &Name) {
return DeclarationName();
return Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(Ty));
+ Context.getCanonicalType(Ty));
}
case UnqualifiedId::IK_DestructorName: {
@@ -2194,8 +2203,6 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
if (!PrevDecl)
return 0;
- // FIXME: PrevDecl could be an OverloadedFunctionDecl, in which
- // case we need to check each of the overloaded functions.
if (!PrevDecl->hasLinkage())
return false;
@@ -2364,8 +2371,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
- NewVD->addAttr(::new (Context) AsmLabelAttr(std::string(SE->getStrData(),
- SE->getByteLength())));
+ NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getString()));
}
// Don't consider existing declarations that are in a different
@@ -2548,10 +2554,22 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *UserData) {
RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
-
+
FindOverriddenMethodData *Data
= reinterpret_cast<FindOverriddenMethodData*>(UserData);
- for (Path.Decls = BaseRecord->lookup(Data->Method->getDeclName());
+
+ DeclarationName Name = Data->Method->getDeclName();
+
+ // FIXME: Do we care about other names here too?
+ if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
+ // We really want to find the base class constructor here.
+ QualType T = Data->S->Context.getTypeDeclType(BaseRecord);
+ CanQualType CT = Data->S->Context.getCanonicalType(T);
+
+ Name = Data->S->Context.DeclarationNames.getCXXDestructorName(CT);
+ }
+
+ for (Path.Decls = BaseRecord->lookup(Name);
Path.Decls.first != Path.Decls.second;
++Path.Decls.first) {
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*Path.Decls.first)) {
@@ -2576,7 +2594,8 @@ void Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
E = Paths.found_decls_end(); I != E; ++I) {
if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
if (!CheckOverridingFunctionReturnType(MD, OldMD) &&
- !CheckOverridingFunctionExceptionSpec(MD, OldMD))
+ !CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
+ !CheckOverridingFunctionAttributes(MD, OldMD))
MD->addOverriddenMethod(OldMD);
}
}
@@ -2846,7 +2865,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);
@@ -2869,8 +2887,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
- NewFD->addAttr(::new (Context) AsmLabelAttr(std::string(SE->getStrData(),
- SE->getByteLength())));
+ NewFD->addAttr(::new (Context) AsmLabelAttr(SE->getString()));
}
// Copy the parameter declarations from the declarator D to the function
@@ -2935,10 +2952,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// If the declarator is a template-id, translate the parser's template
// argument list into our AST format.
bool HasExplicitTemplateArgs = false;
- llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs;
- SourceLocation LAngleLoc, RAngleLoc;
+ TemplateArgumentListInfo TemplateArgs;
if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
+ TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
+ TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);
ASTTemplateArgsPtr TemplateArgsPtr(*this,
TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
@@ -2947,8 +2965,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
TemplateArgsPtr.release();
HasExplicitTemplateArgs = true;
- LAngleLoc = TemplateId->LAngleLoc;
- RAngleLoc = TemplateId->RAngleLoc;
if (FunctionTemplate) {
// FIXME: Diagnose function template with explicit template
@@ -2970,9 +2986,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
if (isFunctionTemplateSpecialization) {
- if (CheckFunctionTemplateSpecialization(NewFD, HasExplicitTemplateArgs,
- LAngleLoc, TemplateArgs.data(),
- TemplateArgs.size(), RAngleLoc,
+ if (CheckFunctionTemplateSpecialization(NewFD,
+ (HasExplicitTemplateArgs ? &TemplateArgs : 0),
Previous))
NewFD->setInvalidDecl();
} else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) &&
@@ -2988,6 +3003,16 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
+ // If we have a function template, check the template parameter
+ // list. This will check and merge default template arguments.
+ if (FunctionTemplate) {
+ FunctionTemplateDecl *PrevTemplate = FunctionTemplate->getPreviousDeclaration();
+ CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(),
+ PrevTemplate? PrevTemplate->getTemplateParameters() : 0,
+ D.getDeclSpec().isFriendSpecified()? TPC_FriendFunctionTemplate
+ : TPC_FunctionTemplate);
+ }
+
if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
// An out-of-line member function declaration must also be a
// definition (C++ [dcl.meaning]p1).
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index c96ab46..b2124fe 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -177,9 +177,10 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
// Special case where the argument is a template id.
if (Attr.getParameterName()) {
- sizeExpr = S.ActOnDeclarationNameExpr(scope, Attr.getLoc(),
- Attr.getParameterName(),
- false, 0, false).takeAs<Expr>();
+ CXXScopeSpec SS;
+ UnqualifiedId id;
+ id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
+ sizeExpr = S.ActOnIdExpression(scope, SS, id, false, false).takeAs<Expr>();
} else {
// check the attribute arguments.
if (Attr.getNumArgs() != 1) {
@@ -410,12 +411,9 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- const char *Alias = Str->getStrData();
- unsigned AliasLen = Str->getByteLength();
-
// FIXME: check if target symbol exists in current file
- d->addAttr(::new (S.Context) AliasAttr(std::string(Alias, AliasLen)));
+ d->addAttr(::new (S.Context) AliasAttr(Str->getString()));
}
static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
@@ -464,7 +462,9 @@ 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()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ S.Diag(Attr.getLoc(),
+ Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
+ : diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
return false;
}
@@ -484,6 +484,15 @@ static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
d->addAttr(::new (S.Context) AnalyzerNoReturnAttr());
}
+static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ if (!isFunctionOrMethod(d) && !isa<ParmVarDecl>(d)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << 8; /*function, method, or parameter*/
+ return;
+ }
+ // FIXME: Actually store the attribute on the declaration
+}
+
static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() != 0) {
@@ -994,12 +1003,10 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
- std::string SectionStr(SE->getStrData(), SE->getByteLength());
-
// If the target wants to validate the section specifier, make it happen.
- std::string Error = S.Context.Target.isValidSectionSpecifier(SectionStr);
+ std::string Error = S.Context.Target.isValidSectionSpecifier(SE->getString());
if (Error.empty()) {
- D->addAttr(::new (S.Context) SectionAttr(SectionStr));
+ D->addAttr(::new (S.Context) SectionAttr(SE->getString()));
return;
}
@@ -1506,8 +1513,7 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate";
return;
}
- d->addAttr(::new (S.Context) AnnotateAttr(std::string(SE->getStrData(),
- SE->getByteLength())));
+ d->addAttr(::new (S.Context) AnnotateAttr(SE->getString()));
}
static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -1516,6 +1522,10 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
+
+ //FIXME: The C++0x version of this attribute has more limited applicabilty
+ // than GNU's, and should error out when it is used to specify a
+ // weaker alignment, rather than being silently ignored.
unsigned Align = 0;
if (Attr.getNumArgs() == 0) {
@@ -1794,6 +1804,108 @@ static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(::new (S.Context) RegparmAttr(NumParams.getZExtValue()));
}
+static void HandleFinalAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isa<CXXRecordDecl>(d)
+ && (!isa<CXXMethodDecl>(d) || !cast<CXXMethodDecl>(d)->isVirtual())) {
+ S.Diag(Attr.getLoc(),
+ Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
+ : diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 7 /*virtual method or class*/;
+ return;
+ }
+
+ // FIXME: Conform to C++0x redeclaration rules.
+
+ if (d->getAttr<FinalAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "final";
+ return;
+ }
+
+ d->addAttr(::new (S.Context) FinalAttr());
+}
+
+//===----------------------------------------------------------------------===//
+// C++0x member checking attributes
+//===----------------------------------------------------------------------===//
+
+static void HandleBaseCheckAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isa<CXXRecordDecl>(d)) {
+ S.Diag(Attr.getLoc(),
+ Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
+ : diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 9 /*class*/;
+ return;
+ }
+
+ if (d->getAttr<BaseCheckAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "base_check";
+ return;
+ }
+
+ d->addAttr(::new (S.Context) BaseCheckAttr());
+}
+
+static void HandleHidingAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isa<RecordDecl>(d->getDeclContext())) {
+ // FIXME: It's not the type that's the problem
+ S.Diag(Attr.getLoc(),
+ Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
+ : diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 11 /*member*/;
+ return;
+ }
+
+ // FIXME: Conform to C++0x redeclaration rules.
+
+ if (d->getAttr<HidingAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "hiding";
+ return;
+ }
+
+ d->addAttr(::new (S.Context) HidingAttr());
+}
+
+static void HandleOverrideAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isa<CXXMethodDecl>(d) || !cast<CXXMethodDecl>(d)->isVirtual()) {
+ // FIXME: It's not the type that's the problem
+ S.Diag(Attr.getLoc(),
+ Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
+ : diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 10 /*virtual method*/;
+ return;
+ }
+
+ // FIXME: Conform to C++0x redeclaration rules.
+
+ if (d->getAttr<OverrideAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "override";
+ return;
+ }
+
+ d->addAttr(::new (S.Context) OverrideAttr());
+}
+
//===----------------------------------------------------------------------===//
// Checker-specific attribute handlers.
//===----------------------------------------------------------------------===//
@@ -1841,7 +1953,8 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
/// the attribute applies to decls. If the attribute is a type attribute, just
-/// silently ignore it.
+/// silently ignore it if a GNU attribute. FIXME: Applying a C++0x attribute to
+/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4).
static void ProcessDeclAttribute(Scope *scope, Decl *D,
const AttributeList &Attr, Sema &S) {
if (Attr.isDeclspecAttribute())
@@ -1854,31 +1967,37 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
// Ignore these, these are type attributes, handled by
// ProcessTypeAttributes.
break;
- case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break;
- case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break;
+ case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break;
+ case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break;
case AttributeList::AT_always_inline:
HandleAlwaysInlineAttr (D, Attr, S); break;
case AttributeList::AT_analyzer_noreturn:
HandleAnalyzerNoReturnAttr (D, Attr, S); break;
- case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break;
- case AttributeList::AT_cdecl: HandleCDeclAttr (D, Attr, S); break;
- case AttributeList::AT_constructor: HandleConstructorAttr(D, Attr, S); break;
- case AttributeList::AT_deprecated: HandleDeprecatedAttr(D, Attr, S); break;
- case AttributeList::AT_destructor: HandleDestructorAttr(D, Attr, S); break;
- case AttributeList::AT_dllexport: HandleDLLExportAttr (D, Attr, S); break;
- case AttributeList::AT_dllimport: HandleDLLImportAttr (D, Attr, S); break;
+ case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break;
+ case AttributeList::AT_base_check: HandleBaseCheckAttr (D, Attr, S); break;
+ case AttributeList::AT_carries_dependency:
+ HandleDependencyAttr (D, Attr, S); break;
+ case AttributeList::AT_cdecl: HandleCDeclAttr (D, Attr, S); break;
+ case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break;
+ case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break;
+ case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break;
+ case AttributeList::AT_dllexport: HandleDLLExportAttr (D, Attr, S); break;
+ case AttributeList::AT_dllimport: HandleDLLImportAttr (D, Attr, S); break;
case AttributeList::AT_ext_vector_type:
HandleExtVectorTypeAttr(scope, D, Attr, S);
break;
- case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break;
- case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break;
- case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break;
- case AttributeList::AT_gnu_inline: HandleGNUInlineAttr(D, Attr, S); break;
- case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break;
- case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break;
- case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break;
- case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break;
- case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break;
+ case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break;
+ case AttributeList::AT_final: HandleFinalAttr (D, Attr, S); break;
+ case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break;
+ case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break;
+ case AttributeList::AT_gnu_inline: HandleGNUInlineAttr (D, Attr, S); break;
+ case AttributeList::AT_hiding: HandleHidingAttr (D, Attr, S); break;
+ case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break;
+ case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break;
+ case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break;
+ case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break;
+ case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break;
+ case AttributeList::AT_override: HandleOverrideAttr (D, Attr, S); break;
// Checker-specific.
case AttributeList::AT_ns_returns_retained:
@@ -1888,18 +2007,18 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_reqd_wg_size:
HandleReqdWorkGroupSize(D, Attr, S); break;
- case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break;
- case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break;
- case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break;
- 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_packed: HandlePackedAttr (D, Attr, S); break;
+ case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break;
+ case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break;
+ 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;
- case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break;
- case AttributeList::AT_weak_import: HandleWeakImportAttr(D, Attr, S); break;
+ case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break;
+ case AttributeList::AT_weak_import: HandleWeakImportAttr (D, Attr, S); break;
case AttributeList::AT_transparent_union:
HandleTransparentUnionAttr(D, Attr, S);
break;
@@ -1907,15 +2026,15 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
HandleObjCExceptionAttr(D, Attr, S);
break;
case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break;
- case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break;
- case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break;
- case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break;
- case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break;
- case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break;
- case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break;
- case AttributeList::AT_nodebug: HandleNoDebugAttr (D, Attr, S); break;
- case AttributeList::AT_noinline: HandleNoInlineAttr (D, Attr, S); break;
- case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break;
+ case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break;
+ case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break;
+ case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break;
+ case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break;
+ case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break;
+ case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break;
+ case AttributeList::AT_nodebug: HandleNoDebugAttr (D, Attr, S); break;
+ case AttributeList::AT_noinline: HandleNoInlineAttr (D, Attr, S); break;
+ case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break;
case AttributeList::IgnoredAttribute:
case AttributeList::AT_no_instrument_function: // Interacts with -pg.
// Just ignore
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index bda1a69..f161cb5 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -24,8 +24,6 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Support/Compiler.h"
-#include <algorithm> // for std::equal
#include <map>
#include <set>
@@ -41,7 +39,7 @@ namespace {
/// contains any ill-formed subexpressions. For example, this will
/// diagnose the use of local variables or parameters within the
/// default argument expression.
- class VISIBILITY_HIDDEN CheckDefaultArgumentVisitor
+ class CheckDefaultArgumentVisitor
: public StmtVisitor<CheckDefaultArgumentVisitor, bool> {
Expr *DefaultArg;
Sema *S;
@@ -354,9 +352,8 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
if (CheckEquivalentExceptionSpec(
Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
- New->getType()->getAs<FunctionProtoType>(), New->getLocation())) {
+ New->getType()->getAs<FunctionProtoType>(), New->getLocation()))
Invalid = true;
- }
return Invalid;
}
@@ -489,6 +486,13 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
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();
+ return 0;
+ }
// C++ [dcl.init.aggr]p1:
// An aggregate is [...] a class with [...] no base classes [...].
@@ -783,7 +787,8 @@ std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) {
Sema::DeclPtrTy
Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
- ExprTy *BW, ExprTy *InitExpr, bool Deleted) {
+ ExprTy *BW, ExprTy *InitExpr, bool IsDefinition,
+ bool Deleted) {
const DeclSpec &DS = D.getDeclSpec();
DeclarationName Name = GetNameForDeclarator(D);
Expr *BitWidth = static_cast<Expr*>(BW);
@@ -865,7 +870,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
AS);
assert(Member && "HandleField never returns null");
} else {
- Member = HandleDeclarator(S, D, move(TemplateParameterLists), false)
+ Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition)
.getAs<Decl>();
if (!Member) {
if (BitWidth) DeleteExpr(BitWidth);
@@ -1708,7 +1713,7 @@ void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {
namespace {
/// PureVirtualMethodCollector - traverses a class and its superclasses
/// and determines if it has any pure virtual methods.
- class VISIBILITY_HIDDEN PureVirtualMethodCollector {
+ class PureVirtualMethodCollector {
ASTContext &Context;
public:
@@ -1855,7 +1860,7 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
}
namespace {
- class VISIBILITY_HIDDEN AbstractClassUsageDiagnoser
+ class AbstractClassUsageDiagnoser
: public DeclVisitor<AbstractClassUsageDiagnoser, bool> {
Sema &SemaRef;
CXXRecordDecl *AbstractClass;
@@ -2164,6 +2169,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
Destructor->setImplicit();
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
ClassDecl->addDecl(Destructor);
+
+ AddOverriddenMethods(ClassDecl, Destructor);
}
}
@@ -2360,9 +2367,9 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
ClassDecl->addedConstructor(Context, Constructor);
}
-/// CheckDestructor - Checks a fully-formed destructor for
-/// well-formedness, issuing any diagnostics required.
-void Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
+/// CheckDestructor - Checks a fully-formed destructor for well-formedness,
+/// issuing any diagnostics required. Returns true on error.
+bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
CXXRecordDecl *RD = Destructor->getParent();
if (Destructor->isVirtual()) {
@@ -2377,9 +2384,13 @@ void Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
FunctionDecl *OperatorDelete = 0;
DeclarationName Name =
Context.DeclarationNames.getCXXOperatorName(OO_Delete);
- if (!FindDeallocationFunction(Loc, RD, Name, OperatorDelete))
- Destructor->setOperatorDelete(OperatorDelete);
+ if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete))
+ return true;
+
+ Destructor->setOperatorDelete(OperatorDelete);
}
+
+ return false;
}
static inline bool
@@ -2594,16 +2605,8 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
if (FunctionTemplateDecl *ConversionTemplate
= Conversion->getDescribedFunctionTemplate())
ExpectedPrevDecl = ConversionTemplate->getPreviousDeclaration();
- OverloadedFunctionDecl *Conversions = ClassDecl->getConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator
- Conv = Conversions->function_begin(),
- ConvEnd = Conversions->function_end();
- Conv != ConvEnd; ++Conv) {
- if (*Conv == ExpectedPrevDecl) {
- *Conv = Conversion;
- return DeclPtrTy::make(Conversion);
- }
- }
+ if (ClassDecl->replaceConversion(ExpectedPrevDecl, Conversion))
+ return DeclPtrTy::make(Conversion);
assert(Conversion->isInvalidDecl() && "Conversion should not get here.");
} else if (FunctionTemplateDecl *ConversionTemplate
= Conversion->getDescribedFunctionTemplate())
@@ -2723,6 +2726,14 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
return DeclPtrTy::make(Namespc);
}
+/// getNamespaceDecl - Returns the namespace a decl represents. If the decl
+/// is a namespace alias, returns the namespace it points to.
+static inline NamespaceDecl *getNamespaceDecl(NamedDecl *D) {
+ if (NamespaceAliasDecl *AD = dyn_cast_or_null<NamespaceAliasDecl>(D))
+ return AD->getNamespace();
+ return dyn_cast_or_null<NamespaceDecl>(D);
+}
+
/// ActOnFinishNamespaceDef - This callback is called after a namespace is
/// exited. Decl is the DeclTy returned by ActOnStartNamespaceDef.
void Sema::ActOnFinishNamespaceDef(DeclPtrTy D, SourceLocation RBrace) {
@@ -2754,9 +2765,9 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S,
return DeclPtrTy();
if (!R.empty()) {
- NamedDecl *NS = R.getFoundDecl();
- // FIXME: Namespace aliases!
- assert(isa<NamespaceDecl>(NS) && "expected namespace decl");
+ NamedDecl *Named = R.getFoundDecl();
+ assert((isa<NamespaceDecl>(Named) || isa<NamespaceAliasDecl>(Named))
+ && "expected namespace decl");
// C++ [namespace.udir]p1:
// A using-directive specifies that the names in the nominated
// namespace can be used in the scope in which the
@@ -2769,18 +2780,15 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S,
// Find enclosing context containing both using-directive and
// nominated namespace.
+ NamespaceDecl *NS = getNamespaceDecl(Named);
DeclContext *CommonAncestor = cast<DeclContext>(NS);
while (CommonAncestor && !CommonAncestor->Encloses(CurContext))
CommonAncestor = CommonAncestor->getParent();
- UDir = UsingDirectiveDecl::Create(Context,
- CurContext, UsingLoc,
- NamespcLoc,
+ UDir = UsingDirectiveDecl::Create(Context, CurContext, UsingLoc, NamespcLoc,
SS.getRange(),
(NestedNameSpecifier *)SS.getScopeRep(),
- IdentLoc,
- cast<NamespaceDecl>(NS),
- CommonAncestor);
+ IdentLoc, Named, CommonAncestor);
PushUsingDirective(S, UDir);
} else {
Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
@@ -2817,6 +2825,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
switch (Name.getKind()) {
case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_OperatorFunctionId:
+ case UnqualifiedId::IK_LiteralOperatorId:
case UnqualifiedId::IK_ConversionFunctionId:
break;
@@ -3007,14 +3016,6 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
return UD;
}
-/// getNamespaceDecl - Returns the namespace a decl represents. If the decl
-/// is a namespace alias, returns the namespace it points to.
-static inline NamespaceDecl *getNamespaceDecl(NamedDecl *D) {
- if (NamespaceAliasDecl *AD = dyn_cast_or_null<NamespaceAliasDecl>(D))
- return AD->getNamespace();
- return dyn_cast_or_null<NamespaceDecl>(D);
-}
-
Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
SourceLocation NamespaceLoc,
SourceLocation AliasLoc,
@@ -3074,8 +3075,8 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
if (SetBaseOrMemberInitializers(Constructor, 0, 0, true)) {
- Diag(CurrentLocation, diag::note_ctor_synthesized_at)
- << Context.getTagDeclType(ClassDecl);
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
} else {
Constructor->setUsed();
@@ -3127,6 +3128,17 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
}
}
}
+
+ // FIXME: If CheckDestructor fails, we should emit a note about where the
+ // implicit destructor was needed.
+ if (CheckDestructor(Destructor)) {
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXDestructor << Context.getTagDeclType(ClassDecl);
+
+ Destructor->setInvalidDecl();
+ return;
+ }
+
Destructor->setUsed();
}
@@ -3292,6 +3304,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
unsigned NumExprs = ExprArgs.size();
Expr **Exprs = (Expr **)ExprArgs.release();
+ MarkDeclarationReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, Constructor,
Elidable, Exprs, NumExprs));
}
@@ -3305,6 +3318,7 @@ Sema::BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Constructor,
unsigned NumExprs = Args.size();
Expr **Exprs = (Expr **)Args.release();
+ MarkDeclarationReferenced(TyBeginLoc, Constructor);
return Owned(new (Context) CXXTemporaryObjectExpr(Context, Constructor, Ty,
TyBeginLoc, Exprs,
NumExprs, RParenLoc));
@@ -3490,7 +3504,8 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef,
Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) ||
(Kind == Sema::IK_Default && Constructor->isDefaultConstructor())) {
if (ConstructorTmpl)
- SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0,
+ SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl,
+ /*ExplicitArgs*/ 0,
Args, NumArgs, CandidateSet);
else
SemaRef.AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
@@ -3612,10 +3627,13 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
Diag(Loc, diag::err_ovl_deleted_init)
<< Best->Function->isDeleted()
<< InitEntity << Range;
- else
+ else {
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(ClassType->getAs<RecordType>()->getDecl());
Diag(Loc, diag::err_ovl_deleted_init)
<< Best->Function->isDeleted()
- << InitEntity << Range;
+ << RD->getDeclName() << Range;
+ }
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
return 0;
}
@@ -3646,58 +3664,22 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
= Constructor->getType()->getAs<FunctionProtoType>();
assert(Proto && "Constructor without a prototype?");
unsigned NumArgsInProto = Proto->getNumArgs();
- unsigned NumArgsToCheck = NumArgs;
// If too few arguments are available, we'll fill in the rest with defaults.
- if (NumArgs < NumArgsInProto) {
- NumArgsToCheck = NumArgsInProto;
+ if (NumArgs < NumArgsInProto)
ConvertedArgs.reserve(NumArgsInProto);
- } else {
+ else
ConvertedArgs.reserve(NumArgs);
- if (NumArgs > NumArgsInProto)
- NumArgsToCheck = NumArgsInProto;
- }
-
- // Convert arguments
- for (unsigned i = 0; i != NumArgsToCheck; i++) {
- QualType ProtoArgType = Proto->getArgType(i);
-
- Expr *Arg;
- if (i < NumArgs) {
- Arg = Args[i];
-
- // Pass the argument.
- if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
- return true;
-
- Args[i] = 0;
- } else {
- ParmVarDecl *Param = Constructor->getParamDecl(i);
-
- OwningExprResult DefArg = BuildCXXDefaultArgExpr(Loc, Constructor, Param);
- if (DefArg.isInvalid())
- return true;
-
- Arg = DefArg.takeAs<Expr>();
- }
-
- ConvertedArgs.push_back(Arg);
- }
-
- // If this is a variadic call, handle args passed through "...".
- if (Proto->isVariadic()) {
- // Promote the arguments (C99 6.5.2.2p7).
- for (unsigned i = NumArgsInProto; i != NumArgs; i++) {
- Expr *Arg = Args[i];
- if (DefaultVariadicArgumentPromotion(Arg, VariadicConstructor))
- return true;
-
- ConvertedArgs.push_back(Arg);
- Args[i] = 0;
- }
- }
-
- return false;
+
+ VariadicCallType CallType =
+ Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
+ llvm::SmallVector<Expr *, 8> AllArgs;
+ bool Invalid = GatherArgumentsForCall(Loc, Constructor,
+ Proto, 0, Args, NumArgs, AllArgs,
+ CallType);
+ for (unsigned i =0, size = AllArgs.size(); i < size; i++)
+ ConvertedArgs.push_back(AllArgs[i]);
+ return Invalid;
}
/// CompareReferenceRelationship - Compare the two types T1 and T2 to
@@ -3888,18 +3870,17 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
= dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
OverloadCandidateSet CandidateSet;
- OverloadedFunctionDecl *Conversions
+ const UnresolvedSet *Conversions
= T2RecordDecl->getVisibleConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator Func
- = Conversions->function_begin();
- Func != Conversions->function_end(); ++Func) {
+ for (UnresolvedSet::iterator I = Conversions->begin(),
+ E = Conversions->end(); I != E; ++I) {
FunctionTemplateDecl *ConvTemplate
- = dyn_cast<FunctionTemplateDecl>(*Func);
+ = dyn_cast<FunctionTemplateDecl>(*I);
CXXConversionDecl *Conv;
if (ConvTemplate)
Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
- Conv = cast<CXXConversionDecl>(*Func);
+ Conv = cast<CXXConversionDecl>(*I);
// If the conversion function doesn't return a reference type,
// it can't be considered for this conversion.
@@ -4896,6 +4877,19 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
return false;
}
+bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old)
+{
+ if (Old->hasAttr<FinalAttr>()) {
+ Diag(New->getLocation(), diag::err_final_function_overridden)
+ << New->getDeclName();
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ return true;
+ }
+
+ return false;
+}
+
/// 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
@@ -4942,3 +4936,39 @@ void Sema::ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl) {
assert(S->getEntity() == D->getDeclContext() && "Context imbalance!");
ExitDeclaratorContext(S);
}
+
+/// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
+/// C++ if/switch/while/for statement.
+/// e.g: "if (int x = f()) {...}"
+Action::DeclResult
+Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
+ // C++ 6.4p2:
+ // The declarator shall not specify a function or an array.
+ // The type-specifier-seq shall not contain typedef and shall not declare a
+ // new class or enumeration.
+ assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
+ "Parser allowed 'typedef' as storage class of condition decl.");
+
+ DeclaratorInfo *DInfo = 0;
+ TagDecl *OwnedTag = 0;
+ QualType Ty = GetTypeForDeclarator(D, S, &DInfo, &OwnedTag);
+
+ if (Ty->isFunctionType()) { // The declarator shall not specify a function...
+ // We exit without creating a CXXConditionDeclExpr because a FunctionDecl
+ // would be created and CXXConditionDeclExpr wants a VarDecl.
+ Diag(D.getIdentifierLoc(), diag::err_invalid_use_of_function_type)
+ << D.getSourceRange();
+ return DeclResult();
+ } else if (OwnedTag && OwnedTag->isDefinition()) {
+ // The type-specifier-seq shall not declare a new class or enumeration.
+ Diag(OwnedTag->getLocation(), diag::err_type_defined_in_condition);
+ }
+
+ DeclPtrTy Dcl = ActOnDeclarator(S, D);
+ if (!Dcl)
+ return DeclResult();
+
+ VarDecl *VD = cast<VarDecl>(Dcl.getAs<Decl>());
+ VD->setDeclaredInCondition(true);
+ return Dcl;
+}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 4f08ffe..f653cf6 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -152,9 +152,10 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
++sentinel;
}
Expr *sentinelExpr = Args[sentinel];
- if (sentinelExpr && (!sentinelExpr->getType()->isPointerType() ||
- !sentinelExpr->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNull))) {
+ if (sentinelExpr && (!isa<GNUNullExpr>(sentinelExpr) &&
+ (!sentinelExpr->getType()->isPointerType() ||
+ !sentinelExpr->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)))) {
Diag(Loc, diag::warn_missing_sentinel) << isMethod;
Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
}
@@ -415,7 +416,6 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
/// BuildDeclRefExpr - Build a DeclRefExpr.
Sema::OwningExprResult
Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
- bool TypeDependent, bool ValueDependent,
const CXXScopeSpec *SS) {
if (Context.getCanonicalType(Ty) == Context.UndeducedAutoTy) {
Diag(Loc,
@@ -443,8 +443,7 @@ Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
return Owned(DeclRefExpr::Create(Context,
SS? (NestedNameSpecifier *)SS->getScopeRep() : 0,
SS? SS->getRange() : SourceRange(),
- D, Loc,
- Ty, TypeDependent, ValueDependent));
+ D, Loc, Ty));
}
/// getObjectForAnonymousRecordDecl - Retrieve the (unnamed) field or
@@ -616,204 +615,210 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
return Owned(Result);
}
-Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
- const CXXScopeSpec &SS,
- UnqualifiedId &Name,
- bool HasTrailingLParen,
- bool IsAddressOfOperand) {
- if (Name.getKind() == UnqualifiedId::IK_TemplateId) {
- ASTTemplateArgsPtr TemplateArgsPtr(*this,
- Name.TemplateId->getTemplateArgs(),
- Name.TemplateId->NumArgs);
- return ActOnTemplateIdExpr(SS,
- TemplateTy::make(Name.TemplateId->Template),
- Name.TemplateId->TemplateNameLoc,
- Name.TemplateId->LAngleLoc,
- TemplateArgsPtr,
- Name.TemplateId->RAngleLoc);
+/// Decomposes the given name into a DeclarationName, its location, and
+/// possibly a list of template arguments.
+///
+/// If this produces template arguments, it is permitted to call
+/// DecomposeTemplateName.
+///
+/// This actually loses a lot of source location information for
+/// non-standard name kinds; we should consider preserving that in
+/// some way.
+static void DecomposeUnqualifiedId(Sema &SemaRef,
+ const UnqualifiedId &Id,
+ TemplateArgumentListInfo &Buffer,
+ DeclarationName &Name,
+ SourceLocation &NameLoc,
+ const TemplateArgumentListInfo *&TemplateArgs) {
+ if (Id.getKind() == UnqualifiedId::IK_TemplateId) {
+ Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc);
+ Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc);
+
+ ASTTemplateArgsPtr TemplateArgsPtr(SemaRef,
+ Id.TemplateId->getTemplateArgs(),
+ Id.TemplateId->NumArgs);
+ SemaRef.translateTemplateArguments(TemplateArgsPtr, Buffer);
+ TemplateArgsPtr.release();
+
+ TemplateName TName =
+ Sema::TemplateTy::make(Id.TemplateId->Template).getAsVal<TemplateName>();
+
+ Name = SemaRef.Context.getNameForTemplate(TName);
+ NameLoc = Id.TemplateId->TemplateNameLoc;
+ TemplateArgs = &Buffer;
+ } else {
+ Name = SemaRef.GetNameFromUnqualifiedId(Id);
+ NameLoc = Id.StartLocation;
+ TemplateArgs = 0;
}
-
- // FIXME: We lose a bunch of source information by doing this. Later,
- // we'll want to merge ActOnDeclarationNameExpr's logic into
- // ActOnIdExpression.
- return ActOnDeclarationNameExpr(S,
- Name.StartLocation,
- GetNameFromUnqualifiedId(Name),
- HasTrailingLParen,
- &SS,
- IsAddressOfOperand);
}
-/// ActOnDeclarationNameExpr - The parser has read some kind of name
-/// (e.g., a C++ id-expression (C++ [expr.prim]p1)). This routine
-/// performs lookup on that name and returns an expression that refers
-/// to that name. This routine isn't directly called from the parser,
-/// because the parser doesn't know about DeclarationName. Rather,
-/// this routine is called by ActOnIdExpression, which contains a
-/// parsed UnqualifiedId.
+/// Decompose the given template name into a list of lookup results.
///
-/// HasTrailingLParen indicates whether this identifier is used in a
-/// function call context. LookupCtx is only used for a C++
-/// qualified-id (foo::bar) to indicate the class or namespace that
-/// the identifier must be a member of.
-///
-/// isAddressOfOperand means that this expression is the direct operand
-/// of an address-of operator. This matters because this is the only
-/// situation where a qualified name referencing a non-static member may
-/// appear outside a member function of this class.
-Sema::OwningExprResult
-Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
- DeclarationName Name, bool HasTrailingLParen,
- const CXXScopeSpec *SS,
- bool isAddressOfOperand) {
- // Could be enum-constant, value decl, instance variable, etc.
- if (SS && SS->isInvalid())
- return ExprError();
+/// The unqualified ID must name a non-dependent template, which can
+/// be more easily tested by checking whether DecomposeUnqualifiedId
+/// found template arguments.
+static void DecomposeTemplateName(LookupResult &R, const UnqualifiedId &Id) {
+ assert(Id.getKind() == UnqualifiedId::IK_TemplateId);
+ TemplateName TName =
+ Sema::TemplateTy::make(Id.TemplateId->Template).getAsVal<TemplateName>();
+
+ if (TemplateDecl *TD = TName.getAsTemplateDecl())
+ R.addDecl(TD);
+ else if (OverloadedFunctionDecl *OD
+ = TName.getAsOverloadedFunctionDecl())
+ for (OverloadIterator I(OD), E; I != E; ++I)
+ R.addDecl(*I);
+
+ R.resolveKind();
+}
- // C++ [temp.dep.expr]p3:
- // An id-expression is type-dependent if it contains:
- // -- a nested-name-specifier that contains a class-name that
- // names a dependent type.
- // FIXME: Member of the current instantiation.
- if (SS && isDependentScopeSpecifier(*SS)) {
- return Owned(new (Context) UnresolvedDeclRefExpr(Name, Context.DependentTy,
- Loc, SS->getRange(),
- static_cast<NestedNameSpecifier *>(SS->getScopeRep()),
- isAddressOfOperand));
+static bool IsFullyFormedScope(Sema &SemaRef, CXXRecordDecl *Record) {
+ 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 (!BaseRecord->isDefinition() ||
+ !IsFullyFormedScope(SemaRef, BaseRecord))
+ return false;
}
- LookupResult Lookup(*this, Name, Loc, LookupOrdinaryName);
- LookupParsedName(Lookup, S, SS, true);
+ return true;
+}
+
+/// Determines whether we can lookup this id-expression now or whether
+/// we have to wait until template instantiation is complete.
+static bool IsDependentIdExpression(Sema &SemaRef, const CXXScopeSpec &SS) {
+ DeclContext *DC = SemaRef.computeDeclContext(SS, false);
+
+ // If the qualifier scope isn't computable, it's definitely dependent.
+ if (!DC) return true;
- if (Lookup.isAmbiguous())
+ // If the qualifier scope doesn't name a record, we can always look into it.
+ if (!isa<CXXRecordDecl>(DC)) return false;
+
+ // 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 CurRecord && !IsFullyFormedScope(SemaRef, CurRecord);
+}
+
+Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
+ const CXXScopeSpec &SS,
+ UnqualifiedId &Id,
+ bool HasTrailingLParen,
+ bool isAddressOfOperand) {
+ assert(!(isAddressOfOperand && HasTrailingLParen) &&
+ "cannot be direct & operand and have a trailing lparen");
+
+ if (SS.isInvalid())
return ExprError();
- NamedDecl *D = Lookup.getAsSingleDecl(Context);
+ TemplateArgumentListInfo TemplateArgsBuffer;
+
+ // Decompose the UnqualifiedId into the following data.
+ DeclarationName Name;
+ SourceLocation NameLoc;
+ const TemplateArgumentListInfo *TemplateArgs;
+ DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer,
+ Name, NameLoc, TemplateArgs);
- // If this reference is in an Objective-C method, then ivar lookup happens as
- // well.
IdentifierInfo *II = Name.getAsIdentifierInfo();
- if (II && getCurMethodDecl()) {
- // There are two cases to handle here. 1) scoped lookup could have failed,
- // in which case we should look for an ivar. 2) scoped lookup could have
- // found a decl, but that decl is outside the current instance method (i.e.
- // a global variable). In these two cases, we do a lookup for an ivar with
- // this name, if the lookup sucedes, we replace it our current decl.
- if (D == 0 || D->isDefinedOutsideFunctionOrMethod()) {
- ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
- ObjCInterfaceDecl *ClassDeclared;
- if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
- // Check if referencing a field with __attribute__((deprecated)).
- if (DiagnoseUseOfDecl(IV, Loc))
- return ExprError();
- // If we're referencing an invalid decl, just return this as a silent
- // error node. The error diagnostic was already emitted on the decl.
- if (IV->isInvalidDecl())
- return ExprError();
+ // C++ [temp.dep.expr]p3:
+ // An id-expression is type-dependent if it contains:
+ // -- a nested-name-specifier that contains a class-name that
+ // names a dependent type.
+ // Determine whether this is a member of an unknown specialization;
+ // we need to handle these differently.
+ if (SS.isSet() && IsDependentIdExpression(*this, SS)) {
+ bool CheckForImplicitMember = !isAddressOfOperand;
- bool IsClsMethod = getCurMethodDecl()->isClassMethod();
- // If a class method attemps to use a free standing ivar, this is
- // an error.
- if (IsClsMethod && D && !D->isDefinedOutsideFunctionOrMethod())
- return ExprError(Diag(Loc, diag::error_ivar_use_in_class_method)
- << IV->getDeclName());
- // If a class method uses a global variable, even if an ivar with
- // same name exists, use the global.
- if (!IsClsMethod) {
- if (IV->getAccessControl() == ObjCIvarDecl::Private &&
- ClassDeclared != IFace)
- Diag(Loc, diag::error_private_ivar_access) << IV->getDeclName();
- // FIXME: This should use a new expr for a direct reference, don't
- // turn this into Self->ivar, just return a BareIVarExpr or something.
- IdentifierInfo &II = Context.Idents.get("self");
- UnqualifiedId SelfName;
- SelfName.setIdentifier(&II, SourceLocation());
- CXXScopeSpec SelfScopeSpec;
- OwningExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec,
- SelfName, false, false);
- MarkDeclarationReferenced(Loc, IV);
- return Owned(new (Context)
- ObjCIvarRefExpr(IV, IV->getType(), Loc,
- SelfExpr.takeAs<Expr>(), true, true));
- }
- }
- } else if (getCurMethodDecl()->isInstanceMethod()) {
- // We should warn if a local variable hides an ivar.
- ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
- ObjCInterfaceDecl *ClassDeclared;
- if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
- if (IV->getAccessControl() != ObjCIvarDecl::Private ||
- IFace == ClassDeclared)
- Diag(Loc, diag::warn_ivar_use_hidden) << IV->getDeclName();
- }
- }
- // Needed to implement property "super.method" notation.
- if (D == 0 && II->isStr("super")) {
- QualType T;
+ return ActOnDependentIdExpression(SS, Name, NameLoc,
+ CheckForImplicitMember,
+ TemplateArgs);
+ }
- if (getCurMethodDecl()->isInstanceMethod())
- T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType(
- getCurMethodDecl()->getClassInterface()));
- else
- T = Context.getObjCClassType();
- return Owned(new (Context) ObjCSuperExpr(Loc, T));
+ // Perform the required lookup.
+ LookupResult R(*this, Name, NameLoc, LookupOrdinaryName);
+ if (TemplateArgs) {
+ // Just re-use the lookup done by isTemplateName.
+ DecomposeTemplateName(R, Id);
+ } else {
+ LookupParsedName(R, S, &SS, true);
+
+ // If this reference is in an Objective-C method, then we need to do
+ // some special Objective-C lookup, too.
+ if (!SS.isSet() && II && getCurMethodDecl()) {
+ OwningExprResult E(LookupInObjCMethod(R, S, II));
+ if (E.isInvalid())
+ return ExprError();
+
+ Expr *Ex = E.takeAs<Expr>();
+ if (Ex) return Owned(Ex);
}
}
+ if (R.isAmbiguous())
+ return ExprError();
+
// Determine whether this name might be a candidate for
// argument-dependent lookup.
- bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
- HasTrailingLParen;
+ bool ADL = UseArgumentDependentLookup(SS, R, HasTrailingLParen);
- if (ADL && D == 0) {
- // We've seen something of the form
- //
- // identifier(
- //
- // and we did not find any entity by the name
- // "identifier". However, this identifier is still subject to
- // argument-dependent lookup, so keep track of the name.
- return Owned(new (Context) UnresolvedFunctionNameExpr(Name,
- Context.OverloadTy,
- Loc));
- }
-
- if (D == 0) {
+ if (R.empty() && !ADL) {
// Otherwise, this could be an implicitly declared function reference (legal
- // in C90, extension in C99).
- if (HasTrailingLParen && II &&
- !getLangOptions().CPlusPlus) // Not in C++.
- D = ImplicitlyDefineFunction(Loc, *II, S);
- else {
- // If this name wasn't predeclared and if this is not a function call,
- // diagnose the problem.
- if (SS && !SS->isEmpty())
- return ExprError(Diag(Loc, diag::err_no_member)
- << Name << computeDeclContext(*SS, false)
- << SS->getRange());
+ // in C90, extension in C99, forbidden in C++).
+ if (HasTrailingLParen && II && !getLangOptions().CPlusPlus) {
+ NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *II, S);
+ if (D) R.addDecl(D);
+ }
+
+ // If this name wasn't predeclared and if this is not a function
+ // call, diagnose the problem.
+ if (R.empty()) {
+ if (!SS.isEmpty())
+ return ExprError(Diag(NameLoc, diag::err_no_member)
+ << Name << computeDeclContext(SS, false)
+ << SS.getRange());
else if (Name.getNameKind() == DeclarationName::CXXOperatorName ||
+ Name.getNameKind() == DeclarationName::CXXLiteralOperatorName ||
Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
- return ExprError(Diag(Loc, diag::err_undeclared_use)
- << Name.getAsString());
+ return ExprError(Diag(NameLoc, diag::err_undeclared_use)
+ << Name);
else
- return ExprError(Diag(Loc, diag::err_undeclared_var_use) << Name);
+ return ExprError(Diag(NameLoc, diag::err_undeclared_var_use) << Name);
}
}
- if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ // This is guaranteed from this point on.
+ assert(!R.empty() || ADL);
+
+ if (VarDecl *Var = R.getAsSingle<VarDecl>()) {
// Warn about constructs like:
// if (void *X = foo()) { ... } else { X }.
// In the else block, the pointer is always false.
- // FIXME: In a template instantiation, we don't have scope
- // information to check this property.
if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) {
Scope *CheckS = S;
while (CheckS && CheckS->getControlParent()) {
if (CheckS->isWithinElse() &&
CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) {
- ExprError(Diag(Loc, diag::warn_value_always_zero)
+ ExprError(Diag(NameLoc, diag::warn_value_always_zero)
<< Var->getDeclName()
<< (Var->getType()->isPointerType()? 2 :
Var->getType()->isBooleanType()? 1 : 0));
@@ -824,26 +829,174 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
CheckS = CheckS->getParent();
}
}
- } else if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D)) {
+ } else if (FunctionDecl *Func = R.getAsSingle<FunctionDecl>()) {
if (!getLangOptions().CPlusPlus && !Func->hasPrototype()) {
// C99 DR 316 says that, if a function type comes from a
// function definition (without a prototype), that type is only
// used for checking compatibility. Therefore, when referencing
// the function, we pretend that we don't have the full function
// type.
- if (DiagnoseUseOfDecl(Func, Loc))
+ if (DiagnoseUseOfDecl(Func, NameLoc))
return ExprError();
QualType T = Func->getType();
QualType NoProtoType = T;
if (const FunctionProtoType *Proto = T->getAs<FunctionProtoType>())
NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType());
- return BuildDeclRefExpr(Func, NoProtoType, Loc, false, false, SS);
+ return BuildDeclRefExpr(Func, NoProtoType, NameLoc, &SS);
+ }
+ }
+
+ // &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) {
+ bool isAbstractMemberPointer = (isAddressOfOperand && !SS.isEmpty());
+
+ if (!isAbstractMemberPointer && !R.empty() &&
+ isa<CXXRecordDecl>((*R.begin())->getDeclContext())) {
+ return BuildImplicitMemberReferenceExpr(SS, R, TemplateArgs);
}
}
- return BuildDeclarationNameExpr(Loc, D, HasTrailingLParen, SS, isAddressOfOperand);
+ if (TemplateArgs)
+ return BuildTemplateIdExpr(SS, R, ADL, *TemplateArgs);
+
+ return BuildDeclarationNameExpr(SS, R, ADL);
+}
+
+/// BuildQualifiedDeclarationNameExpr - Build a C++ qualified
+/// declaration name, generally during template instantiation.
+/// There's a large number of things which don't need to be done along
+/// this path.
+Sema::OwningExprResult
+Sema::BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS,
+ DeclarationName Name,
+ SourceLocation NameLoc) {
+ DeclContext *DC;
+ if (!(DC = computeDeclContext(SS, false)) ||
+ DC->isDependentContext() ||
+ RequireCompleteDeclContext(SS))
+ return BuildDependentDeclRefExpr(SS, Name, NameLoc, 0);
+
+ LookupResult R(*this, Name, NameLoc, LookupOrdinaryName);
+ LookupQualifiedName(R, DC);
+
+ if (R.isAmbiguous())
+ return ExprError();
+
+ if (R.empty()) {
+ Diag(NameLoc, diag::err_no_member) << Name << DC << SS.getRange();
+ return ExprError();
+ }
+
+ return BuildDeclarationNameExpr(SS, R, /*ADL*/ false);
}
+
+/// LookupInObjCMethod - The parser has read a name in, and Sema has
+/// detected that we're currently inside an ObjC method. Perform some
+/// additional lookup.
+///
+/// Ideally, most of this would be done by lookup, but there's
+/// actually quite a lot of extra work involved.
+///
+/// Returns a null sentinel to indicate trivial success.
+Sema::OwningExprResult
+Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
+ IdentifierInfo *II) {
+ SourceLocation Loc = Lookup.getNameLoc();
+
+ // There are two cases to handle here. 1) scoped lookup could have failed,
+ // in which case we should look for an ivar. 2) scoped lookup could have
+ // found a decl, but that decl is outside the current instance method (i.e.
+ // a global variable). In these two cases, we do a lookup for an ivar with
+ // this name, if the lookup sucedes, we replace it our current decl.
+
+ // If we're in a class method, we don't normally want to look for
+ // ivars. But if we don't find anything else, and there's an
+ // ivar, that's an error.
+ bool IsClassMethod = getCurMethodDecl()->isClassMethod();
+
+ bool LookForIvars;
+ if (Lookup.empty())
+ LookForIvars = true;
+ else if (IsClassMethod)
+ LookForIvars = false;
+ else
+ LookForIvars = (Lookup.isSingleResult() &&
+ Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod());
+
+ if (LookForIvars) {
+ ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
+ ObjCInterfaceDecl *ClassDeclared;
+ if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
+ // Diagnose using an ivar in a class method.
+ if (IsClassMethod)
+ return ExprError(Diag(Loc, diag::error_ivar_use_in_class_method)
+ << IV->getDeclName());
+
+ // If we're referencing an invalid decl, just return this as a silent
+ // error node. The error diagnostic was already emitted on the decl.
+ if (IV->isInvalidDecl())
+ return ExprError();
+
+ // Check if referencing a field with __attribute__((deprecated)).
+ if (DiagnoseUseOfDecl(IV, Loc))
+ return ExprError();
+
+ // Diagnose the use of an ivar outside of the declaring class.
+ if (IV->getAccessControl() == ObjCIvarDecl::Private &&
+ ClassDeclared != IFace)
+ Diag(Loc, diag::error_private_ivar_access) << IV->getDeclName();
+
+ // FIXME: This should use a new expr for a direct reference, don't
+ // turn this into Self->ivar, just return a BareIVarExpr or something.
+ IdentifierInfo &II = Context.Idents.get("self");
+ UnqualifiedId SelfName;
+ SelfName.setIdentifier(&II, SourceLocation());
+ CXXScopeSpec SelfScopeSpec;
+ OwningExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec,
+ SelfName, false, false);
+ MarkDeclarationReferenced(Loc, IV);
+ return Owned(new (Context)
+ ObjCIvarRefExpr(IV, IV->getType(), Loc,
+ SelfExpr.takeAs<Expr>(), true, true));
+ }
+ } else if (getCurMethodDecl()->isInstanceMethod()) {
+ // We should warn if a local variable hides an ivar.
+ ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
+ ObjCInterfaceDecl *ClassDeclared;
+ if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
+ if (IV->getAccessControl() != ObjCIvarDecl::Private ||
+ IFace == ClassDeclared)
+ Diag(Loc, diag::warn_ivar_use_hidden) << IV->getDeclName();
+ }
+ }
+
+ // Needed to implement property "super.method" notation.
+ if (Lookup.empty() && II->isStr("super")) {
+ QualType T;
+
+ if (getCurMethodDecl()->isInstanceMethod())
+ T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType(
+ getCurMethodDecl()->getClassInterface()));
+ else
+ T = Context.getObjCClassType();
+ return Owned(new (Context) ObjCSuperExpr(Loc, T));
+ }
+
+ // Sentinel value saying that we didn't do anything special.
+ return Owned((Expr*) 0);
+}
+
/// \brief Cast member's object to its own class if necessary.
bool
Sema::PerformObjectMemberConversion(Expr *&From, NamedDecl *Member) {
@@ -874,114 +1027,224 @@ 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,
- SourceLocation Loc, QualType Ty) {
- if (SS && SS->isSet())
- return MemberExpr::Create(C, Base, isArrow,
- (NestedNameSpecifier *)SS->getScopeRep(),
- SS->getRange(), Member, Loc,
- // FIXME: Explicit template argument lists
- false, SourceLocation(), 0, 0, SourceLocation(),
- Ty);
-
- return new (C) MemberExpr(Base, isArrow, Member, Loc, Ty);
+ const CXXScopeSpec &SS, NamedDecl *Member,
+ SourceLocation Loc, QualType Ty,
+ const TemplateArgumentListInfo *TemplateArgs = 0) {
+ NestedNameSpecifier *Qualifier = 0;
+ SourceRange QualifierRange;
+ if (SS.isSet()) {
+ Qualifier = (NestedNameSpecifier *) SS.getScopeRep();
+ QualifierRange = SS.getRange();
+ }
+
+ return MemberExpr::Create(C, Base, isArrow, Qualifier, QualifierRange,
+ Member, Loc, TemplateArgs, Ty);
}
-/// \brief Complete semantic analysis for a reference to the given declaration.
-Sema::OwningExprResult
-Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
- bool HasTrailingLParen,
- const CXXScopeSpec *SS,
- bool isAddressOfOperand) {
- assert(D && "Cannot refer to a NULL declaration");
- DeclarationName Name = D->getDeclName();
+/// 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 this is an expression of the form &Class::member, don't build an
- // implicit member ref, because we want a pointer to the member in general,
- // not any specific instance's member.
- if (isAddressOfOperand && SS && !SS->isEmpty() && !HasTrailingLParen) {
- DeclContext *DC = computeDeclContext(*SS);
- if (D && isa<CXXRecordDecl>(DC)) {
- QualType DType;
- if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
- DType = FD->getType().getNonReferenceType();
- } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
- DType = Method->getType();
- } else if (isa<OverloadedFunctionDecl>(D)) {
- DType = Context.OverloadTy;
- }
- // Could be an inner type. That's diagnosed below, so ignore it here.
- if (!DType.isNull()) {
- // The pointer is type- and value-dependent if it points into something
- // dependent.
- bool Dependent = DC->isDependentContext();
- return BuildDeclRefExpr(D, DType, Loc, Dependent, Dependent, SS);
- }
- }
+ 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.
+Sema::OwningExprResult
+Sema::BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ assert(!R.empty() && !R.isAmbiguous());
+
+ SourceLocation Loc = R.getNameLoc();
+
// We may have found a field within an anonymous union or struct
// (C++ [class.union]).
// FIXME: This needs to happen post-isImplicitMemberReference?
- if (FieldDecl *FD = dyn_cast<FieldDecl>(D))
+ // FIXME: template-ids inside anonymous structs?
+ if (FieldDecl *FD = R.getAsSingle<FieldDecl>())
if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion())
return BuildAnonymousStructUnionMemberReference(Loc, FD);
- // Cope with an implicit member access in a C++ non-static member function.
- QualType ThisType, MemberType;
- if (isImplicitMemberReference(SS, D, Loc, ThisType, MemberType)) {
+ QualType ThisType;
+ if (isImplicitMemberReference(R, ThisType)) {
Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType);
- MarkDeclarationReferenced(Loc, D);
- if (PerformObjectMemberConversion(This, D))
- return ExprError();
-
- bool ShouldCheckUse = true;
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
- // Don't diagnose the use of a virtual member function unless it's
- // explicitly qualified.
- if (MD->isVirtual() && (!SS || !SS->isSet()))
- ShouldCheckUse = false;
- }
-
- if (ShouldCheckUse && DiagnoseUseOfDecl(D, Loc))
- return ExprError();
- return Owned(BuildMemberExpr(Context, This, true, SS, D,
- Loc, MemberType));
+ return BuildMemberReferenceExpr(ExprArg(*this, This),
+ /*OpLoc*/ SourceLocation(),
+ /*IsArrow*/ true,
+ SS, R, TemplateArgs);
}
- if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+ // 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())
+ if (MD->isStatic()) {
// "invalid use of member 'x' in static member function"
- return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method)
- << FD->getDeclName());
+ 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.
- return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use)
- << FD->getDeclName());
- }
-
- if (isa<TypedefDecl>(D))
- return ExprError(Diag(Loc, diag::err_unexpected_typedef) << Name);
- if (isa<ObjCInterfaceDecl>(D))
- return ExprError(Diag(Loc, diag::err_unexpected_interface) << Name);
- if (isa<NamespaceDecl>(D))
- return ExprError(Diag(Loc, diag::err_unexpected_namespace) << Name);
-
- // Make the DeclRefExpr or BlockDeclRefExpr for the decl.
- if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D))
- return BuildDeclRefExpr(Ovl, Context.OverloadTy, Loc,
- false, false, SS);
- else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
- return BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
- false, false, SS);
- else if (UnresolvedUsingValueDecl *UD = dyn_cast<UnresolvedUsingValueDecl>(D))
- return BuildDeclRefExpr(UD, Context.DependentTy, Loc,
- /*TypeDependent=*/true,
- /*ValueDependent=*/true, SS);
+ Diag(Loc, diag::err_invalid_non_static_member_use)
+ << R.getLookupName();
+ return ExprError();
+ }
+
+ // 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);
+}
+
+bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
+ const LookupResult &R,
+ bool HasTrailingLParen) {
+ // Only when used directly as the postfix-expression of a call.
+ if (!HasTrailingLParen)
+ return false;
+
+ // Never if a scope specifier was provided.
+ if (SS.isSet())
+ return false;
+
+ // Only in C++ or ObjC++.
+ if (!getLangOptions().CPlusPlus)
+ return false;
+
+ // Turn off ADL when we find certain kinds of declarations during
+ // normal lookup:
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ NamedDecl *D = *I;
+
+ // C++0x [basic.lookup.argdep]p3:
+ // -- a declaration of a class member
+ // Since using decls preserve this property, we check this on the
+ // original decl.
+ if (D->getDeclContext()->isRecord())
+ return false;
+
+ // C++0x [basic.lookup.argdep]p3:
+ // -- a block-scope function declaration that is not a
+ // using-declaration
+ // NOTE: we also trigger this for function templates (in fact, we
+ // don't check the decl type at all, since all other decl types
+ // turn off ADL anyway).
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+ else if (D->getDeclContext()->isFunctionOrMethod())
+ return false;
+
+ // C++0x [basic.lookup.argdep]p3:
+ // -- a declaration that is neither a function or a function
+ // template
+ // And also for builtin functions.
+ if (isa<FunctionDecl>(D)) {
+ FunctionDecl *FDecl = cast<FunctionDecl>(D);
+
+ // But also builtin functions.
+ if (FDecl->getBuiltinID() && FDecl->isImplicit())
+ return false;
+ } else if (!isa<FunctionTemplateDecl>(D))
+ return false;
+ }
+
+ return true;
+}
+
+
+/// Diagnoses obvious problems with the use of the given declaration
+/// as an expression. This is only actually called for lookups that
+/// were not overloaded, and it doesn't promise that the declaration
+/// will in fact be used.
+static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D) {
+ if (isa<TypedefDecl>(D)) {
+ S.Diag(Loc, diag::err_unexpected_typedef) << D->getDeclName();
+ return true;
+ }
+
+ if (isa<ObjCInterfaceDecl>(D)) {
+ S.Diag(Loc, diag::err_unexpected_interface) << D->getDeclName();
+ return true;
+ }
+
+ if (isa<NamespaceDecl>(D)) {
+ S.Diag(Loc, diag::err_unexpected_namespace) << D->getDeclName();
+ return true;
+ }
+
+ return false;
+}
+
+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())
+ return BuildDeclarationNameExpr(SS, R.getNameLoc(), R.getFoundDecl());
+
+ // We only need to check the declaration if there's exactly one
+ // result, because in the overloaded case the results can only be
+ // functions and function templates.
+ if (R.isSingleResult() &&
+ CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl()))
+ return ExprError();
+
+ bool Dependent
+ = UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), 0);
+ UnresolvedLookupExpr *ULE
+ = UnresolvedLookupExpr::Create(Context, Dependent,
+ (NestedNameSpecifier*) SS.getScopeRep(),
+ SS.getRange(),
+ R.getLookupName(), R.getNameLoc(),
+ NeedsADL, R.isOverloadedResult());
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
+ ULE->addDecl(*I);
+
+ return Owned(ULE);
+}
+
+
+/// \brief Complete semantic analysis for a reference to the given declaration.
+Sema::OwningExprResult
+Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
+ SourceLocation Loc, NamedDecl *D) {
+ assert(D && "Cannot refer to a NULL declaration");
+ assert(!isa<FunctionTemplateDecl>(D) &&
+ "Cannot refer unambiguously to a function template");
+ DeclarationName Name = D->getDeclName();
+
+ if (CheckDeclInExpr(*this, Loc, D))
+ return ExprError();
ValueDecl *VD = cast<ValueDecl>(D);
@@ -989,9 +1252,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
// this check when we're going to perform argument-dependent lookup
// on this function name, because this might not be the function
// that overload resolution actually selects.
- bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
- HasTrailingLParen;
- if (!(ADL && isa<FunctionDecl>(VD)) && DiagnoseUseOfDecl(VD, Loc))
+ if (DiagnoseUseOfDecl(VD, Loc))
return ExprError();
// Only create DeclRefExpr's for valid Decl's.
@@ -1023,57 +1284,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
// If this reference is not in a block or if the referenced variable is
// within the block, create a normal DeclRefExpr.
- bool TypeDependent = false;
- bool ValueDependent = false;
- if (getLangOptions().CPlusPlus) {
- // C++ [temp.dep.expr]p3:
- // An id-expression is type-dependent if it contains:
- // - an identifier that was declared with a dependent type,
- if (VD->getType()->isDependentType())
- TypeDependent = true;
- // - FIXME: a template-id that is dependent,
- // - a conversion-function-id that specifies a dependent type,
- else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
- Name.getCXXNameType()->isDependentType())
- TypeDependent = true;
- // - a nested-name-specifier that contains a class-name that
- // names a dependent type.
- else if (SS && !SS->isEmpty()) {
- for (DeclContext *DC = computeDeclContext(*SS);
- DC; DC = DC->getParent()) {
- // FIXME: could stop early at namespace scope.
- if (DC->isRecord()) {
- CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
- if (Context.getTypeDeclType(Record)->isDependentType()) {
- TypeDependent = true;
- break;
- }
- }
- }
- }
-
- // C++ [temp.dep.constexpr]p2:
- //
- // An identifier is value-dependent if it is:
- // - a name declared with a dependent type,
- if (TypeDependent)
- ValueDependent = true;
- // - the name of a non-type template parameter,
- else if (isa<NonTypeTemplateParmDecl>(VD))
- ValueDependent = true;
- // - a constant with integral or enumeration type and is
- // initialized with an expression that is value-dependent
- else if (const VarDecl *Dcl = dyn_cast<VarDecl>(VD)) {
- if (Context.getCanonicalType(Dcl->getType()).getCVRQualifiers()
- == Qualifiers::Const &&
- Dcl->getInit()) {
- ValueDependent = Dcl->getInit()->isValueDependent();
- }
- }
- }
-
- return BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc,
- TypeDependent, ValueDependent, SS);
+ return BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc, &SS);
}
Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
@@ -1281,6 +1492,13 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType,
if (exprType->isDependentType())
return false;
+ // C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
+ // the result is the size of the referenced type."
+ // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
+ // result shall be the alignment of the referenced type."
+ if (const ReferenceType *Ref = exprType->getAs<ReferenceType>())
+ exprType = Ref->getPointeeType();
+
// C99 6.5.3.4p1:
if (exprType->isFunctionType()) {
// alignof(function) is allowed as an extension.
@@ -1733,33 +1951,318 @@ static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy,
return GDecl;
}
-Action::OwningExprResult
-Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
- tok::TokenKind OpKind, SourceLocation MemberLoc,
- DeclarationName MemberName,
- bool HasExplicitTemplateArgs,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
- SourceLocation RAngleLoc,
- DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS,
- NamedDecl *FirstQualifierInScope) {
- if (SS && SS->isInvalid())
+Sema::OwningExprResult
+Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc,
+ const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
+ DeclarationName Name, SourceLocation NameLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ Expr *BaseExpr = Base.takeAs<Expr>();
+
+ // Even in dependent contexts, try to diagnose base expressions with
+ // obviously wrong types, e.g.:
+ //
+ // T* t;
+ // t.f;
+ //
+ // In Obj-C++, however, the above expression is valid, since it could be
+ // 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>();
+ if (PT && (!getLangOptions().ObjC1 ||
+ PT->getPointeeType()->isRecordType())) {
+ Diag(NameLoc, diag::err_typecheck_member_reference_struct_union)
+ << BaseExpr->getType() << BaseExpr->getSourceRange();
+ return ExprError();
+ }
+ }
+
+ assert(BaseExpr->getType()->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,
+ IsArrow, OpLoc,
+ static_cast<NestedNameSpecifier*>(SS.getScopeRep()),
+ SS.getRange(),
+ FirstQualifierInScope,
+ Name, NameLoc,
+ TemplateArgs));
+}
+
+/// We know that the given qualified member reference points only to
+/// declarations which do not belong to the static type of the base
+/// expression. Diagnose the problem.
+static void DiagnoseQualifiedMemberReference(Sema &SemaRef,
+ Expr *BaseExpr,
+ QualType BaseType,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ const LookupResult &R) {
+ DeclContext *DC = R.getRepresentativeDecl()->getDeclContext();
+
+ // FIXME: this is an exceedingly lame diagnostic for some of the more
+ // complicated cases here.
+ SemaRef.Diag(R.getNameLoc(), diag::err_not_direct_base_or_virtual)
+ << QualifierRange << DC << BaseType;
+}
+
+// Check whether the declarations we found through a nested-name
+// specifier in a member expression are actually members of the base
+// type. The restriction here is:
+//
+// C++ [expr.ref]p2:
+// ... In these cases, the id-expression shall name a
+// member of the class or of one of its base classes.
+//
+// So it's perfectly legitimate for the nested-name specifier to name
+// an unrelated class, and for us to find an overload set including
+// decls from classes which are not superclasses, as long as the decl
+// we actually pick through overload resolution is from a superclass.
+bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
+ QualType BaseType,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ const LookupResult &R) {
+ QualType BaseTypeCanon
+ = Context.getCanonicalType(BaseType).getUnqualifiedType();
+
+ bool FoundValid = false;
+
+ 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 (BaseTypeCanon == MemberTypeCanon ||
+ IsDerivedFrom(BaseTypeCanon, MemberTypeCanon)) {
+ FoundValid = true;
+ break;
+ }
+ }
+
+ if (!FoundValid) {
+ DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType,
+ Qualifier, QualifierRange, R);
+ return true;
+ }
+
+ return false;
+}
+
+Sema::OwningExprResult
+Sema::BuildMemberReferenceExpr(ExprArg BaseArg,
+ SourceLocation OpLoc, bool IsArrow,
+ const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
+ DeclarationName Name, SourceLocation NameLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ Expr *Base = BaseArg.takeAs<Expr>();
+
+ if (Base->getType()->isDependentType())
+ return ActOnDependentMemberExpr(ExprArg(*this, Base),
+ 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();
+ }
- // Since this might be a postfix expression, get rid of ParenListExprs.
- Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
+ if (Result.get())
+ return move(Result);
+
+ return BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc,
+ IsArrow, SS, R, TemplateArgs);
+}
+Sema::OwningExprResult
+Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc,
+ bool IsArrow, const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs) {
Expr *BaseExpr = Base.takeAs<Expr>();
+ QualType BaseType = BaseExpr->getType();
+ if (IsArrow) {
+ assert(BaseType->isPointerType());
+ BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+ }
+
+ NestedNameSpecifier *Qualifier =
+ static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+ DeclarationName MemberName = R.getLookupName();
+ SourceLocation MemberLoc = R.getNameLoc();
+
+ if (R.isAmbiguous())
+ return ExprError();
+
+ if (R.empty()) {
+ // Rederive where we looked up.
+ DeclContext *DC = (SS.isSet()
+ ? computeDeclContext(SS, false)
+ : BaseType->getAs<RecordType>()->getDecl());
+
+ Diag(R.getNameLoc(), diag::err_no_member)
+ << MemberName << DC << BaseExpr->getSourceRange();
+ 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))
+ 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);
+
+ UnresolvedMemberExpr *MemExpr
+ = UnresolvedMemberExpr::Create(Context, Dependent,
+ R.isUnresolvableResult(),
+ BaseExpr, IsArrow, OpLoc,
+ Qualifier, SS.getRange(),
+ MemberName, MemberLoc,
+ TemplateArgs);
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
+ MemExpr->addDecl(*I);
+
+ return Owned(MemExpr);
+ }
+
+ assert(R.isSingleResult());
+ NamedDecl *MemberDecl = R.getFoundDecl();
+
+ // FIXME: diagnose the presence of template arguments now.
+
+ // If the decl being referenced had an error, return an error for this
+ // sub-expr without emitting another error, in order to avoid cascading
+ // error cases.
+ if (MemberDecl->isInvalidDecl())
+ return ExprError();
+
+ bool ShouldCheckUse = true;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) {
+ // Don't diagnose the use of a virtual member function unless it's
+ // explicitly qualified.
+ if (MD->isVirtual() && !SS.isSet())
+ ShouldCheckUse = false;
+ }
+
+ // Check the use of this member.
+ if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) {
+ Owned(BaseExpr);
+ return ExprError();
+ }
+
+ 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())
+ return BuildAnonymousStructUnionMemberReference(MemberLoc, FD,
+ BaseExpr, OpLoc);
+
+ // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
+ QualType MemberType = FD->getType();
+ if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>())
+ MemberType = Ref->getPointeeType();
+ else {
+ Qualifiers BaseQuals = BaseType.getQualifiers();
+ BaseQuals.removeObjCGCAttr();
+ if (FD->isMutable()) BaseQuals.removeConst();
+
+ Qualifiers MemberQuals
+ = Context.getCanonicalType(MemberType).getQualifiers();
+
+ Qualifiers Combined = BaseQuals + MemberQuals;
+ if (Combined != MemberQuals)
+ MemberType = Context.getQualifiedType(MemberType, Combined);
+ }
+
+ MarkDeclarationReferenced(MemberLoc, FD);
+ if (PerformObjectMemberConversion(BaseExpr, FD))
+ return ExprError();
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ FD, MemberLoc, MemberType));
+ }
+
+ if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
+ MarkDeclarationReferenced(MemberLoc, Var);
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ Var, MemberLoc,
+ Var->getType().getNonReferenceType()));
+ }
+
+ if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) {
+ MarkDeclarationReferenced(MemberLoc, MemberDecl);
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ MemberFn, MemberLoc,
+ MemberFn->getType()));
+ }
+
+ if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
+ MarkDeclarationReferenced(MemberLoc, MemberDecl);
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ Enum, MemberLoc, Enum->getType()));
+ }
+
+ Owned(BaseExpr);
+
+ if (isa<TypeDecl>(MemberDecl))
+ return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type)
+ << MemberName << int(IsArrow));
+
+ // We found a declaration kind that we didn't expect. This is a
+ // generic error message that tells the user that she can't refer
+ // to this member with '.' or '->'.
+ return ExprError(Diag(MemberLoc,
+ diag::err_typecheck_member_reference_unknown)
+ << MemberName << int(IsArrow));
+}
+
+/// Look up the given member of the given non-type-dependent
+/// expression. This can return in one of two ways:
+/// * If it returns a sentinel null-but-valid result, the caller will
+/// assume that lookup was performed and the results written into
+/// the provided structure. It will take over from there.
+/// * Otherwise, the returned expression will be produced in place of
+/// an ordinary member expression.
+///
+/// The ObjCImpDecl bit is a gross hack that will need to be properly
+/// fixed for ObjC++.
+Sema::OwningExprResult
+Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
+ bool IsArrow, SourceLocation OpLoc,
+ const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
+ DeclPtrTy ObjCImpDecl) {
assert(BaseExpr && "no base expression");
// Perform default conversions.
DefaultFunctionArrayConversion(BaseExpr);
QualType BaseType = BaseExpr->getType();
+ assert(!BaseType->isDependentType());
+
+ DeclarationName MemberName = R.getLookupName();
+ SourceLocation MemberLoc = R.getNameLoc();
// If the user is trying to apply -> or . to a function pointer
- // type, it's probably because the forgot parentheses to call that
+ // type, it's probably because they forgot parentheses to call that
// function. Suggest the addition of those parentheses, build the
// call, and continue on.
if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
@@ -1767,8 +2270,8 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
= Ptr->getPointeeType()->getAs<FunctionProtoType>()) {
QualType ResultTy = Fun->getResultType();
if (Fun->getNumArgs() == 0 &&
- ((OpKind == tok::period && ResultTy->isRecordType()) ||
- (OpKind == tok::arrow && ResultTy->isPointerType() &&
+ ((!IsArrow && ResultTy->isRecordType()) ||
+ (IsArrow && ResultTy->isPointerType() &&
ResultTy->getAs<PointerType>()->getPointeeType()
->isRecordType()))) {
SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd());
@@ -1777,10 +2280,10 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
<< CodeModificationHint::CreateInsertion(Loc, "()");
OwningExprResult NewBase
- = ActOnCallExpr(S, ExprArg(*this, BaseExpr), Loc,
+ = ActOnCallExpr(0, ExprArg(*this, BaseExpr), Loc,
MultiExprArg(*this, 0, 0), 0, Loc);
if (NewBase.isInvalid())
- return move(NewBase);
+ return ExprError();
BaseExpr = NewBase.takeAs<Expr>();
DefaultFunctionArrayConversion(BaseExpr);
@@ -1799,10 +2302,22 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast);
}
}
+
+ // If this is an Objective-C pseudo-builtin and a definition is provided then
+ // use that.
+ if (Context.isObjCSelType(BaseType)) {
+ // We have an 'SEL' type. Rather than fall through, we check if this
+ // is a reference to 'sel_id'.
+ if (BaseType != Context.ObjCSelRedefinitionType) {
+ BaseType = Context.ObjCSelRedefinitionType;
+ ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast);
+ }
+ }
+
assert(!BaseType.isNull() && "no type for member expression");
// Handle properties on ObjC 'Class' types.
- if (OpKind == tok::period && BaseType->isObjCClassType()) {
+ if (!IsArrow && BaseType->isObjCClassType()) {
// Also must look for a getter name which uses property syntax.
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
@@ -1856,76 +2371,21 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
BaseType = Context.ObjCClassRedefinitionType;
ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast);
}
-
- // 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.
- if (OpKind == tok::arrow) {
- if (BaseType->isDependentType()) {
- NestedNameSpecifier *Qualifier = 0;
- if (SS) {
- Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
- if (!FirstQualifierInScope)
- FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
- }
- return Owned(CXXUnresolvedMemberExpr::Create(Context, BaseExpr, true,
- OpLoc, Qualifier,
- SS? SS->getRange() : SourceRange(),
- FirstQualifierInScope,
- MemberName,
- MemberLoc,
- HasExplicitTemplateArgs,
- LAngleLoc,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
- RAngleLoc));
- }
- else if (const PointerType *PT = BaseType->getAs<PointerType>())
+ if (IsArrow) {
+ if (const PointerType *PT = BaseType->getAs<PointerType>())
BaseType = PT->getPointeeType();
else if (BaseType->isObjCObjectPointerType())
;
- else
- return ExprError(Diag(MemberLoc,
- diag::err_typecheck_member_reference_arrow)
- << BaseType << BaseExpr->getSourceRange());
- } else if (BaseType->isDependentType()) {
- // Require that the base type isn't a pointer type
- // (so we'll report an error for)
- // T* t;
- // t.f;
- //
- // In Obj-C++, however, the above expression is valid, since it could be
- // 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.
- const PointerType *PT = BaseType->getAs<PointerType>();
-
- if (!PT || (getLangOptions().ObjC1 &&
- !PT->getPointeeType()->isRecordType())) {
- NestedNameSpecifier *Qualifier = 0;
- if (SS) {
- Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
- if (!FirstQualifierInScope)
- FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
- }
-
- return Owned(CXXUnresolvedMemberExpr::Create(Context,
- BaseExpr, false,
- OpLoc,
- Qualifier,
- SS? SS->getRange() : SourceRange(),
- FirstQualifierInScope,
- MemberName,
- MemberLoc,
- HasExplicitTemplateArgs,
- LAngleLoc,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
- RAngleLoc));
- }
+ else {
+ Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
+ << BaseType << BaseExpr->getSourceRange();
+ return ExprError();
}
+ }
- // Handle field access to simple records. This also handles access to fields
- // of the ObjC 'id' struct.
+ // 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,
@@ -1934,155 +2394,25 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
return ExprError();
DeclContext *DC = RDecl;
- if (SS && SS->isSet()) {
+ if (SS.isSet()) {
// If the member name was a qualified-id, look into the
// nested-name-specifier.
- DC = computeDeclContext(*SS, false);
+ DC = computeDeclContext(SS, false);
if (!isa<TypeDecl>(DC)) {
Diag(MemberLoc, diag::err_qualified_member_nonclass)
- << DC << SS->getRange();
+ << DC << SS.getRange();
return ExprError();
}
// FIXME: If DC is not computable, we should build a
- // CXXUnresolvedMemberExpr.
+ // CXXDependentScopeMemberExpr.
assert(DC && "Cannot handle non-computable dependent contexts in lookup");
}
// The record definition is complete, now make sure the member is valid.
- LookupResult Result(*this, MemberName, MemberLoc, LookupMemberName);
- LookupQualifiedName(Result, DC);
-
- if (Result.empty())
- return ExprError(Diag(MemberLoc, diag::err_no_member)
- << MemberName << DC << BaseExpr->getSourceRange());
- if (Result.isAmbiguous())
- return ExprError();
-
- NamedDecl *MemberDecl = Result.getAsSingleDecl(Context);
-
- if (SS && SS->isSet()) {
- TypeDecl* TyD = cast<TypeDecl>(MemberDecl->getDeclContext());
- QualType BaseTypeCanon
- = Context.getCanonicalType(BaseType).getUnqualifiedType();
- QualType MemberTypeCanon
- = Context.getCanonicalType(Context.getTypeDeclType(TyD));
-
- if (BaseTypeCanon != MemberTypeCanon &&
- !IsDerivedFrom(BaseTypeCanon, MemberTypeCanon))
- return ExprError(Diag(SS->getBeginLoc(),
- diag::err_not_direct_base_or_virtual)
- << MemberTypeCanon << BaseTypeCanon);
- }
-
- // If the decl being referenced had an error, return an error for this
- // sub-expr without emitting another error, in order to avoid cascading
- // error cases.
- if (MemberDecl->isInvalidDecl())
- return ExprError();
-
- bool ShouldCheckUse = true;
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) {
- // Don't diagnose the use of a virtual member function unless it's
- // explicitly qualified.
- if (MD->isVirtual() && (!SS || !SS->isSet()))
- ShouldCheckUse = false;
- }
-
- // Check the use of this field
- if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc))
- return ExprError();
-
- 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())
- return BuildAnonymousStructUnionMemberReference(MemberLoc, FD,
- BaseExpr, OpLoc);
-
- // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
- QualType MemberType = FD->getType();
- if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>())
- MemberType = Ref->getPointeeType();
- else {
- Qualifiers BaseQuals = BaseType.getQualifiers();
- BaseQuals.removeObjCGCAttr();
- if (FD->isMutable()) BaseQuals.removeConst();
-
- Qualifiers MemberQuals
- = Context.getCanonicalType(MemberType).getQualifiers();
-
- Qualifiers Combined = BaseQuals + MemberQuals;
- if (Combined != MemberQuals)
- MemberType = Context.getQualifiedType(MemberType, Combined);
- }
-
- MarkDeclarationReferenced(MemberLoc, FD);
- if (PerformObjectMemberConversion(BaseExpr, FD))
- return ExprError();
- return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
- FD, MemberLoc, MemberType));
- }
-
- if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
- Var, MemberLoc,
- Var->getType().getNonReferenceType()));
- }
- if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
- MemberFn, MemberLoc,
- MemberFn->getType()));
- }
- if (FunctionTemplateDecl *FunTmpl
- = dyn_cast<FunctionTemplateDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
-
- if (HasExplicitTemplateArgs)
- return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow,
- (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
- SS? SS->getRange() : SourceRange(),
- FunTmpl, MemberLoc, true,
- LAngleLoc, ExplicitTemplateArgs,
- NumExplicitTemplateArgs, RAngleLoc,
- Context.OverloadTy));
-
- return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
- FunTmpl, MemberLoc,
- Context.OverloadTy));
- }
- if (OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(MemberDecl)) {
- if (HasExplicitTemplateArgs)
- return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow,
- (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
- SS? SS->getRange() : SourceRange(),
- Ovl, MemberLoc, true,
- LAngleLoc, ExplicitTemplateArgs,
- NumExplicitTemplateArgs, RAngleLoc,
- Context.OverloadTy));
-
- return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
- Ovl, MemberLoc, Context.OverloadTy));
- }
- if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
- Enum, MemberLoc, Enum->getType()));
- }
- if (isa<TypeDecl>(MemberDecl))
- return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type)
- << MemberName << int(OpKind == tok::arrow));
-
- // We found a declaration kind that we didn't expect. This is a
- // generic error message that tells the user that she can't refer
- // to this member with '.' or '->'.
- return ExprError(Diag(MemberLoc,
- diag::err_typecheck_member_reference_unknown)
- << MemberName << int(OpKind == tok::arrow));
+ LookupQualifiedName(R, DC);
+ return Owned((Expr*) 0);
}
// Handle pseudo-destructors (C++ [expr.pseudo]). Since anything referring
@@ -2118,18 +2448,17 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
// FIXME: We've lost the precise spelling of the type by going through
// DeclarationName. Can we do better?
return Owned(new (Context) CXXPseudoDestructorExpr(Context, BaseExpr,
- OpKind == tok::arrow,
- OpLoc,
- (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
- SS? SS->getRange() : SourceRange(),
+ IsArrow, OpLoc,
+ (NestedNameSpecifier *) SS.getScopeRep(),
+ SS.getRange(),
MemberName.getCXXNameType(),
MemberLoc));
}
// Handle access to Objective-C instance variables, such as "Obj->ivar" and
// (*Obj).ivar.
- if ((OpKind == tok::arrow && BaseType->isObjCObjectPointerType()) ||
- (OpKind == tok::period && BaseType->isObjCInterfaceType())) {
+ if ((IsArrow && BaseType->isObjCObjectPointerType()) ||
+ (!IsArrow && BaseType->isObjCInterfaceType())) {
const ObjCObjectPointerType *OPT = BaseType->getAs<ObjCObjectPointerType>();
const ObjCInterfaceType *IFaceT =
OPT ? OPT->getInterfaceType() : BaseType->getAs<ObjCInterfaceType>();
@@ -2184,7 +2513,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
MemberLoc, BaseExpr,
- OpKind == tok::arrow));
+ IsArrow));
}
return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
<< IDecl->getDeclName() << MemberName
@@ -2192,8 +2521,8 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
}
}
// Handle properties on 'id' and qualified "id".
- if (OpKind == tok::period && (BaseType->isObjCIdType() ||
- BaseType->isObjCQualifiedIdType())) {
+ if (!IsArrow && (BaseType->isObjCIdType() ||
+ BaseType->isObjCQualifiedIdType())) {
const ObjCObjectPointerType *QIdTy = BaseType->getAs<ObjCObjectPointerType>();
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
@@ -2226,8 +2555,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
// Handle Objective-C property access, which is "Obj.property" where Obj is a
// pointer to a (potentially qualified) interface type.
const ObjCObjectPointerType *OPT;
- if (OpKind == tok::period &&
- (OPT = BaseType->getAsObjCInterfacePointerType())) {
+ if (!IsArrow && (OPT = BaseType->getAsObjCInterfacePointerType())) {
const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
ObjCInterfaceDecl *IFace = IFaceT->getDecl();
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
@@ -2312,7 +2640,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
}
// Handle the following exceptional case (*Obj).isa.
- if (OpKind == tok::period &&
+ if (!IsArrow &&
BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) &&
MemberName.getAsIdentifierInfo()->isStr("isa"))
return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc,
@@ -2334,75 +2662,105 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
return ExprError();
}
-Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg Base,
+static Sema::OwningExprResult DiagnoseDtorReference(Sema &SemaRef,
+ SourceLocation NameLoc,
+ Sema::ExprArg MemExpr) {
+ Expr *E = (Expr *) MemExpr.get();
+ SourceLocation ExpectedLParenLoc = SemaRef.PP.getLocForEndOfToken(NameLoc);
+ SemaRef.Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
+ << isa<CXXPseudoDestructorExpr>(E)
+ << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
+
+ return SemaRef.ActOnCallExpr(/*Scope*/ 0,
+ move(MemExpr),
+ /*LPLoc*/ ExpectedLParenLoc,
+ Sema::MultiExprArg(SemaRef, 0, 0),
+ /*CommaLocs*/ 0,
+ /*RPLoc*/ ExpectedLParenLoc);
+}
+
+/// The main callback when the parser finds something like
+/// expression . [nested-name-specifier] identifier
+/// expression -> [nested-name-specifier] identifier
+/// where 'identifier' encompasses a fairly broad spectrum of
+/// possibilities, including destructor and operator references.
+///
+/// \param OpKind either tok::arrow or tok::period
+/// \param HasTrailingLParen whether the next token is '(', which
+/// is used to diagnose mis-uses of special members that can
+/// only be called
+/// \param ObjCImpDecl the current ObjC @implementation decl;
+/// this is an ugly hack around the fact that ObjC @implementations
+/// aren't properly put in the context chain
+Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
SourceLocation OpLoc,
tok::TokenKind OpKind,
const CXXScopeSpec &SS,
- UnqualifiedId &Member,
+ UnqualifiedId &Id,
DeclPtrTy ObjCImpDecl,
bool HasTrailingLParen) {
- if (Member.getKind() == UnqualifiedId::IK_TemplateId) {
- TemplateName Template
- = TemplateName::getFromVoidPointer(Member.TemplateId->Template);
-
- // FIXME: We're going to end up looking up the template based on its name,
- // twice!
- DeclarationName Name;
- if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl())
- Name = ActualTemplate->getDeclName();
- else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl())
- Name = Ovl->getDeclName();
- else {
- DependentTemplateName *DTN = Template.getAsDependentTemplateName();
- if (DTN->isIdentifier())
- Name = DTN->getIdentifier();
- else
- Name = Context.DeclarationNames.getCXXOperatorName(DTN->getOperator());
+ if (SS.isSet() && SS.isInvalid())
+ return ExprError();
+
+ TemplateArgumentListInfo TemplateArgsBuffer;
+
+ // Decompose the name into its component parts.
+ DeclarationName Name;
+ SourceLocation NameLoc;
+ const TemplateArgumentListInfo *TemplateArgs;
+ DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer,
+ Name, NameLoc, TemplateArgs);
+
+ bool IsArrow = (OpKind == tok::arrow);
+
+ NamedDecl *FirstQualifierInScope
+ = (!SS.isSet() ? 0 : FindFirstQualifierInScope(S,
+ static_cast<NestedNameSpecifier*>(SS.getScopeRep())));
+
+ // This is a postfix expression, so get rid of ParenListExprs.
+ BaseArg = MaybeConvertParenListExprToParenExpr(S, move(BaseArg));
+
+ Expr *Base = BaseArg.takeAs<Expr>();
+ OwningExprResult Result(*this);
+ if (Base->getType()->isDependentType()) {
+ Result = ActOnDependentMemberExpr(ExprArg(*this, Base),
+ IsArrow, OpLoc,
+ SS, FirstQualifierInScope,
+ Name, NameLoc,
+ TemplateArgs);
+ } else {
+ LookupResult R(*this, Name, NameLoc, LookupMemberName);
+ if (TemplateArgs) {
+ // Re-use the lookup done for the template name.
+ DecomposeTemplateName(R, Id);
+ } else {
+ Result = LookupMemberExpr(R, Base, IsArrow, OpLoc,
+ SS, FirstQualifierInScope,
+ ObjCImpDecl);
+
+ if (Result.isInvalid()) {
+ Owned(Base);
+ return ExprError();
+ }
+
+ if (Result.get()) {
+ // The only way a reference to a destructor can be used is to
+ // immediately call it, which falls into this case. If the
+ // next token is not a '(', produce a diagnostic and build the
+ // call now.
+ if (!HasTrailingLParen &&
+ Id.getKind() == UnqualifiedId::IK_DestructorName)
+ return DiagnoseDtorReference(*this, NameLoc, move(Result));
+
+ return move(Result);
+ }
}
-
- // Translate the parser's template argument list in our AST format.
- ASTTemplateArgsPtr TemplateArgsPtr(*this,
- Member.TemplateId->getTemplateArgs(),
- Member.TemplateId->NumArgs);
-
- llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs;
- translateTemplateArguments(TemplateArgsPtr,
- TemplateArgs);
- TemplateArgsPtr.release();
-
- // Do we have the save the actual template name? We might need it...
- return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind,
- Member.TemplateId->TemplateNameLoc,
- Name, true, Member.TemplateId->LAngleLoc,
- TemplateArgs.data(), TemplateArgs.size(),
- Member.TemplateId->RAngleLoc, DeclPtrTy(),
- &SS);
+
+ Result = BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc,
+ IsArrow, SS, R, TemplateArgs);
}
-
- // FIXME: We lose a lot of source information by mapping directly to the
- // DeclarationName.
- OwningExprResult Result
- = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind,
- Member.getSourceRange().getBegin(),
- GetNameFromUnqualifiedId(Member),
- ObjCImpDecl, &SS);
-
- if (Result.isInvalid() || HasTrailingLParen ||
- Member.getKind() != UnqualifiedId::IK_DestructorName)
- return move(Result);
-
- // The only way a reference to a destructor can be used is to
- // immediately call them. Since the next token is not a '(', produce a
- // diagnostic and build the call now.
- Expr *E = (Expr *)Result.get();
- SourceLocation ExpectedLParenLoc
- = PP.getLocForEndOfToken(Member.getSourceRange().getEnd());
- Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
- << isa<CXXPseudoDestructorExpr>(E)
- << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
-
- return ActOnCallExpr(0, move(Result), ExpectedLParenLoc,
- MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc);
+
+ return move(Result);
}
Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
@@ -2468,17 +2826,14 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
// C99 6.5.2.2p7 - the arguments are implicitly converted, as if by
// assignment, to the types of the corresponding parameter, ...
unsigned NumArgsInProto = Proto->getNumArgs();
- unsigned NumArgsToCheck = NumArgs;
bool Invalid = false;
-
+
// If too few arguments are available (and we don't have default
// arguments for the remaining parameters), don't make the call.
if (NumArgs < NumArgsInProto) {
if (!FDecl || NumArgs < FDecl->getMinRequiredArguments())
return Diag(RParenLoc, diag::err_typecheck_call_too_few_args)
<< Fn->getType()->isBlockPointerType() << Fn->getSourceRange();
- // Use default arguments for missing arguments
- NumArgsToCheck = NumArgsInProto;
Call->setNumArgs(Context, NumArgsInProto);
}
@@ -2493,25 +2848,55 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
Args[NumArgs-1]->getLocEnd());
// This deletes the extra arguments.
Call->setNumArgs(Context, NumArgsInProto);
- Invalid = true;
+ return true;
}
- NumArgsToCheck = NumArgsInProto;
}
+ llvm::SmallVector<Expr *, 8> AllArgs;
+ VariadicCallType CallType =
+ Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply;
+ if (Fn->getType()->isBlockPointerType())
+ CallType = VariadicBlock; // Block
+ else if (isa<MemberExpr>(Fn))
+ CallType = VariadicMethod;
+ Invalid = GatherArgumentsForCall(Call->getSourceRange().getBegin(), FDecl,
+ Proto, 0, Args, NumArgs, AllArgs, CallType);
+ if (Invalid)
+ return true;
+ unsigned TotalNumArgs = AllArgs.size();
+ for (unsigned i = 0; i < TotalNumArgs; ++i)
+ Call->setArg(i, AllArgs[i]);
+
+ return false;
+}
+bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
+ FunctionDecl *FDecl,
+ const FunctionProtoType *Proto,
+ unsigned FirstProtoArg,
+ Expr **Args, unsigned NumArgs,
+ llvm::SmallVector<Expr *, 8> &AllArgs,
+ VariadicCallType CallType) {
+ unsigned NumArgsInProto = Proto->getNumArgs();
+ unsigned NumArgsToCheck = NumArgs;
+ bool Invalid = false;
+ if (NumArgs != NumArgsInProto)
+ // Use default arguments for missing arguments
+ NumArgsToCheck = NumArgsInProto;
+ unsigned ArgIx = 0;
// Continue to check argument types (even if we have too few/many args).
- for (unsigned i = 0; i != NumArgsToCheck; i++) {
+ for (unsigned i = FirstProtoArg; i != NumArgsToCheck; i++) {
QualType ProtoArgType = Proto->getArgType(i);
-
+
Expr *Arg;
- if (i < NumArgs) {
- Arg = Args[i];
-
+ if (ArgIx < NumArgs) {
+ Arg = Args[ArgIx++];
+
if (RequireCompleteType(Arg->getSourceRange().getBegin(),
ProtoArgType,
PDiag(diag::err_call_incomplete_argument)
- << Arg->getSourceRange()))
+ << Arg->getSourceRange()))
return true;
-
+
// Pass the argument.
if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
return true;
@@ -2520,35 +2905,26 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
Arg = MaybeBindToTemporary(Arg).takeAs<Expr>();
} else {
ParmVarDecl *Param = FDecl->getParamDecl(i);
-
+
OwningExprResult ArgExpr =
- BuildCXXDefaultArgExpr(Call->getSourceRange().getBegin(),
- FDecl, Param);
+ BuildCXXDefaultArgExpr(CallLoc, FDecl, Param);
if (ArgExpr.isInvalid())
return true;
-
+
Arg = ArgExpr.takeAs<Expr>();
}
-
- Call->setArg(i, Arg);
+ AllArgs.push_back(Arg);
}
-
+
// If this is a variadic call, handle args passed through "...".
- if (Proto->isVariadic()) {
- VariadicCallType CallType = VariadicFunction;
- if (Fn->getType()->isBlockPointerType())
- CallType = VariadicBlock; // Block
- else if (isa<MemberExpr>(Fn))
- CallType = VariadicMethod;
-
+ if (CallType != VariadicDoesNotApply) {
// Promote the arguments (C99 6.5.2.2p7).
- for (unsigned i = NumArgsInProto; i < NumArgs; i++) {
+ for (unsigned i = ArgIx; i < NumArgs; i++) {
Expr *Arg = Args[i];
Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType);
- Call->setArg(i, Arg);
+ AllArgs.push_back(Arg);
}
}
-
return Invalid;
}
@@ -2557,22 +2933,22 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
/// whether argument-dependent lookup is available, whether it has explicit
/// template arguments, etc.
void Sema::DeconstructCallFunction(Expr *FnExpr,
- NamedDecl *&Function,
+ llvm::SmallVectorImpl<NamedDecl*> &Fns,
DeclarationName &Name,
NestedNameSpecifier *&Qualifier,
SourceRange &QualifierRange,
bool &ArgumentDependentLookup,
+ bool &Overloaded,
bool &HasExplicitTemplateArguments,
- const TemplateArgumentLoc *&ExplicitTemplateArgs,
- unsigned &NumExplicitTemplateArgs) {
+ TemplateArgumentListInfo &ExplicitTemplateArgs) {
// Set defaults for all of the output parameters.
- Function = 0;
Name = DeclarationName();
Qualifier = 0;
QualifierRange = SourceRange();
- ArgumentDependentLookup = getLangOptions().CPlusPlus;
+ ArgumentDependentLookup = false;
+ Overloaded = false;
HasExplicitTemplateArguments = false;
-
+
// If we're directly calling a function, get the appropriate declaration.
// Also, in C++, keep track of whether we should perform argument-dependent
// lookup and whether there were any explicitly-specified template arguments.
@@ -2580,59 +2956,31 @@ void Sema::DeconstructCallFunction(Expr *FnExpr,
if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(FnExpr))
FnExpr = IcExpr->getSubExpr();
else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) {
- // Parentheses around a function disable ADL
- // (C++0x [basic.lookup.argdep]p1).
- ArgumentDependentLookup = false;
FnExpr = PExpr->getSubExpr();
} else if (isa<UnaryOperator>(FnExpr) &&
cast<UnaryOperator>(FnExpr)->getOpcode()
== UnaryOperator::AddrOf) {
FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr();
} else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) {
- Function = dyn_cast<NamedDecl>(DRExpr->getDecl());
- if ((Qualifier = DRExpr->getQualifier())) {
- ArgumentDependentLookup = false;
+ Fns.push_back(cast<NamedDecl>(DRExpr->getDecl()));
+ ArgumentDependentLookup = false;
+ if ((Qualifier = DRExpr->getQualifier()))
QualifierRange = DRExpr->getQualifierRange();
- }
break;
- } else if (UnresolvedFunctionNameExpr *DepName
- = dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) {
- Name = DepName->getName();
- break;
- } else if (TemplateIdRefExpr *TemplateIdRef
- = dyn_cast<TemplateIdRefExpr>(FnExpr)) {
- Function = TemplateIdRef->getTemplateName().getAsTemplateDecl();
- if (!Function)
- Function = TemplateIdRef->getTemplateName().getAsOverloadedFunctionDecl();
- HasExplicitTemplateArguments = true;
- ExplicitTemplateArgs = TemplateIdRef->getTemplateArgs();
- NumExplicitTemplateArgs = TemplateIdRef->getNumTemplateArgs();
-
- // C++ [temp.arg.explicit]p6:
- // [Note: For simple function names, argument dependent lookup (3.4.2)
- // applies even when the function name is not visible within the
- // scope of the call. This is because the call still has the syntactic
- // form of a function call (3.4.1). But when a function template with
- // explicit template arguments is used, the call does not have the
- // correct syntactic form unless there is a function template with
- // that name visible at the point of the call. If no such name is
- // visible, the call is not syntactically well-formed and
- // argument-dependent lookup does not apply. If some such name is
- // visible, argument dependent lookup applies and additional function
- // templates may be found in other namespaces.
- //
- // The summary of this paragraph is that, if we get to this point and the
- // template-id was not a qualified name, then argument-dependent lookup
- // is still possible.
- if ((Qualifier = TemplateIdRef->getQualifier())) {
- ArgumentDependentLookup = false;
- QualifierRange = TemplateIdRef->getQualifierRange();
+ } else if (UnresolvedLookupExpr *UnresLookup
+ = dyn_cast<UnresolvedLookupExpr>(FnExpr)) {
+ Name = UnresLookup->getName();
+ Fns.append(UnresLookup->decls_begin(), UnresLookup->decls_end());
+ ArgumentDependentLookup = UnresLookup->requiresADL();
+ Overloaded = UnresLookup->isOverloaded();
+ if ((Qualifier = UnresLookup->getQualifier()))
+ QualifierRange = UnresLookup->getQualifierRange();
+ if (UnresLookup->hasExplicitTemplateArgs()) {
+ HasExplicitTemplateArguments = true;
+ UnresLookup->copyTemplateArgumentsInto(ExplicitTemplateArgs);
}
break;
} else {
- // Any kind of name that does not refer to a declaration (or
- // set of declarations) disables ADL (C++0x [basic.lookup.argdep]p3).
- ArgumentDependentLookup = false;
break;
}
}
@@ -2653,9 +3001,6 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
Expr *Fn = fn.takeAs<Expr>();
Expr **Args = reinterpret_cast<Expr**>(args.release());
assert(Fn && "no function call expression");
- FunctionDecl *FDecl = NULL;
- NamedDecl *NDecl = NULL;
- DeclarationName UnqualifiedName;
if (getLangOptions().CPlusPlus) {
// If this is a pseudo-destructor expression, build the call immediately.
@@ -2696,20 +3041,33 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc));
+ Expr *NakedFn = Fn->IgnoreParens();
+
+ // Determine whether this is a call to an unresolved member function.
+ if (UnresolvedMemberExpr *MemE = dyn_cast<UnresolvedMemberExpr>(NakedFn)) {
+ // If lookup was unresolved but not dependent (i.e. didn't find
+ // an unresolved using declaration), it has to be an overloaded
+ // function set, which means it must contain either multiple
+ // declarations (all methods or method templates) or a single
+ // method template.
+ assert((MemE->getNumDecls() > 1) ||
+ isa<FunctionTemplateDecl>(*MemE->decls_begin()));
+ (void)MemE;
+
+ return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
+ CommaLocs, RParenLoc));
+ }
+
// Determine whether this is a call to a member function.
- if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(Fn->IgnoreParens())) {
+ if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(NakedFn)) {
NamedDecl *MemDecl = MemExpr->getMemberDecl();
- if (isa<OverloadedFunctionDecl>(MemDecl) ||
- isa<CXXMethodDecl>(MemDecl) ||
- (isa<FunctionTemplateDecl>(MemDecl) &&
- isa<CXXMethodDecl>(
- cast<FunctionTemplateDecl>(MemDecl)->getTemplatedDecl())))
+ if (isa<CXXMethodDecl>(MemDecl))
return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc));
}
// Determine whether this is a call to a pointer-to-member function.
- if (BinaryOperator *BO = dyn_cast<BinaryOperator>(Fn->IgnoreParens())) {
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(NakedFn)) {
if (BO->getOpcode() == BinaryOperator::PtrMemD ||
BO->getOpcode() == BinaryOperator::PtrMemI) {
if (const FunctionProtoType *FPT =
@@ -2742,48 +3100,65 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
// If we're directly calling a function, get the appropriate declaration.
// Also, in C++, keep track of whether we should perform argument-dependent
// lookup and whether there were any explicitly-specified template arguments.
- bool ADL = true;
+ llvm::SmallVector<NamedDecl*,8> Fns;
+ DeclarationName UnqualifiedName;
+ bool Overloaded;
+ bool ADL;
bool HasExplicitTemplateArgs = 0;
- const TemplateArgumentLoc *ExplicitTemplateArgs = 0;
- unsigned NumExplicitTemplateArgs = 0;
+ TemplateArgumentListInfo ExplicitTemplateArgs;
NestedNameSpecifier *Qualifier = 0;
SourceRange QualifierRange;
- DeconstructCallFunction(Fn, NDecl, UnqualifiedName, Qualifier, QualifierRange,
- ADL,HasExplicitTemplateArgs, ExplicitTemplateArgs,
- NumExplicitTemplateArgs);
-
- OverloadedFunctionDecl *Ovl = 0;
- FunctionTemplateDecl *FunctionTemplate = 0;
- if (NDecl) {
- FDecl = dyn_cast<FunctionDecl>(NDecl);
- if ((FunctionTemplate = dyn_cast<FunctionTemplateDecl>(NDecl)))
- FDecl = FunctionTemplate->getTemplatedDecl();
- else
- FDecl = dyn_cast<FunctionDecl>(NDecl);
- Ovl = dyn_cast<OverloadedFunctionDecl>(NDecl);
- }
-
- if (Ovl || FunctionTemplate ||
- (getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
- // We don't perform ADL for implicit declarations of builtins.
- if (FDecl && FDecl->getBuiltinID() && FDecl->isImplicit())
- ADL = false;
-
- // We don't perform ADL in C.
- if (!getLangOptions().CPlusPlus)
- ADL = false;
-
- if (Ovl || FunctionTemplate || ADL) {
- FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName,
- HasExplicitTemplateArgs,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
- LParenLoc, Args, NumArgs, CommaLocs,
- RParenLoc, ADL);
- if (!FDecl)
- return ExprError();
+ DeconstructCallFunction(Fn, Fns, UnqualifiedName, Qualifier, QualifierRange,
+ ADL, Overloaded, HasExplicitTemplateArgs,
+ ExplicitTemplateArgs);
+
+ NamedDecl *NDecl; // the specific declaration we're calling, if applicable
+ FunctionDecl *FDecl; // same, if it's known to be a function
+
+ if (Overloaded || ADL) {
+#ifndef NDEBUG
+ if (ADL) {
+ // To do ADL, we must have found an unqualified name.
+ assert(UnqualifiedName && "found no unqualified name for ADL");
+
+ // We don't perform ADL for implicit declarations of builtins.
+ // Verify that this was correctly set up.
+ if (Fns.size() == 1 && (FDecl = dyn_cast<FunctionDecl>(Fns[0])) &&
+ FDecl->getBuiltinID() && FDecl->isImplicit())
+ assert(0 && "performing ADL for builtin");
+
+ // We don't perform ADL in C.
+ assert(getLangOptions().CPlusPlus && "ADL enabled in C");
+ }
+
+ if (Overloaded) {
+ // To be overloaded, we must either have multiple functions or
+ // at least one function template (which is effectively an
+ // infinite set of functions).
+ assert((Fns.size() > 1 ||
+ (Fns.size() == 1 &&
+ isa<FunctionTemplateDecl>(Fns[0]->getUnderlyingDecl())))
+ && "unrecognized overload situation");
+ }
+#endif
+
+ FDecl = ResolveOverloadedCallFn(Fn, Fns, UnqualifiedName,
+ (HasExplicitTemplateArgs ? &ExplicitTemplateArgs : 0),
+ LParenLoc, Args, NumArgs, CommaLocs,
+ RParenLoc, ADL);
+ if (!FDecl)
+ return ExprError();
- Fn = FixOverloadedFunctionReference(Fn, FDecl);
+ Fn = FixOverloadedFunctionReference(Fn, FDecl);
+
+ NDecl = FDecl;
+ } else {
+ assert(Fns.size() <= 1 && "overloaded without Overloaded flag");
+ if (Fns.empty())
+ NDecl = FDecl = 0;
+ else {
+ NDecl = Fns[0];
+ FDecl = dyn_cast<FunctionDecl>(NDecl);
}
}
@@ -3198,13 +3573,18 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
}
}
-Action::OwningExprResult Sema::ActOnParenListExpr(SourceLocation L,
+Action::OwningExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L,
SourceLocation R,
- MultiExprArg Val) {
+ MultiExprArg Val,
+ TypeTy *TypeOfCast) {
unsigned nexprs = Val.size();
Expr **exprs = reinterpret_cast<Expr**>(Val.release());
- assert((exprs != 0) && "ActOnParenListExpr() missing expr list");
- Expr *expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R);
+ assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list");
+ Expr *expr;
+ if (nexprs == 1 && TypeOfCast && !TypeIsVectorType(TypeOfCast))
+ expr = new (Context) ParenExpr(L, R, exprs[0]);
+ else
+ expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R);
return Owned(expr);
}
@@ -3305,6 +3685,17 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
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;
+ }
// Handle block pointer types.
if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) {
if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) {
@@ -4334,7 +4725,7 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc,
const PartialDiagnostic &PD, bool Equality) {
// Don't warn if we're in an unevaluated context.
- if (ExprEvalContext == Unevaluated)
+ if (ExprEvalContexts.back().Context == Unevaluated)
return;
QualType lt = lex->getType(), rt = rex->getType();
@@ -4771,19 +5162,41 @@ inline QualType Sema::CheckBitwiseOperands(
inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
Expr *&lex, Expr *&rex, SourceLocation Loc) {
- UsualUnaryConversions(lex);
- UsualUnaryConversions(rex);
+ if (!Context.getLangOptions().CPlusPlus) {
+ UsualUnaryConversions(lex);
+ UsualUnaryConversions(rex);
- if (!lex->getType()->isScalarType() || !rex->getType()->isScalarType())
- return InvalidOperands(Loc, lex, rex);
+ if (!lex->getType()->isScalarType() || !rex->getType()->isScalarType())
+ return InvalidOperands(Loc, lex, rex);
- if (Context.getLangOptions().CPlusPlus) {
- // C++ [expr.log.and]p2
- // C++ [expr.log.or]p2
- return Context.BoolTy;
+ return Context.IntTy;
}
+
+ // C++ [expr.log.and]p1
+ // C++ [expr.log.or]p1
+ // The operands are both implicitly converted to type bool (clause 4).
+ StandardConversionSequence LHS;
+ if (!IsStandardConversion(lex, Context.BoolTy,
+ /*InOverloadResolution=*/false, LHS))
+ return InvalidOperands(Loc, lex, rex);
- return Context.IntTy;
+ if (PerformImplicitConversion(lex, Context.BoolTy, LHS,
+ "passing", /*IgnoreBaseAccess=*/false))
+ return InvalidOperands(Loc, lex, rex);
+
+ StandardConversionSequence RHS;
+ if (!IsStandardConversion(rex, Context.BoolTy,
+ /*InOverloadResolution=*/false, RHS))
+ return InvalidOperands(Loc, lex, rex);
+
+ if (PerformImplicitConversion(rex, Context.BoolTy, RHS,
+ "passing", /*IgnoreBaseAccess=*/false))
+ return InvalidOperands(Loc, lex, rex);
+
+ // C++ [expr.log.and]p2
+ // C++ [expr.log.or]p2
+ // The result is a bool.
+ return Context.BoolTy;
}
/// IsReadonlyProperty - Verify that otherwise a valid l-value expression
@@ -5123,6 +5536,8 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
// FIXME: Can LHS ever be null here?
if (!CheckAddressOfOperand(CO->getTrueExpr(), OpLoc).isNull())
return CheckAddressOfOperand(CO->getFalseExpr(), OpLoc);
+ } else if (isa<UnresolvedLookupExpr>(op)) {
+ return Context.OverloadTy;
} else if (dcl) { // C99 6.5.3.2p1
// We have an lvalue with a decl. Make sure the decl is not declared
// with the register storage-class specifier.
@@ -5132,8 +5547,7 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
<< "register variable" << op->getSourceRange();
return QualType();
}
- } else if (isa<OverloadedFunctionDecl>(dcl) ||
- isa<FunctionTemplateDecl>(dcl)) {
+ } else if (isa<FunctionTemplateDecl>(dcl)) {
return Context.OverloadTy;
} else if (FieldDecl *FD = dyn_cast<FieldDecl>(dcl)) {
// Okay: we can take the address of a field.
@@ -6199,34 +6613,41 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){
return false;
}
-Sema::ExpressionEvaluationContext
+void
Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
- // Introduce a new set of potentially referenced declarations to the stack.
- if (NewContext == PotentiallyPotentiallyEvaluated)
- PotentiallyReferencedDeclStack.push_back(PotentiallyReferencedDecls());
-
- std::swap(ExprEvalContext, NewContext);
- return NewContext;
+ ExprEvalContexts.push_back(
+ ExpressionEvaluationContextRecord(NewContext, ExprTemporaries.size()));
}
void
-Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
- ExpressionEvaluationContext NewContext) {
- ExprEvalContext = NewContext;
+Sema::PopExpressionEvaluationContext() {
+ // Pop the current expression evaluation context off the stack.
+ ExpressionEvaluationContextRecord Rec = ExprEvalContexts.back();
+ ExprEvalContexts.pop_back();
- if (OldContext == PotentiallyPotentiallyEvaluated) {
+ 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).
- PotentiallyReferencedDecls RemainingDecls;
- RemainingDecls.swap(PotentiallyReferencedDeclStack.back());
- PotentiallyReferencedDeclStack.pop_back();
-
- for (PotentiallyReferencedDecls::iterator I = RemainingDecls.begin(),
- IEnd = RemainingDecls.end();
+ for (PotentiallyReferencedDecls::iterator
+ I = Rec.PotentiallyReferenced->begin(),
+ IEnd = Rec.PotentiallyReferenced->end();
I != IEnd; ++I)
MarkDeclarationReferenced(I->first, I->second);
- }
+ }
+
+ // When are coming out of an unevaluated context, clear out any
+ // temporaries that we may have created as part of the evaluation of
+ // the expression in that context: they aren't relevant because they
+ // will never be constructed.
+ if (Rec.Context == Unevaluated &&
+ ExprTemporaries.size() > Rec.NumTemporaries)
+ ExprTemporaries.erase(ExprTemporaries.begin() + Rec.NumTemporaries,
+ ExprTemporaries.end());
+
+ // Destroy the popped expression evaluation record.
+ Rec.Destroy();
}
/// \brief Note that the given declaration was referenced in the source code.
@@ -6258,7 +6679,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
if (CurContext->isDependentContext())
return;
- switch (ExprEvalContext) {
+ switch (ExprEvalContexts.back().Context) {
case Unevaluated:
// We are in an expression that is not potentially evaluated; do nothing.
return;
@@ -6272,7 +6693,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
// We are in an expression that may be potentially evaluated; queue this
// declaration reference until we know whether the expression is
// potentially evaluated.
- PotentiallyReferencedDeclStack.back().push_back(std::make_pair(Loc, D));
+ ExprEvalContexts.back().addReferencedDecl(Loc, D);
return;
}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 462bf13..00fb65d 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -63,10 +63,11 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
}
}
- // If this is an unevaluated operand, clear out the set of declaration
- // references we have been computing.
+ // If this is an unevaluated operand, clear out the set of
+ // declaration references we have been computing and eliminate any
+ // temporaries introduced in its computation.
if (isUnevaluatedOperand)
- PotentiallyReferencedDeclStack.back().clear();
+ ExprEvalContexts.back().Context = Unevaluated;
}
return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr,
@@ -326,7 +327,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &DInfo);
if (D.isInvalidType())
return ExprError();
-
+
return BuildCXXNew(StartLoc, UseGlobal,
PlacementLParen,
move(PlacementArgs),
@@ -394,7 +395,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
FunctionDecl *OperatorDelete = 0;
Expr **PlaceArgs = (Expr**)PlacementArgs.get();
unsigned NumPlaceArgs = PlacementArgs.size();
-
+
if (!AllocType->isDependentType() &&
!Expr::hasAnyTypeDependentArguments(PlaceArgs, NumPlaceArgs) &&
FindAllocationFunctions(StartLoc,
@@ -402,7 +403,24 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
UseGlobal, AllocType, ArraySize, PlaceArgs,
NumPlaceArgs, OperatorNew, OperatorDelete))
return ExprError();
-
+ llvm::SmallVector<Expr *, 8> AllPlaceArgs;
+ if (OperatorNew) {
+ // Add default arguments, if any.
+ const FunctionProtoType *Proto =
+ OperatorNew->getType()->getAs<FunctionProtoType>();
+ VariadicCallType CallType =
+ Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply;
+ bool Invalid = GatherArgumentsForCall(PlacementLParen, OperatorNew,
+ Proto, 1, PlaceArgs, NumPlaceArgs,
+ AllPlaceArgs, CallType);
+ if (Invalid)
+ return ExprError();
+
+ NumPlaceArgs = AllPlaceArgs.size();
+ if (NumPlaceArgs > 0)
+ PlaceArgs = &AllPlaceArgs[0];
+ }
+
bool Init = ConstructorLParen.isValid();
// --- Choosing a constructor ---
// C++ 5.3.4p15
@@ -602,7 +620,9 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
// The first argument is size_t, and the first parameter must be size_t,
// too. This is checked on declaration and can be assumed. (It can't be
// asserted on, though, since invalid decls are left in there.)
- for (unsigned i = 0; i < NumArgs; ++i) {
+ // Whatch out for variadic allocator function.
+ unsigned NumArgsInFnDecl = FnDecl->getNumParams();
+ for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) {
// FIXME: Passing word to diagnostic.
if (PerformCopyInitialization(Args[i],
FnDecl->getParamDecl(i)->getType(),
@@ -827,18 +847,15 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
if (const RecordType *Record = Type->getAs<RecordType>()) {
llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions;
CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
- OverloadedFunctionDecl *Conversions =
- RD->getVisibleConversionFunctions();
+ const UnresolvedSet *Conversions = RD->getVisibleConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator
- Func = Conversions->function_begin(),
- FuncEnd = Conversions->function_end();
- Func != FuncEnd; ++Func) {
+ for (UnresolvedSet::iterator I = Conversions->begin(),
+ E = Conversions->end(); I != E; ++I) {
// Skip over templated conversion functions; they aren't considered.
- if (isa<FunctionTemplateDecl>(*Func))
+ if (isa<FunctionTemplateDecl>(*I))
continue;
- CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(*I);
QualType ConvType = Conv->getConversionType().getNonReferenceType();
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
@@ -927,54 +944,25 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
OperatorDelete, Ex, StartLoc));
}
-
-/// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
-/// C++ if/switch/while/for statement.
-/// e.g: "if (int x = f()) {...}"
-Action::OwningExprResult
-Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc,
- Declarator &D,
- SourceLocation EqualLoc,
- ExprArg AssignExprVal) {
- assert(AssignExprVal.get() && "Null assignment expression");
-
- // C++ 6.4p2:
- // The declarator shall not specify a function or an array.
- // The type-specifier-seq shall not contain typedef and shall not declare a
- // new class or enumeration.
-
- assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
- "Parser allowed 'typedef' as storage class of condition decl.");
-
- // FIXME: Store DeclaratorInfo in the expression.
- DeclaratorInfo *DInfo = 0;
- TagDecl *OwnedTag = 0;
- QualType Ty = GetTypeForDeclarator(D, S, &DInfo, &OwnedTag);
-
- if (Ty->isFunctionType()) { // The declarator shall not specify a function...
- // We exit without creating a CXXConditionDeclExpr because a FunctionDecl
- // would be created and CXXConditionDeclExpr wants a VarDecl.
- return ExprError(Diag(StartLoc, diag::err_invalid_use_of_function_type)
- << SourceRange(StartLoc, EqualLoc));
- } else if (Ty->isArrayType()) { // ...or an array.
- Diag(StartLoc, diag::err_invalid_use_of_array_type)
- << SourceRange(StartLoc, EqualLoc);
- } else if (OwnedTag && OwnedTag->isDefinition()) {
- // The type-specifier-seq shall not declare a new class or enumeration.
- Diag(OwnedTag->getLocation(), diag::err_type_defined_in_condition);
- }
-
- DeclPtrTy Dcl = ActOnDeclarator(S, D);
- if (!Dcl)
- return ExprError();
- AddInitializerToDecl(Dcl, move(AssignExprVal), /*DirectInit=*/false);
-
- // Mark this variable as one that is declared within a conditional.
- // We know that the decl had to be a VarDecl because that is the only type of
- // decl that can be assigned and the grammar requires an '='.
- VarDecl *VD = cast<VarDecl>(Dcl.getAs<Decl>());
- VD->setDeclaredInCondition(true);
- return Owned(new (Context) CXXConditionDeclExpr(StartLoc, EqualLoc, VD));
+/// \brief Check the use of the given variable as a C++ condition in an if,
+/// while, do-while, or switch statement.
+Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar) {
+ QualType T = ConditionVar->getType();
+
+ // C++ [stmt.select]p2:
+ // The declarator shall not specify a function or an array.
+ if (T->isFunctionType())
+ return ExprError(Diag(ConditionVar->getLocation(),
+ diag::err_invalid_use_of_function_type)
+ << ConditionVar->getSourceRange());
+ else if (T->isArrayType())
+ return ExprError(Diag(ConditionVar->getLocation(),
+ diag::err_invalid_use_of_array_type)
+ << ConditionVar->getSourceRange());
+
+ return Owned(DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar,
+ ConditionVar->getLocation(),
+ ConditionVar->getType().getNonReferenceType()));
}
/// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid.
@@ -1128,11 +1116,12 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
dyn_cast<CXXConstructorDecl>(FD)) {
CastKind = CastExpr::CK_ConstructorConversion;
// Do no conversion if dealing with ... for the first conversion.
- if (!ICS.UserDefined.EllipsisConversion)
+ if (!ICS.UserDefined.EllipsisConversion) {
// If the user-defined conversion is specified by a constructor, the
// initial standard conversion sequence converts the source type to the
// type required by the argument of the constructor
- BeforeToType = Ctor->getParamDecl(0)->getType();
+ BeforeToType = Ctor->getParamDecl(0)->getType().getNonReferenceType();
+ }
}
else
assert(0 && "Unknown conversion function kind!");
@@ -1152,21 +1141,25 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
if (CastArg.isInvalid())
return true;
-
+
+ From = CastArg.takeAs<Expr>();
+
+ // FIXME: This and the following if statement shouldn't be necessary, but
+ // there's some nasty stuff involving MaybeBindToTemporary going on here.
if (ICS.UserDefined.After.Second == ICK_Derived_To_Base &&
ICS.UserDefined.After.CopyConstructor) {
- From = CastArg.takeAs<Expr>();
return BuildCXXDerivedToBaseExpr(From, CastKind, ICS, Flavor);
}
-
- if (ICS.UserDefined.After.Second == ICK_Pointer_Member &&
- ToType.getNonReferenceType()->isMemberFunctionPointerType())
- CastKind = CastExpr::CK_BaseToDerivedMemberPointer;
-
- From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(),
- CastKind, CastArg.takeAs<Expr>(),
- ToType->isLValueReferenceType());
- return false;
+
+ if (ICS.UserDefined.After.CopyConstructor) {
+ From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(),
+ CastKind, From,
+ ToType->isLValueReferenceType());
+ return false;
+ }
+
+ return PerformImplicitConversion(From, ToType, ICS.UserDefined.After,
+ "converting", IgnoreBaseAccess);
}
case ImplicitConversionSequence::EllipsisConversion:
@@ -1333,9 +1326,14 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
ImpCastExprToType(From, ToType, Kind);
break;
}
- case ICK_Boolean_Conversion:
- ImpCastExprToType(From, Context.BoolTy, CastExpr::CK_Unknown);
+ case ICK_Boolean_Conversion: {
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ if (FromType->isMemberPointerType())
+ Kind = CastExpr::CK_MemberPointerToBoolean;
+
+ ImpCastExprToType(From, Context.BoolTy, Kind);
break;
+ }
case ICK_Derived_To_Base:
if (CheckDerivedToBaseConversion(From->getType(),
@@ -2131,10 +2129,10 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
return ExprError();
}
}
- }
- if (BaseType->isPointerType())
- BaseType = BaseType->getPointeeType();
+ if (BaseType->isPointerType())
+ BaseType = BaseType->getPointeeType();
+ }
// We could end up with various non-record types here, such as extended
// vector types or Objective-C interfaces. Just return early and let
@@ -2175,10 +2173,10 @@ CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
else
ResultType = Method->getResultType().getNonReferenceType();
- CXXMemberCallExpr *CE =
- new (Context) CXXMemberCallExpr(Context, ME, 0, 0,
- ResultType,
- Exp->getLocEnd());
+ MarkDeclarationReferenced(Exp->getLocStart(), Method);
+ CXXMemberCallExpr *CE =
+ new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType,
+ Exp->getLocEnd());
return CE;
}
@@ -2238,9 +2236,6 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
///
/// FIXME: Should Objective-C also use this approach?
///
-/// \param SS if non-NULL, the C++ nested-name-specifier that precedes the
-/// name of the declaration referenced.
-///
/// \param D the declaration being referenced from the current scope.
///
/// \param NameLoc the location of the name in the source.
@@ -2249,16 +2244,11 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
/// access, will be set to the type of the "this" pointer to be used when
/// building that implicit member access.
///
-/// \param MemberType if the reference to this declaration is an implicit
-/// member access, will be set to the type of the member being referenced
-/// (for use at the type of the resulting member access expression).
-///
/// \returns true if this is an implicit member reference (in which case
/// \p ThisType and \p MemberType will be set), or false if it is not an
/// implicit member reference.
-bool Sema::isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D,
- SourceLocation NameLoc, QualType &ThisType,
- QualType &MemberType) {
+bool Sema::isImplicitMemberReference(const LookupResult &R,
+ QualType &ThisType) {
// If this isn't a C++ method, then it isn't an implicit member reference.
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext);
if (!MD || MD->isStatic())
@@ -2271,30 +2261,21 @@ bool Sema::isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D,
// class member access expression (5.2.5) using (*this) (9.3.2)
// as the postfix-expression to the left of the '.' operator.
DeclContext *Ctx = 0;
- if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+ if (R.isUnresolvableResult()) {
+ // FIXME: this is just picking one at random
+ Ctx = R.getRepresentativeDecl()->getDeclContext();
+ } else if (FieldDecl *FD = R.getAsSingle<FieldDecl>()) {
Ctx = FD->getDeclContext();
- MemberType = FD->getType();
-
- if (const ReferenceType *RefType = MemberType->getAs<ReferenceType>())
- MemberType = RefType->getPointeeType();
- else if (!FD->isMutable())
- MemberType
- = Context.getQualifiedType(MemberType,
- Qualifiers::fromCVRMask(MD->getTypeQualifiers()));
} else {
- for (OverloadIterator Ovl(D), OvlEnd; Ovl != OvlEnd; ++Ovl) {
- CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Ovl);
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*I);
FunctionTemplateDecl *FunTmpl = 0;
- if (!Method && (FunTmpl = dyn_cast<FunctionTemplateDecl>(*Ovl)))
+ if (!Method && (FunTmpl = dyn_cast<FunctionTemplateDecl>(*I)))
Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
// FIXME: Do we have to know if there are explicit template arguments?
if (Method && !Method->isStatic()) {
Ctx = Method->getParent();
- if (isa<CXXMethodDecl>(D) && !FunTmpl)
- MemberType = Method->getType();
- else
- MemberType = Context.OverloadTy;
break;
}
}
@@ -2306,11 +2287,8 @@ bool Sema::isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D,
// Determine whether the declaration(s) we found are actually in a base
// class. If not, this isn't an implicit member reference.
ThisType = MD->getThisType(Context);
-
- // If the type of "this" is dependent, we can't tell if the member is in a
- // base class or not, so treat this as a dependent implicit member reference.
- if (ThisType->isDependentType())
- return true;
+
+ // FIXME: this doesn't really work for overloaded lookups.
QualType CtxType = Context.getTypeDeclType(cast<CXXRecordDecl>(Ctx));
QualType ClassType
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 0f973d6d..2eba704 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -136,8 +136,51 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
SourceLocation InitLoc,
DeclarationName InitEntity, bool DirectInit) {
if (DeclType->isDependentType() ||
- Init->isTypeDependent() || Init->isValueDependent())
+ Init->isTypeDependent() || Init->isValueDependent()) {
+ // We have either a dependent type or a type- or value-dependent
+ // initializer, so we don't perform any additional checking at
+ // this point.
+
+ // If the declaration is a non-dependent, incomplete array type
+ // that has an initializer, then its type will be completed once
+ // the initializer is instantiated.
+ if (!DeclType->isDependentType()) {
+ if (const IncompleteArrayType *ArrayT
+ = Context.getAsIncompleteArrayType(DeclType)) {
+ if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
+ if (!ILE->isTypeDependent()) {
+ // Compute the constant array type from the length of the
+ // initializer list.
+ // FIXME: This will be wrong if there are designated
+ // initializations. Good thing they don't exist in C++!
+ llvm::APInt NumElements(Context.getTypeSize(Context.getSizeType()),
+ ILE->getNumInits());
+ llvm::APInt Zero(Context.getTypeSize(Context.getSizeType()), 0);
+ if (NumElements == Zero) {
+ // Sizing an array implicitly to zero is not allowed by ISO C,
+ // but is supported by GNU.
+ Diag(ILE->getLocStart(), diag::ext_typecheck_zero_array_size);
+ }
+
+ DeclType = Context.getConstantArrayType(ArrayT->getElementType(),
+ NumElements,
+ ArrayT->getSizeModifier(),
+ ArrayT->getIndexTypeCVRQualifiers());
+ return false;
+ }
+ }
+
+ // Make the array type-dependent by making it dependently-sized.
+ DeclType = Context.getDependentSizedArrayType(ArrayT->getElementType(),
+ /*NumElts=*/0,
+ ArrayT->getSizeModifier(),
+ ArrayT->getIndexTypeCVRQualifiers(),
+ SourceRange());
+ }
+ }
+
return false;
+ }
// C++ [dcl.init.ref]p1:
// A variable declared to be a T& or T&&, that is "reference to type T"
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 1957d7f..8f09827 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -242,6 +242,7 @@ void LookupResult::deletePaths(CXXBasePaths *Paths) {
delete Paths;
}
+/// Resolves the result kind of this lookup.
void LookupResult::resolveKind() {
unsigned N = Decls.size();
@@ -251,8 +252,12 @@ void LookupResult::resolveKind() {
return;
}
+ // If there's a single decl, we need to examine it to decide what
+ // kind of lookup this is.
if (N == 1) {
- if (isa<UnresolvedUsingValueDecl>(Decls[0]))
+ if (isa<FunctionTemplateDecl>(Decls[0]))
+ ResultKind = FoundOverloaded;
+ else if (isa<UnresolvedUsingValueDecl>(Decls[0]))
ResultKind = FoundUnresolvedValue;
return;
}
@@ -264,7 +269,7 @@ void LookupResult::resolveKind() {
bool Ambiguous = false;
bool HasTag = false, HasFunction = false, HasNonFunction = false;
- bool HasUnresolved = false;
+ bool HasFunctionTemplate = false, HasUnresolved = false;
unsigned UniqueTagIndex = 0;
@@ -290,7 +295,10 @@ void LookupResult::resolveKind() {
Ambiguous = true;
UniqueTagIndex = I;
HasTag = true;
- } else if (D->isFunctionOrFunctionTemplate()) {
+ } else if (isa<FunctionTemplateDecl>(D)) {
+ HasFunction = true;
+ HasFunctionTemplate = true;
+ } else if (isa<FunctionDecl>(D)) {
HasFunction = true;
} else {
if (HasNonFunction)
@@ -323,7 +331,7 @@ void LookupResult::resolveKind() {
setAmbiguous(LookupResult::AmbiguousReference);
else if (HasUnresolved)
ResultKind = LookupResult::FoundUnresolvedValue;
- else if (N > 1)
+ else if (N > 1 || HasFunctionTemplate)
ResultKind = LookupResult::FoundOverloaded;
else
ResultKind = LookupResult::Found;
@@ -1525,33 +1533,25 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
// in which the function or function template is defined and the
// classes and namespaces associated with its (non-dependent)
// parameter types and return type.
- DeclRefExpr *DRE = 0;
- TemplateIdRefExpr *TIRE = 0;
Arg = Arg->IgnoreParens();
- if (UnaryOperator *unaryOp = dyn_cast<UnaryOperator>(Arg)) {
- if (unaryOp->getOpcode() == UnaryOperator::AddrOf) {
- DRE = dyn_cast<DeclRefExpr>(unaryOp->getSubExpr());
- TIRE = dyn_cast<TemplateIdRefExpr>(unaryOp->getSubExpr());
- }
- } else {
- DRE = dyn_cast<DeclRefExpr>(Arg);
- TIRE = dyn_cast<TemplateIdRefExpr>(Arg);
- }
+ if (UnaryOperator *unaryOp = dyn_cast<UnaryOperator>(Arg))
+ if (unaryOp->getOpcode() == UnaryOperator::AddrOf)
+ Arg = unaryOp->getSubExpr();
+
+ // TODO: avoid the copies. This should be easy when the cases
+ // share a storage implementation.
+ llvm::SmallVector<NamedDecl*, 8> Functions;
- OverloadedFunctionDecl *Ovl = 0;
- if (DRE)
- Ovl = dyn_cast<OverloadedFunctionDecl>(DRE->getDecl());
- else if (TIRE)
- Ovl = TIRE->getTemplateName().getAsOverloadedFunctionDecl();
- if (!Ovl)
+ if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Arg))
+ Functions.append(ULE->decls_begin(), ULE->decls_end());
+ else
continue;
- for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
- FuncEnd = Ovl->function_end();
- Func != FuncEnd; ++Func) {
- FunctionDecl *FDecl = dyn_cast<FunctionDecl>(*Func);
+ for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Functions.begin(),
+ E = Functions.end(); I != E; ++I) {
+ FunctionDecl *FDecl = dyn_cast<FunctionDecl>(*I);
if (!FDecl)
- FDecl = cast<FunctionTemplateDecl>(*Func)->getTemplatedDecl();
+ FDecl = cast<FunctionTemplateDecl>(*I)->getTemplatedDecl();
// Add the namespace in which this function was defined. Note
// that, if this is a member function, we do *not* consider the
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index daf5b7f..6ea6a14 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -23,7 +23,6 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Support/Compiler.h"
#include <algorithm>
#include <cstdio>
@@ -1353,18 +1352,6 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) {
return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType);
}
-/// \brief Given a function template or function, extract the function template
-/// declaration (if any) and the underlying function declaration.
-template<typename T>
-static void GetFunctionAndTemplate(AnyFunctionDecl Orig, T *&Function,
- FunctionTemplateDecl *&FunctionTemplate) {
- FunctionTemplate = dyn_cast<FunctionTemplateDecl>(Orig);
- if (FunctionTemplate)
- Function = cast<T>(FunctionTemplate->getTemplatedDecl());
- else
- Function = cast<T>(Orig);
-}
-
/// Determines whether there is a user-defined conversion sequence
/// (C++ [over.ics.user]) that converts expression From to the type
/// ToType. If such a conversion exists, User will contain the
@@ -1431,8 +1418,8 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion(
if (!Constructor->isInvalidDecl() &&
Constructor->isConvertingConstructor(AllowExplicit)) {
if (ConstructorTmpl)
- AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, &From,
- 1, CandidateSet,
+ AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0,
+ &From, 1, CandidateSet,
SuppressUserConversions, ForceRValue);
else
// Allow one user-defined conversion when user specifies a
@@ -1455,18 +1442,16 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion(
if (CXXRecordDecl *FromRecordDecl
= dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) {
// Add all of the conversion functions as candidates.
- OverloadedFunctionDecl *Conversions
+ const UnresolvedSet *Conversions
= FromRecordDecl->getVisibleConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator Func
- = Conversions->function_begin();
- Func != Conversions->function_end(); ++Func) {
+ for (UnresolvedSet::iterator I = Conversions->begin(),
+ E = Conversions->end(); I != E; ++I) {
CXXConversionDecl *Conv;
FunctionTemplateDecl *ConvTemplate;
- GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
- if (ConvTemplate)
+ if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(*I)))
Conv = dyn_cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
- Conv = dyn_cast<CXXConversionDecl>(*Func);
+ Conv = dyn_cast<CXXConversionDecl>(*I);
if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
@@ -2254,6 +2239,9 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
if (!CandidateSet.isNewCandidate(Function))
return;
+ // Overload resolution is always an unevaluated context.
+ EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated);
+
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Function)){
// C++ [class.copy]p3:
// A member function template is never instantiated to perform the copy
@@ -2365,13 +2353,13 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions,
if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) &&
!cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic())
AddMethodTemplateCandidate(FunTmpl,
- /*FIXME: explicit args */false, 0, 0,
+ /*FIXME: explicit args */ 0,
Args[0], Args + 1, NumArgs - 1,
CandidateSet,
SuppressUserConversions);
else
AddTemplateOverloadCandidate(FunTmpl,
- /*FIXME: explicit args */false, 0, 0,
+ /*FIXME: explicit args */ 0,
Args, NumArgs, CandidateSet,
SuppressUserConversions);
}
@@ -2394,7 +2382,7 @@ 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, false, 0, 0,
+ AddMethodTemplateCandidate(TD, /*ExplicitArgs*/ 0,
Object, Args, NumArgs,
CandidateSet,
SuppressUserConversions,
@@ -2430,6 +2418,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
if (!CandidateSet.isNewCandidate(Method))
return;
+ // Overload resolution is always an unevaluated context.
+ EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated);
+
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
@@ -2509,9 +2500,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
/// function template specialization.
void
Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
- bool HasExplicitTemplateArgs,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr *Object, Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
@@ -2531,8 +2520,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
TemplateDeductionInfo Info(Context);
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult Result
- = DeduceTemplateArguments(MethodTmpl, HasExplicitTemplateArgs,
- ExplicitTemplateArgs, NumExplicitTemplateArgs,
+ = DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs,
Args, NumArgs, Specialization, Info)) {
// FIXME: Record what happened with template argument deduction, so
// that we can give the user a beautiful diagnostic.
@@ -2554,9 +2542,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
/// an appropriate function template specialization.
void
Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
- bool HasExplicitTemplateArgs,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
@@ -2576,8 +2562,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
TemplateDeductionInfo Info(Context);
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult Result
- = DeduceTemplateArguments(FunctionTemplate, HasExplicitTemplateArgs,
- ExplicitTemplateArgs, NumExplicitTemplateArgs,
+ = DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
Args, NumArgs, Specialization, Info)) {
// FIXME: Record what happened with template argument deduction, so
// that we can give the user a beautiful diagnostic.
@@ -2608,6 +2593,9 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
if (!CandidateSet.isNewCandidate(Conversion))
return;
+ // Overload resolution is always an unevaluated context.
+ EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated);
+
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
@@ -2732,6 +2720,9 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
if (!CandidateSet.isNewCandidate(Conversion))
return;
+ // Overload resolution is always an unevaluated context.
+ EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated);
+
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = 0;
@@ -2897,6 +2888,9 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
OverloadCandidateSet& CandidateSet,
bool IsAssignmentOperator,
unsigned NumContextualBoolArguments) {
+ // Overload resolution is always an unevaluated context.
+ EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated);
+
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
@@ -3144,20 +3138,17 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
}
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
- OverloadedFunctionDecl *Conversions
+ const UnresolvedSet *Conversions
= ClassDecl->getVisibleConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator Func
- = Conversions->function_begin();
- Func != Conversions->function_end(); ++Func) {
- CXXConversionDecl *Conv;
- FunctionTemplateDecl *ConvTemplate;
- GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
+ for (UnresolvedSet::iterator I = Conversions->begin(),
+ E = Conversions->end(); I != E; ++I) {
// Skip conversion function templates; they don't tell us anything
// about which builtin types we can convert to.
- if (ConvTemplate)
+ if (isa<FunctionTemplateDecl>(*I))
continue;
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(*I);
if (AllowExplicitConversions || !Conv->isExplicit()) {
AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false,
VisibleQuals);
@@ -3211,13 +3202,12 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
}
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
- OverloadedFunctionDecl *Conversions =
+ const UnresolvedSet *Conversions =
ClassDecl->getVisibleConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator Func
- = Conversions->function_begin();
- Func != Conversions->function_end(); ++Func) {
- if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(*Func)) {
+ for (UnresolvedSet::iterator I = Conversions->begin(),
+ E = Conversions->end(); I != E; ++I) {
+ if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(*I)) {
QualType CanTy = Context.getCanonicalType(Conv->getConversionType());
if (const ReferenceType *ResTypeRef = CanTy->getAs<ReferenceType>())
CanTy = ResTypeRef->getPointeeType();
@@ -3959,9 +3949,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
void
Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
Expr **Args, unsigned NumArgs,
- bool HasExplicitTemplateArgs,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
bool PartialOverloading) {
FunctionSet Functions;
@@ -4000,16 +3988,14 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
FuncEnd = Functions.end();
Func != FuncEnd; ++Func) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func)) {
- if (HasExplicitTemplateArgs)
+ if (ExplicitTemplateArgs)
continue;
AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
false, false, PartialOverloading);
} else
AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*Func),
- HasExplicitTemplateArgs,
ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
Args, NumArgs, CandidateSet);
}
}
@@ -4336,7 +4322,6 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
return 0;
// Find the actual overloaded function declaration.
- OverloadedFunctionDecl *Ovl = 0;
// C++ [over.over]p1:
// [...] [Note: any redundant set of parentheses surrounding the
@@ -4352,50 +4337,37 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
}
bool HasExplicitTemplateArgs = false;
- const TemplateArgumentLoc *ExplicitTemplateArgs = 0;
- unsigned NumExplicitTemplateArgs = 0;
+ TemplateArgumentListInfo ExplicitTemplateArgs;
+
+ llvm::SmallVector<NamedDecl*,8> Fns;
- // Try to dig out the overloaded function.
- FunctionTemplateDecl *FunctionTemplate = 0;
- if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OvlExpr)) {
- Ovl = dyn_cast<OverloadedFunctionDecl>(DR->getDecl());
- FunctionTemplate = dyn_cast<FunctionTemplateDecl>(DR->getDecl());
- HasExplicitTemplateArgs = DR->hasExplicitTemplateArgumentList();
- ExplicitTemplateArgs = DR->getTemplateArgs();
- NumExplicitTemplateArgs = DR->getNumTemplateArgs();
- } else if (MemberExpr *ME = dyn_cast<MemberExpr>(OvlExpr)) {
- Ovl = dyn_cast<OverloadedFunctionDecl>(ME->getMemberDecl());
- FunctionTemplate = dyn_cast<FunctionTemplateDecl>(ME->getMemberDecl());
- HasExplicitTemplateArgs = ME->hasExplicitTemplateArgumentList();
- ExplicitTemplateArgs = ME->getTemplateArgs();
- NumExplicitTemplateArgs = ME->getNumTemplateArgs();
- } else if (TemplateIdRefExpr *TIRE = dyn_cast<TemplateIdRefExpr>(OvlExpr)) {
- TemplateName Name = TIRE->getTemplateName();
- Ovl = Name.getAsOverloadedFunctionDecl();
- FunctionTemplate =
- dyn_cast_or_null<FunctionTemplateDecl>(Name.getAsTemplateDecl());
-
- HasExplicitTemplateArgs = true;
- ExplicitTemplateArgs = TIRE->getTemplateArgs();
- NumExplicitTemplateArgs = TIRE->getNumTemplateArgs();
+ // Look into the overloaded expression.
+ if (UnresolvedLookupExpr *UL
+ = dyn_cast<UnresolvedLookupExpr>(OvlExpr)) {
+ Fns.append(UL->decls_begin(), UL->decls_end());
+ if (UL->hasExplicitTemplateArgs()) {
+ HasExplicitTemplateArgs = true;
+ UL->copyTemplateArgumentsInto(ExplicitTemplateArgs);
+ }
+ } else if (UnresolvedMemberExpr *ME
+ = dyn_cast<UnresolvedMemberExpr>(OvlExpr)) {
+ Fns.append(ME->decls_begin(), ME->decls_end());
+ if (ME->hasExplicitTemplateArgs()) {
+ HasExplicitTemplateArgs = true;
+ ME->copyTemplateArgumentsInto(ExplicitTemplateArgs);
+ }
}
-
- // If there's no overloaded function declaration or function template,
- // we're done.
- if (!Ovl && !FunctionTemplate)
- return 0;
- OverloadIterator Fun;
- if (Ovl)
- Fun = Ovl;
- else
- Fun = FunctionTemplate;
+ // If we didn't actually find anything, we're done.
+ if (Fns.empty())
+ return 0;
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
llvm::SmallPtrSet<FunctionDecl *, 4> Matches;
bool FoundNonTemplateFunction = false;
- for (OverloadIterator FunEnd; Fun != FunEnd; ++Fun) {
+ for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(),
+ E = Fns.end(); I != E; ++I) {
// C++ [over.over]p3:
// Non-member functions and static member functions match
// targets of type "pointer-to-function" or "reference-to-function."
@@ -4404,7 +4376,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// Note that according to DR 247, the containing class does not matter.
if (FunctionTemplateDecl *FunctionTemplate
- = dyn_cast<FunctionTemplateDecl>(*Fun)) {
+ = dyn_cast<FunctionTemplateDecl>(*I)) {
if (CXXMethodDecl *Method
= dyn_cast<CXXMethodDecl>(FunctionTemplate->getTemplatedDecl())) {
// Skip non-static function templates when converting to pointer, and
@@ -4424,9 +4396,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
FunctionDecl *Specialization = 0;
TemplateDeductionInfo Info(Context);
if (TemplateDeductionResult Result
- = DeduceTemplateArguments(FunctionTemplate, HasExplicitTemplateArgs,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
+ = DeduceTemplateArguments(FunctionTemplate,
+ (HasExplicitTemplateArgs ? &ExplicitTemplateArgs : 0),
FunctionType, Specialization, Info)) {
// FIXME: make a note of the failed deduction for diagnostics.
(void)Result;
@@ -4438,9 +4409,11 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
Matches.insert(
cast<FunctionDecl>(Specialization->getCanonicalDecl()));
}
+
+ continue;
}
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Fun)) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*I)) {
// Skip non-static functions when converting to pointer, and static
// when converting to member pointer.
if (Method->isStatic() == IsMember)
@@ -4452,9 +4425,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
} else if (IsMember)
continue;
- if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Fun)) {
+ if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*I)) {
if (FunctionType == Context.getCanonicalType(FunDecl->getType())) {
- Matches.insert(cast<FunctionDecl>(Fun->getCanonicalDecl()));
+ Matches.insert(cast<FunctionDecl>(FunDecl->getCanonicalDecl()));
FoundNonTemplateFunction = true;
}
}
@@ -4522,51 +4495,47 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
/// \brief Add a single candidate to the overload set.
static void AddOverloadedCallCandidate(Sema &S,
- AnyFunctionDecl Callee,
- bool &ArgumentDependentLookup,
- bool HasExplicitTemplateArgs,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ NamedDecl *Callee,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading) {
+ if (isa<UsingShadowDecl>(Callee))
+ Callee = cast<UsingShadowDecl>(Callee)->getTargetDecl();
+
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) {
- assert(!HasExplicitTemplateArgs && "Explicit template arguments?");
+ assert(!ExplicitTemplateArgs && "Explicit template arguments?");
S.AddOverloadCandidate(Func, Args, NumArgs, CandidateSet, false, false,
PartialOverloading);
-
- if (Func->getDeclContext()->isRecord() ||
- Func->getDeclContext()->isFunctionOrMethod())
- ArgumentDependentLookup = false;
return;
- }
-
- FunctionTemplateDecl *FuncTemplate = cast<FunctionTemplateDecl>(Callee);
- S.AddTemplateOverloadCandidate(FuncTemplate, HasExplicitTemplateArgs,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
- Args, NumArgs, CandidateSet);
-
- if (FuncTemplate->getDeclContext()->isRecord())
- ArgumentDependentLookup = false;
+ }
+
+ if (FunctionTemplateDecl *FuncTemplate
+ = dyn_cast<FunctionTemplateDecl>(Callee)) {
+ S.AddTemplateOverloadCandidate(FuncTemplate, ExplicitTemplateArgs,
+ Args, NumArgs, CandidateSet);
+ return;
+ }
+
+ assert(false && "unhandled case in overloaded call candidate");
+
+ // do nothing?
}
/// \brief Add the overload candidates named by callee and/or found by argument
/// dependent lookup to the given overload set.
-void Sema::AddOverloadedCallCandidates(NamedDecl *Callee,
+void Sema::AddOverloadedCallCandidates(llvm::SmallVectorImpl<NamedDecl*> &Fns,
DeclarationName &UnqualifiedName,
- bool &ArgumentDependentLookup,
- bool HasExplicitTemplateArgs,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ bool ArgumentDependentLookup,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading) {
- // Add the functions denoted by Callee to the set of candidate
- // functions. While we're doing so, track whether argument-dependent
- // lookup still applies, per:
+
+#ifndef NDEBUG
+ // Verify that ArgumentDependentLookup is consistent with the rules
+ // in C++0x [basic.lookup.argdep]p3:
//
- // C++0x [basic.lookup.argdep]p3:
// Let X be the lookup set produced by unqualified lookup (3.4.1)
// and let Y be the lookup set produced by argument dependent
// lookup (defined as follows). If X contains
@@ -4574,43 +4543,32 @@ void Sema::AddOverloadedCallCandidates(NamedDecl *Callee,
// -- a declaration of a class member, or
//
// -- a block-scope function declaration that is not a
- // using-declaration (FIXME: check for using declaration), or
+ // using-declaration, or
//
// -- a declaration that is neither a function or a function
// template
//
// then Y is empty.
- if (!Callee) {
- // Nothing to do.
- } else if (OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(Callee)) {
- for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
- FuncEnd = Ovl->function_end();
- Func != FuncEnd; ++Func)
- AddOverloadedCallCandidate(*this, *Func, ArgumentDependentLookup,
- HasExplicitTemplateArgs,
- ExplicitTemplateArgs, NumExplicitTemplateArgs,
- Args, NumArgs, CandidateSet,
- PartialOverloading);
- } else if (isa<FunctionDecl>(Callee) || isa<FunctionTemplateDecl>(Callee))
- AddOverloadedCallCandidate(*this,
- AnyFunctionDecl::getFromNamedDecl(Callee),
- ArgumentDependentLookup,
- HasExplicitTemplateArgs,
- ExplicitTemplateArgs, NumExplicitTemplateArgs,
- Args, NumArgs, CandidateSet,
+
+ if (ArgumentDependentLookup) {
+ for (unsigned I = 0; I < Fns.size(); ++I) {
+ assert(!Fns[I]->getDeclContext()->isRecord());
+ assert(isa<UsingShadowDecl>(Fns[I]) ||
+ !Fns[I]->getDeclContext()->isFunctionOrMethod());
+ assert(Fns[I]->getUnderlyingDecl()->isFunctionOrFunctionTemplate());
+ }
+ }
+#endif
+
+ for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(),
+ E = Fns.end(); I != E; ++I)
+ AddOverloadedCallCandidate(*this, *I, ExplicitTemplateArgs,
+ Args, NumArgs, CandidateSet,
PartialOverloading);
- // FIXME: assert isa<FunctionDecl> || isa<FunctionTemplateDecl> rather than
- // checking dynamically.
-
- if (Callee)
- UnqualifiedName = Callee->getDeclName();
-
+
if (ArgumentDependentLookup)
AddArgumentDependentLookupCandidates(UnqualifiedName, Args, NumArgs,
- HasExplicitTemplateArgs,
ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
CandidateSet,
PartialOverloading);
}
@@ -4622,23 +4580,21 @@ void Sema::AddOverloadedCallCandidates(NamedDecl *Callee,
/// the function declaration produced by overload
/// resolution. Otherwise, emits diagnostics, deletes all of the
/// arguments and Fn, and returns NULL.
-FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
+FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn,
+ llvm::SmallVectorImpl<NamedDecl*> &Fns,
DeclarationName UnqualifiedName,
- bool HasExplicitTemplateArgs,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation *CommaLocs,
SourceLocation RParenLoc,
- bool &ArgumentDependentLookup) {
+ bool ArgumentDependentLookup) {
OverloadCandidateSet CandidateSet;
// Add the functions denoted by Callee to the set of candidate
// functions.
- AddOverloadedCallCandidates(Callee, UnqualifiedName, ArgumentDependentLookup,
- HasExplicitTemplateArgs, ExplicitTemplateArgs,
- NumExplicitTemplateArgs, Args, NumArgs,
+ AddOverloadedCallCandidates(Fns, UnqualifiedName, ArgumentDependentLookup,
+ ExplicitTemplateArgs, Args, NumArgs,
CandidateSet);
OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) {
@@ -4675,6 +4631,11 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
return 0;
}
+static bool IsOverloaded(const Sema::FunctionSet &Functions) {
+ return Functions.size() > 1 ||
+ (Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin()));
+}
+
/// \brief Create a unary operation that may resolve to an overloaded
/// operator.
///
@@ -4716,15 +4677,14 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
}
if (Input->isTypeDependent()) {
- OverloadedFunctionDecl *Overloads
- = OverloadedFunctionDecl::Create(Context, CurContext, OpName);
+ UnresolvedLookupExpr *Fn
+ = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true,
+ 0, SourceRange(), OpName, OpLoc,
+ /*ADL*/ true, IsOverloaded(Functions));
for (FunctionSet::iterator Func = Functions.begin(),
FuncEnd = Functions.end();
Func != FuncEnd; ++Func)
- Overloads->addOverload(*Func);
-
- DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy,
- OpLoc, false, false);
+ Fn->addDecl(*Func);
input.release();
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
@@ -4874,15 +4834,15 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
OpLoc));
}
- OverloadedFunctionDecl *Overloads
- = OverloadedFunctionDecl::Create(Context, CurContext, OpName);
+ UnresolvedLookupExpr *Fn
+ = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true,
+ 0, SourceRange(), OpName, OpLoc,
+ /* ADL */ true, IsOverloaded(Functions));
+
for (FunctionSet::iterator Func = Functions.begin(),
FuncEnd = Functions.end();
Func != FuncEnd; ++Func)
- Overloads->addOverload(*Func);
-
- DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy,
- OpLoc, false, false);
+ Fn->addDecl(*Func);
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
Args, 2,
@@ -5040,11 +5000,11 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// expression.
if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) {
- OverloadedFunctionDecl *Overloads
- = OverloadedFunctionDecl::Create(Context, CurContext, OpName);
-
- DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy,
- LLoc, false, false);
+ UnresolvedLookupExpr *Fn
+ = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true,
+ 0, SourceRange(), OpName, LLoc,
+ /*ADL*/ true, /*Overloaded*/ false);
+ // Can't add any actual overloads yet
Base.release();
Idx.release();
@@ -5169,51 +5129,63 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
SourceLocation RParenLoc) {
// Dig out the member expression. This holds both the object
// argument and the member function we're referring to.
- MemberExpr *MemExpr = 0;
- if (ParenExpr *ParenE = dyn_cast<ParenExpr>(MemExprE))
- MemExpr = dyn_cast<MemberExpr>(ParenE->getSubExpr());
- else
- MemExpr = dyn_cast<MemberExpr>(MemExprE);
- assert(MemExpr && "Building member call without member expression");
-
+ Expr *NakedMemExpr = MemExprE->IgnoreParens();
+
// Extract the object argument.
- Expr *ObjectArg = MemExpr->getBase();
+ Expr *ObjectArg;
+ MemberExpr *MemExpr;
CXXMethodDecl *Method = 0;
- if (isa<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) ||
- isa<FunctionTemplateDecl>(MemExpr->getMemberDecl())) {
+ 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();
+
// Add overload candidates
OverloadCandidateSet CandidateSet;
- DeclarationName DeclName = MemExpr->getMemberDecl()->getDeclName();
- for (OverloadIterator Func(MemExpr->getMemberDecl()), FuncEnd;
- Func != FuncEnd; ++Func) {
- if ((Method = dyn_cast<CXXMethodDecl>(*Func))) {
+ 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();
+
+ if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
// If explicit template arguments were provided, we can't call a
// non-template member function.
- if (MemExpr->hasExplicitTemplateArgumentList())
+ if (UnresExpr->hasExplicitTemplateArgs())
continue;
AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/false);
- } else
- AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func),
- MemExpr->hasExplicitTemplateArgumentList(),
- MemExpr->getTemplateArgs(),
- MemExpr->getNumTemplateArgs(),
+ } else {
+ // FIXME: avoid copy.
+ TemplateArgumentListInfo TemplateArgs;
+ if (UnresExpr->hasExplicitTemplateArgs())
+ UnresExpr->copyTemplateArgumentsInto(TemplateArgs);
+
+ AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func),
+ (UnresExpr->hasExplicitTemplateArgs()
+ ? &TemplateArgs : 0),
ObjectArg, Args, NumArgs,
CandidateSet,
/*SuppressUsedConversions=*/false);
+ }
}
+ DeclarationName DeclName = UnresExpr->getMemberName();
+
OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, MemExpr->getLocStart(), Best)) {
+ switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) {
case OR_Success:
Method = cast<CXXMethodDecl>(Best->Function);
break;
case OR_No_Viable_Function:
- Diag(MemExpr->getSourceRange().getBegin(),
+ Diag(UnresExpr->getMemberLoc(),
diag::err_ovl_no_viable_member_function_in_call)
<< DeclName << MemExprE->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
@@ -5221,16 +5193,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
return true;
case OR_Ambiguous:
- Diag(MemExpr->getSourceRange().getBegin(),
- diag::err_ovl_ambiguous_member_call)
+ Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call)
<< DeclName << MemExprE->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
// FIXME: Leaking incoming expressions!
return true;
case OR_Deleted:
- Diag(MemExpr->getSourceRange().getBegin(),
- diag::err_ovl_deleted_member_call)
+ Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call)
<< Best->Function->isDeleted()
<< DeclName << MemExprE->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
@@ -5238,9 +5208,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
return true;
}
- FixOverloadedFunctionReference(MemExpr, Method);
- } else {
- Method = dyn_cast<CXXMethodDecl>(MemExpr->getMemberDecl());
+ MemExprE = FixOverloadedFunctionReference(MemExprE, Method);
+ MemExpr = cast<MemberExpr>(MemExprE->IgnoreParens());
}
assert(Method && "Member call to something that isn't a method?");
@@ -5329,21 +5298,17 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// accessible base class provided the function is not hidden
// within T by another intervening declaration.
// FIXME: Look in base classes for more conversion operators!
- OverloadedFunctionDecl *Conversions
+ const UnresolvedSet *Conversions
= cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator
- Func = Conversions->function_begin(),
- FuncEnd = Conversions->function_end();
- Func != FuncEnd; ++Func) {
- CXXConversionDecl *Conv;
- FunctionTemplateDecl *ConvTemplate;
- GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
-
+ for (UnresolvedSet::iterator I = Conversions->begin(),
+ E = Conversions->end(); I != E; ++I) {
// Skip over templated conversion functions; they aren't
// surrogates.
- if (ConvTemplate)
+ if (isa<FunctionTemplateDecl>(*I))
continue;
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(*I);
+
// Strip the reference type (if any) and then the pointer type (if
// any) to get down to what might be a function type.
QualType ConvType = Conv->getConversionType().getNonReferenceType();
@@ -5604,80 +5569,111 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
/// refer (possibly indirectly) to Fn. Returns the new expr.
Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
- Expr *NewExpr = FixOverloadedFunctionReference(PE->getSubExpr(), Fn);
- PE->setSubExpr(NewExpr);
- PE->setType(NewExpr->getType());
- } else if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
- Expr *NewExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), Fn);
+ Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(), Fn);
+ if (SubExpr == PE->getSubExpr())
+ return PE->Retain();
+
+ return new (Context) ParenExpr(PE->getLParen(), PE->getRParen(), SubExpr);
+ }
+
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), Fn);
assert(Context.hasSameType(ICE->getSubExpr()->getType(),
- NewExpr->getType()) &&
+ SubExpr->getType()) &&
"Implicit cast type cannot be determined from overload");
- ICE->setSubExpr(NewExpr);
- } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) {
+ if (SubExpr == ICE->getSubExpr())
+ return ICE->Retain();
+
+ return new (Context) ImplicitCastExpr(ICE->getType(),
+ ICE->getCastKind(),
+ SubExpr,
+ ICE->isLvalueCast());
+ }
+
+ if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) {
assert(UnOp->getOpcode() == UnaryOperator::AddrOf &&
"Can only take the address of an overloaded function");
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
if (Method->isStatic()) {
// Do nothing: static member functions aren't any different
// from non-member functions.
- } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr())) {
- if (DRE->getQualifier()) {
- // We have taken the address of a pointer to member
- // function. Perform the computation here so that we get the
- // appropriate pointer to member type.
- DRE->setDecl(Fn);
- DRE->setType(Fn->getType());
- QualType ClassType
- = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
- E->setType(Context.getMemberPointerType(Fn->getType(),
- ClassType.getTypePtr()));
- return E;
- }
+ } else {
+ // Fix the sub expression, which really has to be an
+ // UnresolvedLookupExpr holding an overloaded member function
+ // or template.
+ Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn);
+ if (SubExpr == UnOp->getSubExpr())
+ return UnOp->Retain();
+
+ assert(isa<DeclRefExpr>(SubExpr)
+ && "fixed to something other than a decl ref");
+ assert(cast<DeclRefExpr>(SubExpr)->getQualifier()
+ && "fixed to a member ref with no nested name qualifier");
+
+ // We have taken the address of a pointer to member
+ // function. Perform the computation here so that we get the
+ // appropriate pointer to member type.
+ QualType ClassType
+ = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
+ QualType MemPtrType
+ = Context.getMemberPointerType(Fn->getType(), ClassType.getTypePtr());
+
+ return new (Context) UnaryOperator(SubExpr, UnaryOperator::AddrOf,
+ MemPtrType, UnOp->getOperatorLoc());
}
- // FIXME: TemplateIdRefExpr referring to a member function template
- // specialization!
}
- Expr *NewExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn);
- UnOp->setSubExpr(NewExpr);
- UnOp->setType(Context.getPointerType(NewExpr->getType()));
+ Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn);
+ if (SubExpr == UnOp->getSubExpr())
+ return UnOp->Retain();
- return UnOp;
- } else if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) {
- assert((isa<OverloadedFunctionDecl>(DR->getDecl()) ||
- isa<FunctionTemplateDecl>(DR->getDecl()) ||
- isa<FunctionDecl>(DR->getDecl())) &&
- "Expected function or function template");
- DR->setDecl(Fn);
- E->setType(Fn->getType());
- } else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(E)) {
- MemExpr->setMemberDecl(Fn);
- E->setType(Fn->getType());
- } else if (TemplateIdRefExpr *TID = dyn_cast<TemplateIdRefExpr>(E)) {
- E = DeclRefExpr::Create(Context,
- TID->getQualifier(), TID->getQualifierRange(),
- Fn, TID->getTemplateNameLoc(),
- true,
- TID->getLAngleLoc(),
- TID->getTemplateArgs(),
- TID->getNumTemplateArgs(),
- TID->getRAngleLoc(),
- Fn->getType(),
- /*FIXME?*/false, /*FIXME?*/false);
-
- // FIXME: Don't destroy TID here, since we need its template arguments
- // to survive.
- // TID->Destroy(Context);
- } else if (isa<UnresolvedFunctionNameExpr>(E)) {
- return DeclRefExpr::Create(Context,
- /*Qualifier=*/0,
- /*QualifierRange=*/SourceRange(),
- Fn, E->getLocStart(),
- Fn->getType(), false, false);
- } else {
- assert(false && "Invalid reference to overloaded function");
+ return new (Context) UnaryOperator(SubExpr, UnaryOperator::AddrOf,
+ Context.getPointerType(SubExpr->getType()),
+ UnOp->getOperatorLoc());
+ }
+
+ if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
+ 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);
+ }
+
+ return DeclRefExpr::Create(Context,
+ ULE->getQualifier(),
+ ULE->getQualifierRange(),
+ Fn,
+ ULE->getNameLoc(),
+ Fn->getType());
+ }
+
+ if (UnresolvedMemberExpr *MemExpr = dyn_cast<UnresolvedMemberExpr>(E)) {
+ // FIXME: avoid copy.
+ TemplateArgumentListInfo TemplateArgs;
+ if (MemExpr->hasExplicitTemplateArgs())
+ MemExpr->copyTemplateArgumentsInto(TemplateArgs);
+
+ return MemberExpr::Create(Context, MemExpr->getBase()->Retain(),
+ MemExpr->isArrow(),
+ MemExpr->getQualifier(),
+ MemExpr->getQualifierRange(),
+ Fn,
+ MemExpr->getMemberLoc(),
+ (MemExpr->hasExplicitTemplateArgs()
+ ? &TemplateArgs : 0),
+ Fn->getType());
}
- return E;
+ assert(false && "Invalid reference to overloaded function");
+ return E->Retain();
}
} // end namespace clang
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index d0f214f..de67a5f 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -15,9 +15,11 @@
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
@@ -59,6 +61,15 @@ Sema::OwningStmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg,
return Owned(new (Context) DeclStmt(DG, StartLoc, EndLoc));
}
+void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) {
+ DeclGroupRef DG = dg.getAsVal<DeclGroupRef>();
+
+ // If we have an invalid decl, just return.
+ if (DG.isNull() || !DG.isSingleDecl()) return;
+ // suppress any potential 'unused variable' warning.
+ DG.getSingleDecl()->setUsed();
+}
+
void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
const Expr *E = dyn_cast_or_null<Expr>(S);
if (!E)
@@ -225,16 +236,24 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
}
Action::OwningStmtResult
-Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal,
+Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar,
StmtArg ThenVal, SourceLocation ElseLoc,
StmtArg ElseVal) {
OwningExprResult CondResult(CondVal.release());
- Expr *condExpr = CondResult.takeAs<Expr>();
-
- assert(condExpr && "ActOnIfStmt(): missing expression");
- if (CheckBooleanCondition(condExpr, IfLoc)) {
- CondResult = condExpr;
+ VarDecl *ConditionVar = 0;
+ if (CondVar.get()) {
+ ConditionVar = CondVar.getAs<VarDecl>();
+ CondResult = CheckConditionVariable(ConditionVar);
+ if (CondResult.isInvalid())
+ return StmtError();
+ }
+ Expr *ConditionExpr = CondResult.takeAs<Expr>();
+ if (!ConditionExpr)
+ return StmtError();
+
+ if (CheckBooleanCondition(ConditionExpr, IfLoc)) {
+ CondResult = ConditionExpr;
return StmtError();
}
@@ -254,41 +273,23 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal,
DiagnoseUnusedExprResult(elseStmt);
CondResult.release();
- return Owned(new (Context) IfStmt(IfLoc, condExpr, thenStmt,
- ElseLoc, elseStmt));
+ return Owned(new (Context) IfStmt(IfLoc, ConditionVar, ConditionExpr,
+ thenStmt, ElseLoc, elseStmt));
}
Action::OwningStmtResult
-Sema::ActOnStartOfSwitchStmt(ExprArg cond) {
- Expr *Cond = cond.takeAs<Expr>();
-
- if (getLangOptions().CPlusPlus) {
- // C++ 6.4.2.p2:
- // The condition shall be of integral type, enumeration type, or of a class
- // type for which a single conversion function to integral or enumeration
- // type exists (12.3). If the condition is of class type, the condition is
- // converted by calling that conversion function, and the result of the
- // conversion is used in place of the original condition for the remainder
- // of this section. Integral promotions are performed.
- if (!Cond->isTypeDependent()) {
- QualType Ty = Cond->getType();
-
- // FIXME: Handle class types.
-
- // If the type is wrong a diagnostic will be emitted later at
- // ActOnFinishSwitchStmt.
- if (Ty->isIntegralType() || Ty->isEnumeralType()) {
- // Integral promotions are performed.
- // FIXME: Integral promotions for C++ are not complete.
- UsualUnaryConversions(Cond);
- }
- }
- } else {
- // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
- UsualUnaryConversions(Cond);
+Sema::ActOnStartOfSwitchStmt(FullExprArg cond, DeclPtrTy CondVar) {
+ OwningExprResult CondResult(cond.release());
+
+ VarDecl *ConditionVar = 0;
+ if (CondVar.get()) {
+ ConditionVar = CondVar.getAs<VarDecl>();
+ CondResult = CheckConditionVariable(ConditionVar);
+ if (CondResult.isInvalid())
+ return StmtError();
}
-
- SwitchStmt *SS = new (Context) SwitchStmt(Cond);
+ SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar,
+ CondResult.takeAs<Expr>());
getSwitchStack().push_back(SS);
return Owned(SS);
}
@@ -383,6 +384,103 @@ static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) {
return expr->getType();
}
+/// \brief Check (and possibly convert) the condition in a switch
+/// statement in C++.
+static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc,
+ Expr *&CondExpr) {
+ if (CondExpr->isTypeDependent())
+ return false;
+
+ QualType CondType = CondExpr->getType();
+
+ // C++ 6.4.2.p2:
+ // The condition shall be of integral type, enumeration type, or of a class
+ // type for which a single conversion function to integral or enumeration
+ // type exists (12.3). If the condition is of class type, the condition is
+ // converted by calling that conversion function, and the result of the
+ // conversion is used in place of the original condition for the remainder
+ // of this section. Integral promotions are performed.
+
+ // Make sure that the condition expression has a complete type,
+ // otherwise we'll never find any conversions.
+ if (S.RequireCompleteType(SwitchLoc, CondType,
+ PDiag(diag::err_switch_incomplete_class_type)
+ << CondExpr->getSourceRange()))
+ return true;
+
+ llvm::SmallVector<CXXConversionDecl *, 4> ViableConversions;
+ llvm::SmallVector<CXXConversionDecl *, 4> ExplicitConversions;
+ if (const RecordType *RecordTy = CondType->getAs<RecordType>()) {
+ const UnresolvedSet *Conversions
+ = cast<CXXRecordDecl>(RecordTy->getDecl())
+ ->getVisibleConversionFunctions();
+ for (UnresolvedSet::iterator I = Conversions->begin(),
+ E = Conversions->end(); I != E; ++I) {
+ if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(*I))
+ if (Conversion->getConversionType().getNonReferenceType()
+ ->isIntegralType()) {
+ if (Conversion->isExplicit())
+ ExplicitConversions.push_back(Conversion);
+ else
+ ViableConversions.push_back(Conversion);
+ }
+ }
+
+ switch (ViableConversions.size()) {
+ case 0:
+ if (ExplicitConversions.size() == 1) {
+ // The user probably meant to invoke the given explicit
+ // conversion; use it.
+ QualType ConvTy
+ = ExplicitConversions[0]->getConversionType()
+ .getNonReferenceType();
+ std::string TypeStr;
+ ConvTy.getAsStringInternal(TypeStr, S.Context.PrintingPolicy);
+
+ S.Diag(SwitchLoc, diag::err_switch_explicit_conversion)
+ << CondType << ConvTy << CondExpr->getSourceRange()
+ << CodeModificationHint::CreateInsertion(CondExpr->getLocStart(),
+ "static_cast<" + TypeStr + ">(")
+ << CodeModificationHint::CreateInsertion(
+ S.PP.getLocForEndOfToken(CondExpr->getLocEnd()),
+ ")");
+ S.Diag(ExplicitConversions[0]->getLocation(),
+ diag::note_switch_conversion)
+ << ConvTy->isEnumeralType() << ConvTy;
+
+ // If we aren't in a SFINAE context, build a call to the
+ // explicit conversion function.
+ if (S.isSFINAEContext())
+ return true;
+
+ CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ExplicitConversions[0]);
+ }
+
+ // We'll complain below about a non-integral condition type.
+ break;
+
+ case 1:
+ // Apply this conversion.
+ CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ViableConversions[0]);
+ break;
+
+ default:
+ S.Diag(SwitchLoc, diag::err_switch_multiple_conversions)
+ << CondType << CondExpr->getSourceRange();
+ for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
+ QualType ConvTy
+ = ViableConversions[I]->getConversionType().getNonReferenceType();
+ S.Diag(ViableConversions[I]->getLocation(),
+ diag::note_switch_conversion)
+ << ConvTy->isEnumeralType() << ConvTy;
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
Action::OwningStmtResult
Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
StmtArg Body) {
@@ -394,8 +492,23 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
SS->setBody(BodyStmt, SwitchLoc);
getSwitchStack().pop_back();
+ if (SS->getCond() == 0) {
+ SS->Destroy(Context);
+ return StmtError();
+ }
+
Expr *CondExpr = SS->getCond();
+ QualType CondTypeBeforePromotion =
+ GetTypeBeforeIntegralPromotion(CondExpr);
+
+ if (getLangOptions().CPlusPlus &&
+ CheckCXXSwitchCondition(*this, SwitchLoc, CondExpr))
+ return StmtError();
+
+ // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
+ UsualUnaryConversions(CondExpr);
QualType CondType = CondExpr->getType();
+ SS->setCond(CondExpr);
// C++ 6.4.2.p2:
// Integral promotions are performed (on the switch condition).
@@ -404,9 +517,6 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
// type (before the promotion) doesn't make sense, even when it can
// be represented by the promoted type. Therefore we need to find
// the pre-promotion type of the switch condition.
- QualType CondTypeBeforePromotion =
- GetTypeBeforeIntegralPromotion(CondExpr);
-
if (!CondExpr->isTypeDependent()) {
if (!CondType->isIntegerType()) { // C99 6.8.4.2p1
Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer)
@@ -614,21 +724,32 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
}
Action::OwningStmtResult
-Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, StmtArg Body) {
- ExprArg CondArg(Cond.release());
- Expr *condExpr = CondArg.takeAs<Expr>();
- assert(condExpr && "ActOnWhileStmt(): missing expression");
-
- if (CheckBooleanCondition(condExpr, WhileLoc)) {
- CondArg = condExpr;
+Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond,
+ DeclPtrTy CondVar, StmtArg Body) {
+ OwningExprResult CondResult(Cond.release());
+
+ VarDecl *ConditionVar = 0;
+ if (CondVar.get()) {
+ ConditionVar = CondVar.getAs<VarDecl>();
+ CondResult = CheckConditionVariable(ConditionVar);
+ if (CondResult.isInvalid())
+ return StmtError();
+ }
+ Expr *ConditionExpr = CondResult.takeAs<Expr>();
+ if (!ConditionExpr)
+ return StmtError();
+
+ if (CheckBooleanCondition(ConditionExpr, WhileLoc)) {
+ CondResult = ConditionExpr;
return StmtError();
}
Stmt *bodyStmt = Body.takeAs<Stmt>();
DiagnoseUnusedExprResult(bodyStmt);
- CondArg.release();
- return Owned(new (Context) WhileStmt(condExpr, bodyStmt, WhileLoc));
+ CondResult.release();
+ return Owned(new (Context) WhileStmt(ConditionVar, ConditionExpr, bodyStmt,
+ WhileLoc));
}
Action::OwningStmtResult
@@ -653,12 +774,10 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
Action::OwningStmtResult
Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
- StmtArg first, ExprArg second, ExprArg third,
+ StmtArg first, FullExprArg second, DeclPtrTy secondVar,
+ FullExprArg third,
SourceLocation RParenLoc, StmtArg body) {
Stmt *First = static_cast<Stmt*>(first.get());
- Expr *Second = second.takeAs<Expr>();
- Expr *Third = static_cast<Expr*>(third.get());
- Stmt *Body = static_cast<Stmt*>(body.get());
if (!getLangOptions().CPlusPlus) {
if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) {
@@ -676,20 +795,33 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
}
}
}
+
+ OwningExprResult SecondResult(second.release());
+ VarDecl *ConditionVar = 0;
+ if (secondVar.get()) {
+ ConditionVar = secondVar.getAs<VarDecl>();
+ SecondResult = CheckConditionVariable(ConditionVar);
+ if (SecondResult.isInvalid())
+ return StmtError();
+ }
+
+ Expr *Second = SecondResult.takeAs<Expr>();
if (Second && CheckBooleanCondition(Second, ForLoc)) {
- second = Second;
+ SecondResult = Second;
return StmtError();
}
+ Expr *Third = third.release().takeAs<Expr>();
+ Stmt *Body = static_cast<Stmt*>(body.get());
+
DiagnoseUnusedExprResult(First);
DiagnoseUnusedExprResult(Third);
DiagnoseUnusedExprResult(Body);
first.release();
- third.release();
body.release();
- return Owned(new (Context) ForStmt(First, Second, Third, Body, ForLoc,
- LParenLoc, RParenLoc));
+ return Owned(new (Context) ForStmt(First, Second, ConditionVar, Third, Body,
+ ForLoc, LParenLoc, RParenLoc));
}
Action::OwningStmtResult
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 31cd300..f47577e 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -20,7 +20,6 @@
#include "clang/Parse/Template.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/ADT/StringExtras.h"
using namespace clang;
@@ -59,44 +58,20 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) {
return 0;
}
- OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D);
- if (!Ovl)
- return 0;
-
- for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
- FEnd = Ovl->function_end();
- F != FEnd; ++F) {
- if (FunctionTemplateDecl *FuncTmpl = dyn_cast<FunctionTemplateDecl>(*F)) {
- // We've found a function template. Determine whether there are
- // any other function templates we need to bundle together in an
- // OverloadedFunctionDecl
- for (++F; F != FEnd; ++F) {
- if (isa<FunctionTemplateDecl>(*F))
- break;
- }
-
- if (F != FEnd) {
- // Build an overloaded function decl containing only the
- // function templates in Ovl.
- OverloadedFunctionDecl *OvlTemplate
- = OverloadedFunctionDecl::Create(Context,
- Ovl->getDeclContext(),
- Ovl->getDeclName());
- OvlTemplate->addOverload(FuncTmpl);
- OvlTemplate->addOverload(*F);
- for (++F; F != FEnd; ++F) {
- if (isa<FunctionTemplateDecl>(*F))
- OvlTemplate->addOverload(*F);
- }
-
- return OvlTemplate;
- }
+ return 0;
+}
- return FuncTmpl;
- }
+static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) {
+ LookupResult::Filter filter = R.makeFilter();
+ while (filter.hasNext()) {
+ NamedDecl *Orig = filter.next();
+ NamedDecl *Repl = isAcceptableTemplateName(C, Orig->getUnderlyingDecl());
+ if (!Repl)
+ filter.erase();
+ else if (Repl != Orig)
+ filter.replace(Repl);
}
-
- return 0;
+ filter.done();
}
TemplateNameKind Sema::isTemplateName(Scope *S,
@@ -117,18 +92,65 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
Name.OperatorFunctionId.Operator);
break;
+ case UnqualifiedId::IK_LiteralOperatorId:
+ TName = Context.DeclarationNames.getCXXLiteralOperatorName(Name.Identifier);
+ break;
+
default:
return TNK_Non_template;
}
-
+
+ QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
+
+ LookupResult R(*this, TName, SourceLocation(), LookupOrdinaryName);
+ R.suppressDiagnostics();
+ LookupTemplateName(R, S, SS, ObjectType, EnteringContext);
+ 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));
+ } else {
+ TemplateResult = TemplateTy::make(
+ TemplateName(cast<TemplateDecl>(Template)));
+ }
+
+ if (isa<ClassTemplateDecl>(Template) ||
+ isa<TemplateTemplateParmDecl>(Template))
+ return TNK_Type_template;
+
+ assert((isa<FunctionTemplateDecl>(Template) ||
+ isa<OverloadedFunctionDecl>(Template)) &&
+ "Unhandled template kind in Sema::isTemplateName");
+ return TNK_Function_template;
+}
+
+void Sema::LookupTemplateName(LookupResult &Found,
+ Scope *S, const CXXScopeSpec &SS,
+ QualType ObjectType,
+ bool EnteringContext) {
// Determine where to perform name lookup
DeclContext *LookupCtx = 0;
bool isDependent = false;
- if (ObjectTypePtr) {
+ if (!ObjectType.isNull()) {
// This nested-name-specifier occurs in a member access expression, e.g.,
// x->B::f, and we are looking into the type of the object.
assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
- QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
LookupCtx = computeDeclContext(ObjectType);
isDependent = ObjectType->isDependentType();
assert((isDependent || !ObjectType->isIncompleteType()) &&
@@ -141,10 +163,9 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
// The declaration context must be complete.
if (LookupCtx && RequireCompleteDeclContext(SS))
- return TNK_Non_template;
+ return;
}
- LookupResult Found(*this, TName, SourceLocation(), LookupOrdinaryName);
bool ObjectTypeSearchedInScope = false;
if (LookupCtx) {
// Perform "qualified" name lookup into the declaration context we
@@ -153,7 +174,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
// nested-name-specifier.
LookupQualifiedName(Found, LookupCtx);
- if (ObjectTypePtr && Found.empty()) {
+ if (!ObjectType.isNull() && Found.empty()) {
// C++ [basic.lookup.classref]p1:
// In a class member access expression (5.2.5), if the . or -> token is
// immediately followed by an identifier followed by a <, the
@@ -166,12 +187,12 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
//
// FIXME: When we're instantiating a template, do we actually have to
// look in the scope of the template? Seems fishy...
- LookupName(Found, S);
+ if (S) LookupName(Found, S);
ObjectTypeSearchedInScope = true;
}
} else if (isDependent) {
// We cannot look into a dependent object type or
- return TNK_Non_template;
+ return;
} else {
// Perform unqualified name lookup in the current scope.
LookupName(Found, S);
@@ -181,27 +202,26 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
assert(!Found.isAmbiguous() &&
"Cannot handle template name-lookup ambiguities");
- NamedDecl *Template
- = isAcceptableTemplateName(Context, Found.getAsSingleDecl(Context));
- if (!Template)
- return TNK_Non_template;
+ FilterAcceptableTemplateNames(Context, Found);
+ if (Found.empty())
+ return;
- if (ObjectTypePtr && !ObjectTypeSearchedInScope) {
+ if (S && !ObjectType.isNull() && !ObjectTypeSearchedInScope) {
// C++ [basic.lookup.classref]p1:
// [...] If the lookup in the class of the object expression finds a
// template, the name is also looked up in the context of the entire
// postfix-expression and [...]
//
- LookupResult FoundOuter(*this, TName, SourceLocation(), LookupOrdinaryName);
+ LookupResult FoundOuter(*this, Found.getLookupName(), Found.getNameLoc(),
+ LookupOrdinaryName);
LookupName(FoundOuter, S);
+ FilterAcceptableTemplateNames(Context, FoundOuter);
// FIXME: Handle ambiguities in this lookup better
- NamedDecl *OuterTemplate
- = isAcceptableTemplateName(Context, FoundOuter.getAsSingleDecl(Context));
- if (!OuterTemplate) {
+ if (FoundOuter.empty()) {
// - if the name is not found, the name found in the class of the
// object expression is used, otherwise
- } else if (!isa<ClassTemplateDecl>(OuterTemplate)) {
+ } else if (!FoundOuter.getAsSingle<ClassTemplateDecl>()) {
// - if the name is found in the context of the entire
// postfix-expression and does not name a class template, the name
// found in the class of the object expression is used, otherwise
@@ -209,49 +229,165 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
// - if the name found is a class template, it must refer to the same
// entity as the one found in the class of the object expression,
// otherwise the program is ill-formed.
- if (OuterTemplate->getCanonicalDecl() != Template->getCanonicalDecl()) {
- Diag(Name.getSourceRange().getBegin(),
+ if (!Found.isSingleResult() ||
+ Found.getFoundDecl()->getCanonicalDecl()
+ != FoundOuter.getFoundDecl()->getCanonicalDecl()) {
+ Diag(Found.getNameLoc(),
diag::err_nested_name_member_ref_lookup_ambiguous)
- << TName
- << Name.getSourceRange();
- Diag(Template->getLocation(), diag::note_ambig_member_ref_object_type)
- << QualType::getFromOpaquePtr(ObjectTypePtr);
- Diag(OuterTemplate->getLocation(), diag::note_ambig_member_ref_scope);
+ << Found.getLookupName();
+ Diag(Found.getRepresentativeDecl()->getLocation(),
+ diag::note_ambig_member_ref_object_type)
+ << ObjectType;
+ Diag(FoundOuter.getFoundDecl()->getLocation(),
+ diag::note_ambig_member_ref_scope);
// Recover by taking the template that we found in the object
// expression's type.
}
}
}
+}
- 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));
- } else {
- TemplateResult = TemplateTy::make(
- TemplateName(cast<TemplateDecl>(Template)));
+/// 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;
}
- if (isa<ClassTemplateDecl>(Template) ||
- isa<TemplateTemplateParmDecl>(Template))
- return TNK_Type_template;
+ return false;
+}
- assert((isa<FunctionTemplateDecl>(Template) ||
- isa<OverloadedFunctionDecl>(Template)) &&
- "Unhandled template kind in Sema::isTemplateName");
- return TNK_Function_template;
+/// 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.
+Sema::OwningExprResult
+Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
+ DeclarationName Name,
+ SourceLocation NameLoc,
+ bool CheckForImplicitMember,
+ 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);
+
+ // 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,
+ /*Op*/ SourceLocation(),
+ Qualifier, SS.getRange(),
+ FirstQualifierInScope,
+ Name, NameLoc,
+ TemplateArgs));
+ }
+
+ return BuildDependentDeclRefExpr(SS, Name, NameLoc, TemplateArgs);
+}
+
+Sema::OwningExprResult
+Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
+ DeclarationName Name,
+ SourceLocation NameLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ return Owned(DependentScopeDeclRefExpr::Create(Context,
+ static_cast<NestedNameSpecifier*>(SS.getScopeRep()),
+ SS.getRange(),
+ Name, NameLoc,
+ TemplateArgs));
}
/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
@@ -317,12 +453,11 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
/// \brief Translates template arguments as provided by the parser
/// into template arguments used by semantic analysis.
-void Sema::translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
- llvm::SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
- TemplateArgs.reserve(TemplateArgsIn.size());
-
+void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn,
+ TemplateArgumentListInfo &TemplateArgs) {
for (unsigned I = 0, Last = TemplateArgsIn.size(); I != Last; ++I)
- TemplateArgs.push_back(translateTemplateArgument(*this, TemplateArgsIn[I]));
+ TemplateArgs.addArgument(translateTemplateArgument(*this,
+ TemplateArgsIn[I]));
}
/// ActOnTypeParameter - Called when a C++ template type parameter
@@ -595,7 +730,7 @@ Sema::ActOnTemplateParameterList(unsigned Depth,
DeclPtrTy *Params, unsigned NumParams,
SourceLocation RAngleLoc) {
if (ExportLoc.isValid())
- Diag(ExportLoc, diag::note_template_export_unsupported);
+ Diag(ExportLoc, diag::warn_template_export_unsupported);
return TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
(NamedDecl**)Params, NumParams,
@@ -756,7 +891,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// merging in the template parameter list from the previous class
// template declaration.
if (CheckTemplateParameterList(TemplateParams,
- PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0))
+ PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0,
+ TPC_ClassTemplate))
Invalid = true;
// FIXME: If we had a scope specifier, we better have a previous template
@@ -837,6 +973,55 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
return DeclPtrTy::make(NewTemplate);
}
+/// \brief Diagnose the presence of a default template argument on a
+/// template parameter, which is ill-formed in certain contexts.
+///
+/// \returns true if the default template argument should be dropped.
+static bool DiagnoseDefaultTemplateArgument(Sema &S,
+ Sema::TemplateParamListContext TPC,
+ SourceLocation ParamLoc,
+ SourceRange DefArgRange) {
+ switch (TPC) {
+ case Sema::TPC_ClassTemplate:
+ return false;
+
+ case Sema::TPC_FunctionTemplate:
+ // C++ [temp.param]p9:
+ // A default template-argument shall not be specified in a
+ // function template declaration or a function template
+ // definition [...]
+ // (This sentence is not in C++0x, per DR226).
+ if (!S.getLangOptions().CPlusPlus0x)
+ S.Diag(ParamLoc,
+ diag::err_template_parameter_default_in_function_template)
+ << DefArgRange;
+ return false;
+
+ case Sema::TPC_ClassTemplateMember:
+ // C++0x [temp.param]p9:
+ // A default template-argument shall not be specified in the
+ // template-parameter-lists of the definition of a member of a
+ // class template that appears outside of the member's class.
+ S.Diag(ParamLoc, diag::err_template_parameter_default_template_member)
+ << DefArgRange;
+ return true;
+
+ case Sema::TPC_FriendFunctionTemplate:
+ // C++ [temp.param]p9:
+ // A default template-argument shall not be specified in a
+ // friend template declaration.
+ S.Diag(ParamLoc, diag::err_template_parameter_default_friend_template)
+ << DefArgRange;
+ return true;
+
+ // FIXME: C++0x [temp.param]p9 allows default template-arguments
+ // for friend function templates if there is only a single
+ // declaration (and it is a definition). Strange!
+ }
+
+ return false;
+}
+
/// \brief Checks the validity of a template parameter list, possibly
/// considering the template parameter list from a previous
/// declaration.
@@ -855,9 +1040,13 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
/// arguments will be merged from the old template parameter list to
/// the new template parameter list.
///
+/// \param TPC Describes the context in which we are checking the given
+/// template parameter list.
+///
/// \returns true if an error occurred, false otherwise.
bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
- TemplateParameterList *OldParams) {
+ TemplateParameterList *OldParams,
+ TemplateParamListContext TPC) {
bool Invalid = false;
// C++ [temp.param]p10:
@@ -897,9 +1086,17 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
Invalid = true;
}
- // Merge default arguments for template type parameters.
if (TemplateTypeParmDecl *NewTypeParm
= dyn_cast<TemplateTypeParmDecl>(*NewParam)) {
+ // Check the presence of a default argument here.
+ if (NewTypeParm->hasDefaultArgument() &&
+ DiagnoseDefaultTemplateArgument(*this, TPC,
+ NewTypeParm->getLocation(),
+ NewTypeParm->getDefaultArgumentInfo()->getTypeLoc()
+ .getFullSourceRange()))
+ NewTypeParm->removeDefaultArgument();
+
+ // Merge default arguments for template type parameters.
TemplateTypeParmDecl *OldTypeParm
= OldParams? cast<TemplateTypeParmDecl>(*OldParam) : 0;
@@ -929,6 +1126,15 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
MissingDefaultArg = true;
} else if (NonTypeTemplateParmDecl *NewNonTypeParm
= dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
+ // Check the presence of a default argument here.
+ if (NewNonTypeParm->hasDefaultArgument() &&
+ DiagnoseDefaultTemplateArgument(*this, TPC,
+ NewNonTypeParm->getLocation(),
+ NewNonTypeParm->getDefaultArgument()->getSourceRange())) {
+ NewNonTypeParm->getDefaultArgument()->Destroy(Context);
+ NewNonTypeParm->setDefaultArgument(0);
+ }
+
// Merge default arguments for non-type template parameters
NonTypeTemplateParmDecl *OldNonTypeParm
= OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : 0;
@@ -955,9 +1161,16 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
} else if (SawDefaultArgument)
MissingDefaultArg = true;
} else {
- // Merge default arguments for template template parameters
+ // Check the presence of a default argument here.
TemplateTemplateParmDecl *NewTemplateParm
= cast<TemplateTemplateParmDecl>(*NewParam);
+ if (NewTemplateParm->hasDefaultArgument() &&
+ DiagnoseDefaultTemplateArgument(*this, TPC,
+ NewTemplateParm->getLocation(),
+ NewTemplateParm->getDefaultArgument().getSourceRange()))
+ NewTemplateParm->setDefaultArgument(TemplateArgumentLoc());
+
+ // Merge default arguments for template template parameters
TemplateTemplateParmDecl *OldTemplateParm
= OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0;
if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
@@ -1049,6 +1262,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// template-ids will match up with the template parameter lists.
llvm::SmallVector<const TemplateSpecializationType *, 4>
TemplateIdsInSpecifier;
+ llvm::SmallVector<ClassTemplateSpecializationDecl *, 4>
+ ExplicitSpecializationsInSpecifier;
for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
NNS; NNS = NNS->getPrefix()) {
if (const TemplateSpecializationType *SpecType
@@ -1062,10 +1277,10 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
= cast<ClassTemplateSpecializationDecl>(Record->getDecl());
// If the nested name specifier refers to an explicit specialization,
// we don't need a template<> header.
- // FIXME: revisit this approach once we cope with specializations
- // properly.
- if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization)
+ if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization) {
+ ExplicitSpecializationsInSpecifier.push_back(SpecDecl);
continue;
+ }
}
TemplateIdsInSpecifier.push_back(SpecType);
@@ -1128,6 +1343,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
ExpectedTemplateParams,
true, TPL_TemplateMatch);
}
+
+ CheckTemplateParameterList(ParamLists[Idx], 0, TPC_ClassTemplateMember);
} else if (ParamLists[Idx]->size() > 0)
Diag(ParamLists[Idx]->getTemplateLoc(),
diag::err_template_param_list_matches_nontemplate)
@@ -1146,10 +1363,20 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// If there were too many template parameter lists, complain about that now.
if (Idx != NumParamLists - 1) {
while (Idx < NumParamLists - 1) {
+ bool isExplicitSpecHeader = ParamLists[Idx]->size() == 0;
Diag(ParamLists[Idx]->getTemplateLoc(),
- diag::err_template_spec_extra_headers)
+ isExplicitSpecHeader? diag::warn_template_spec_extra_headers
+ : diag::err_template_spec_extra_headers)
<< SourceRange(ParamLists[Idx]->getTemplateLoc(),
ParamLists[Idx]->getRAngleLoc());
+
+ if (isExplicitSpecHeader && !ExplicitSpecializationsInSpecifier.empty()) {
+ Diag(ExplicitSpecializationsInSpecifier.back()->getLocation(),
+ diag::note_explicit_template_spec_does_not_need_header)
+ << ExplicitSpecializationsInSpecifier.back();
+ ExplicitSpecializationsInSpecifier.pop_back();
+ }
+
++Idx;
}
}
@@ -1161,24 +1388,19 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation RAngleLoc) {
+ const TemplateArgumentListInfo &TemplateArgs) {
TemplateDecl *Template = Name.getAsTemplateDecl();
if (!Template) {
// The template name does not resolve to a template, so we just
// build a dependent template-id type.
- return Context.getTemplateSpecializationType(Name, TemplateArgs,
- NumTemplateArgs);
+ return Context.getTemplateSpecializationType(Name, TemplateArgs);
}
// Check that the template argument list is well-formed for this
// template.
TemplateArgumentListBuilder Converted(Template->getTemplateParameters(),
- NumTemplateArgs);
- if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc,
- TemplateArgs, NumTemplateArgs, RAngleLoc,
+ TemplateArgs.size());
+ if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs,
false, Converted))
return QualType();
@@ -1190,8 +1412,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
if (Name.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs,
- NumTemplateArgs)) {
+ TemplateArgs)) {
// This class template specialization is a dependent
// type. Therefore, its canonical type is another class template
// specialization type that contains all of the converted
@@ -1240,8 +1461,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// Build the fully-sugared type for this class template
// specialization, which refers back to the class template
// specialization we created or found.
- return Context.getTemplateSpecializationType(Name, TemplateArgs,
- NumTemplateArgs, CanonType);
+ return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType);
}
Action::TypeResult
@@ -1252,13 +1472,10 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc,
TemplateName Template = TemplateD.getAsVal<TemplateName>();
// Translate the parser's template argument list in our AST format.
- llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs;
+ TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
- QualType Result = CheckTemplateIdType(Template, TemplateLoc, LAngleLoc,
- TemplateArgs.data(),
- TemplateArgs.size(),
- RAngleLoc);
+ QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs);
TemplateArgsIn.release();
if (Result.isNull())
@@ -1310,64 +1527,72 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult,
return ElabType.getAsOpaquePtr();
}
-Sema::OwningExprResult Sema::BuildTemplateIdExpr(NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- TemplateName Template,
- SourceLocation TemplateNameLoc,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation RAngleLoc) {
+Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ bool RequiresADL,
+ const TemplateArgumentListInfo &TemplateArgs) {
// FIXME: Can we do any checking at this point? I guess we could check the
// template arguments that we have against the template name, if the template
// name refers to a single template. That's not a terribly common case,
// though.
-
- // Cope with an implicit member access in a C++ non-static member function.
- NamedDecl *D = Template.getAsTemplateDecl();
- if (!D)
- D = Template.getAsOverloadedFunctionDecl();
-
- CXXScopeSpec SS;
- SS.setRange(QualifierRange);
- SS.setScopeRep(Qualifier);
- QualType ThisType, MemberType;
- if (D && isImplicitMemberReference(&SS, D, TemplateNameLoc,
- ThisType, MemberType)) {
- Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType);
- return Owned(MemberExpr::Create(Context, This, true,
- Qualifier, QualifierRange,
- D, TemplateNameLoc, true,
- LAngleLoc, TemplateArgs,
- NumTemplateArgs, RAngleLoc,
- Context.OverloadTy));
+
+ // These should be filtered out by our callers.
+ assert(!R.empty() && "empty lookup results when building templateid");
+ assert(!R.isAmbiguous() && "ambiguous lookup when building templateid");
+
+ NestedNameSpecifier *Qualifier = 0;
+ SourceRange QualifierRange;
+ if (SS.isSet()) {
+ Qualifier = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+ QualifierRange = SS.getRange();
}
- return Owned(TemplateIdRefExpr::Create(Context, Context.OverloadTy,
- Qualifier, QualifierRange,
- Template, TemplateNameLoc, LAngleLoc,
- TemplateArgs,
- NumTemplateArgs, RAngleLoc));
+ bool Dependent
+ = UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(),
+ &TemplateArgs);
+ UnresolvedLookupExpr *ULE
+ = UnresolvedLookupExpr::Create(Context, Dependent,
+ Qualifier, QualifierRange,
+ R.getLookupName(), R.getNameLoc(),
+ RequiresADL, TemplateArgs);
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
+ ULE->addDecl(*I);
+
+ return Owned(ULE);
}
-Sema::OwningExprResult Sema::ActOnTemplateIdExpr(const CXXScopeSpec &SS,
- TemplateTy TemplateD,
- SourceLocation TemplateNameLoc,
- SourceLocation LAngleLoc,
- ASTTemplateArgsPtr TemplateArgsIn,
- SourceLocation RAngleLoc) {
- TemplateName Template = TemplateD.getAsVal<TemplateName>();
+// We actually only call this from template instantiation.
+Sema::OwningExprResult
+Sema::BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS,
+ DeclarationName Name,
+ SourceLocation NameLoc,
+ const TemplateArgumentListInfo &TemplateArgs) {
+ DeclContext *DC;
+ if (!(DC = computeDeclContext(SS, false)) ||
+ DC->isDependentContext() ||
+ RequireCompleteDeclContext(SS))
+ return BuildDependentDeclRefExpr(SS, Name, NameLoc, &TemplateArgs);
+
+ LookupResult R(*this, Name, NameLoc, LookupOrdinaryName);
+ LookupTemplateName(R, (Scope*) 0, SS, QualType(), /*Entering*/ false);
+
+ if (R.isAmbiguous())
+ return ExprError();
+
+ if (R.empty()) {
+ Diag(NameLoc, diag::err_template_kw_refers_to_non_template)
+ << Name << SS.getRange();
+ return ExprError();
+ }
- // Translate the parser's template argument list in our AST format.
- llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs;
- translateTemplateArguments(TemplateArgsIn, TemplateArgs);
- TemplateArgsIn.release();
+ if (ClassTemplateDecl *Temp = R.getAsSingle<ClassTemplateDecl>()) {
+ Diag(NameLoc, diag::err_template_kw_refers_to_class_template)
+ << (NestedNameSpecifier*) SS.getScopeRep() << Name << SS.getRange();
+ Diag(Temp->getLocation(), diag::note_referenced_class_template);
+ return ExprError();
+ }
- return BuildTemplateIdExpr((NestedNameSpecifier *)SS.getScopeRep(),
- SS.getRange(),
- Template, TemplateNameLoc, LAngleLoc,
- TemplateArgs.data(), TemplateArgs.size(),
- RAngleLoc);
+ return BuildTemplateIdExpr(SS, R, /* ADL */ false, TemplateArgs);
}
/// \brief Form a dependent template name.
@@ -1381,10 +1606,11 @@ Sema::TemplateTy
Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
const CXXScopeSpec &SS,
UnqualifiedId &Name,
- TypeTy *ObjectType) {
+ TypeTy *ObjectType,
+ bool EnteringContext) {
if ((ObjectType &&
computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) ||
- (SS.isSet() && computeDeclContext(SS, false))) {
+ (SS.isSet() && computeDeclContext(SS, EnteringContext))) {
// C++0x [temp.names]p5:
// If a name prefixed by the keyword template is not the name of
// a template, the program is ill-formed. [Note: the keyword
@@ -1403,7 +1629,7 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
// rules, even in C++03 mode, retroactively applying the DR.
TemplateTy Template;
TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType,
- false, Template);
+ EnteringContext, Template);
if (TNK == TNK_Non_template) {
Diag(Name.getSourceRange().getBegin(),
diag::err_template_kw_refers_to_non_template)
@@ -1426,7 +1652,10 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
case UnqualifiedId::IK_OperatorFunctionId:
return TemplateTy::make(Context.getDependentTemplateName(Qualifier,
Name.OperatorFunctionId.Operator));
-
+
+ case UnqualifiedId::IK_LiteralOperatorId:
+ assert(false && "We don't support these; Parse shouldn't have allowed propagation");
+
default:
break;
}
@@ -1609,6 +1838,65 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
AllTemplateArgs);
}
+/// \brief If the given template parameter has a default template
+/// argument, substitute into that default template argument and
+/// return the corresponding template argument.
+TemplateArgumentLoc
+Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
+ SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc,
+ Decl *Param,
+ TemplateArgumentListBuilder &Converted) {
+ if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) {
+ if (!TypeParm->hasDefaultArgument())
+ return TemplateArgumentLoc();
+
+ DeclaratorInfo *DI = SubstDefaultTemplateArgument(*this, Template,
+ TemplateLoc,
+ RAngleLoc,
+ TypeParm,
+ Converted);
+ if (DI)
+ return TemplateArgumentLoc(TemplateArgument(DI->getType()), DI);
+
+ return TemplateArgumentLoc();
+ }
+
+ if (NonTypeTemplateParmDecl *NonTypeParm
+ = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (!NonTypeParm->hasDefaultArgument())
+ return TemplateArgumentLoc();
+
+ OwningExprResult Arg = SubstDefaultTemplateArgument(*this, Template,
+ TemplateLoc,
+ RAngleLoc,
+ NonTypeParm,
+ Converted);
+ if (Arg.isInvalid())
+ return TemplateArgumentLoc();
+
+ Expr *ArgE = Arg.takeAs<Expr>();
+ return TemplateArgumentLoc(TemplateArgument(ArgE), ArgE);
+ }
+
+ TemplateTemplateParmDecl *TempTempParm
+ = cast<TemplateTemplateParmDecl>(Param);
+ if (!TempTempParm->hasDefaultArgument())
+ return TemplateArgumentLoc();
+
+ TemplateName TName = SubstDefaultTemplateArgument(*this, Template,
+ TemplateLoc,
+ RAngleLoc,
+ TempTempParm,
+ Converted);
+ if (TName.isNull())
+ return TemplateArgumentLoc();
+
+ return TemplateArgumentLoc(TemplateArgument(TName),
+ TempTempParm->getDefaultArgument().getTemplateQualifierRange(),
+ TempTempParm->getDefaultArgument().getTemplateNameLoc());
+}
+
/// \brief Check that the given template argument corresponds to the given
/// template parameter.
bool Sema::CheckTemplateArgument(NamedDecl *Param,
@@ -1679,12 +1967,11 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
// parsed as a template template argument. However, since we now
// know that we need a non-type template argument, convert this
// template name into an expression.
- Expr *E = new (Context) UnresolvedDeclRefExpr(DTN->getIdentifier(),
- Context.DependentTy,
- Arg.getTemplateNameLoc(),
+ Expr *E = DependentScopeDeclRefExpr::Create(Context,
+ DTN->getQualifier(),
Arg.getTemplateQualifierRange(),
- DTN->getQualifier(),
- /*isAddressOfOperand=*/false);
+ DTN->getIdentifier(),
+ Arg.getTemplateNameLoc());
TemplateArgument Result;
if (CheckTemplateArgument(NTTP, NTTPType, E, Result))
@@ -1798,17 +2085,16 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
/// for specializing the given template.
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation RAngleLoc,
+ const TemplateArgumentListInfo &TemplateArgs,
bool PartialTemplateArgs,
TemplateArgumentListBuilder &Converted) {
TemplateParameterList *Params = Template->getTemplateParameters();
unsigned NumParams = Params->size();
- unsigned NumArgs = NumTemplateArgs;
+ unsigned NumArgs = TemplateArgs.size();
bool Invalid = false;
+ SourceLocation RAngleLoc = TemplateArgs.getRAngleLoc();
+
bool HasParameterPack =
NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack();
@@ -2048,7 +2334,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
// Functions must have external linkage.
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(DRE->getDecl())) {
- if (Func->getStorageClass() == FunctionDecl::Static) {
+ if (Func->getLinkage() != NamedDecl::ExternalLinkage) {
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_function_not_extern)
<< Func << Arg->getSourceRange();
@@ -2063,7 +2349,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
}
if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
- if (!Var->hasGlobalStorage()) {
+ if (Var->getLinkage() != NamedDecl::ExternalLinkage) {
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_object_not_extern)
<< Var << Arg->getSourceRange();
@@ -3046,16 +3332,17 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
}
// Translate the parser's template argument list in our AST format.
- llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs;
+ TemplateArgumentListInfo TemplateArgs;
+ TemplateArgs.setLAngleLoc(LAngleLoc);
+ TemplateArgs.setRAngleLoc(RAngleLoc);
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
// Check that the template argument list is well-formed for this
// template.
TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(),
TemplateArgs.size());
- if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
- TemplateArgs.data(), TemplateArgs.size(),
- RAngleLoc, false, Converted))
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
+ TemplateArgs, false, Converted))
return true;
assert((Converted.structuredSize() ==
@@ -3154,8 +3441,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TemplateParams,
ClassTemplate,
Converted,
- TemplateArgs.data(),
- TemplateArgs.size(),
+ TemplateArgs,
PrevPartial);
if (PrevPartial) {
@@ -3267,10 +3553,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// name based on the "canonical" representation used to store the
// template arguments in the specialization.
QualType WrittenTy
- = Context.getTemplateSpecializationType(Name,
- TemplateArgs.data(),
- TemplateArgs.size(),
- CanonType);
+ = Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType);
if (TUK != TUK_Friend)
Specialization->setTypeAsWritten(WrittenTy);
TemplateArgsIn.release();
@@ -3533,11 +3816,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
/// \param PrevDecl the set of declarations that
bool
Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
- bool HasExplicitTemplateArgs,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
- SourceLocation RAngleLoc,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous) {
// The set of function template specializations that could match this
// explicit function template specialization.
@@ -3564,9 +3843,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
TemplateDeductionInfo Info(Context);
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult TDK
- = DeduceTemplateArguments(FunTmpl, HasExplicitTemplateArgs,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
+ = DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs,
FD->getType(),
Specialization,
Info)) {
@@ -3589,7 +3866,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
PartialDiagnostic(diag::err_function_template_spec_no_match)
<< FD->getDeclName(),
PartialDiagnostic(diag::err_function_template_spec_ambiguous)
- << FD->getDeclName() << HasExplicitTemplateArgs,
+ << FD->getDeclName() << (ExplicitTemplateArgs != 0),
PartialDiagnostic(diag::note_function_template_spec_matched));
if (!Specialization)
return true;
@@ -3901,16 +4178,15 @@ Sema::ActOnExplicitInstantiation(Scope *S,
: TSK_ExplicitInstantiationDeclaration;
// Translate the parser's template argument list in our AST format.
- llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs;
+ TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
// Check that the template argument list is well-formed for this
// template.
TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(),
TemplateArgs.size());
- if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
- TemplateArgs.data(), TemplateArgs.size(),
- RAngleLoc, false, Converted))
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
+ TemplateArgs, false, Converted))
return true;
assert((Converted.structuredSize() ==
@@ -3938,6 +4214,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
ClassTemplateSpecializationDecl *Specialization = 0;
+ bool ReusedDecl = false;
if (PrevDecl) {
bool SuppressNew = false;
if (CheckSpecializationInstantiationRedecl(TemplateNameLoc, TSK,
@@ -3959,6 +4236,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
Specialization = PrevDecl;
Specialization->setLocation(TemplateNameLoc);
PrevDecl = 0;
+ ReusedDecl = true;
}
}
@@ -3991,18 +4269,18 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// on the "canonical" representation used to store the template
// arguments in the specialization.
QualType WrittenTy
- = Context.getTemplateSpecializationType(Name,
- TemplateArgs.data(),
- TemplateArgs.size(),
+ = Context.getTemplateSpecializationType(Name, TemplateArgs,
Context.getTypeDeclType(Specialization));
Specialization->setTypeAsWritten(WrittenTy);
TemplateArgsIn.release();
- // Add the explicit instantiation into its lexical context. However,
- // since explicit instantiations are never found by name lookup, we
- // just put it into the declaration context directly.
- Specialization->setLexicalDeclContext(CurContext);
- CurContext->addDecl(Specialization);
+ if (!ReusedDecl) {
+ // Add the explicit instantiation into its lexical context. However,
+ // since explicit instantiations are never found by name lookup, we
+ // just put it into the declaration context directly.
+ Specialization->setLexicalDeclContext(CurContext);
+ CurContext->addDecl(Specialization);
+ }
// C++ [temp.explicit]p3:
// A definition of a class template or class member template
@@ -4277,14 +4555,15 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// If the declarator is a template-id, translate the parser's template
// argument list into our AST format.
bool HasExplicitTemplateArgs = false;
- llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs;
+ TemplateArgumentListInfo TemplateArgs;
if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
+ TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
+ TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);
ASTTemplateArgsPtr TemplateArgsPtr(*this,
TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
- translateTemplateArguments(TemplateArgsPtr,
- TemplateArgs);
+ translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
HasExplicitTemplateArgs = true;
TemplateArgsPtr.release();
}
@@ -4315,8 +4594,8 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
TemplateDeductionInfo Info(Context);
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult TDK
- = DeduceTemplateArguments(FunTmpl, HasExplicitTemplateArgs,
- TemplateArgs.data(), TemplateArgs.size(),
+ = DeduceTemplateArguments(FunTmpl,
+ (HasExplicitTemplateArgs ? &TemplateArgs : 0),
R, Specialization, Info)) {
// FIXME: Keep track of almost-matches?
(void)TDK;
@@ -4365,12 +4644,12 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (SuppressNew)
return DeclPtrTy();
}
+
+ Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
if (TSK == TSK_ExplicitInstantiationDefinition)
InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization,
false, /*DefinitionRequired=*/true);
-
- Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
// C++0x [temp.explicit]p2:
// If the explicit instantiation is for a member function, a member class
@@ -4537,7 +4816,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
namespace {
// See Sema::RebuildTypeInCurrentInstantiation
- class VISIBILITY_HIDDEN CurrentInstantiationRebuilder
+ class CurrentInstantiationRebuilder
: public TreeTransform<CurrentInstantiationRebuilder> {
SourceLocation Loc;
DeclarationName Entity;
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 10594c7..613ffde 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -17,7 +17,6 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Parse/DeclSpec.h"
-#include "llvm/Support/Compiler.h"
#include <algorithm>
namespace clang {
@@ -1050,35 +1049,34 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentLoc *PartialTemplateArgs
= Partial->getTemplateArgsAsWritten();
unsigned N = Partial->getNumTemplateArgsAsWritten();
- llvm::SmallVector<TemplateArgumentLoc, 16> InstArgs(N);
+
+ // Note that we don't provide the langle and rangle locations.
+ TemplateArgumentListInfo InstArgs;
+
for (unsigned I = 0; I != N; ++I) {
Decl *Param = const_cast<NamedDecl *>(
ClassTemplate->getTemplateParameters()->getParam(I));
- if (Subst(PartialTemplateArgs[I], InstArgs[I],
+ TemplateArgumentLoc InstArg;
+ if (Subst(PartialTemplateArgs[I], InstArg,
MultiLevelTemplateArgumentList(*DeducedArgumentList))) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = PartialTemplateArgs[I].getArgument();
return TDK_SubstitutionFailure;
}
+ InstArgs.addArgument(InstArg);
}
TemplateArgumentListBuilder ConvertedInstArgs(
ClassTemplate->getTemplateParameters(), N);
if (CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(),
- /*LAngle*/ SourceLocation(),
- InstArgs.data(), N,
- /*RAngle*/ SourceLocation(),
- false, ConvertedInstArgs)) {
+ InstArgs, false, ConvertedInstArgs)) {
// FIXME: fail with more useful information?
return TDK_SubstitutionFailure;
}
for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) {
- // We don't really care if we overwrite the internal structures of
- // the arg list builder, because we're going to throw it all away.
- TemplateArgument &InstArg
- = const_cast<TemplateArgument&>(ConvertedInstArgs.getFlatArguments()[I]);
+ TemplateArgument InstArg = ConvertedInstArgs.getFlatArguments()[I];
Decl *Param = const_cast<NamedDecl *>(
ClassTemplate->getTemplateParameters()->getParam(I));
@@ -1130,9 +1128,6 @@ static bool isSimpleTemplateIdType(QualType T) {
/// \param ExplicitTemplateArguments the explicitly-specified template
/// arguments.
///
-/// \param NumExplicitTemplateArguments the number of explicitly-specified
-/// template arguments in @p ExplicitTemplateArguments. This value may be zero.
-///
/// \param Deduced the deduced template arguments, which will be populated
/// with the converted and checked explicit template arguments.
///
@@ -1151,8 +1146,7 @@ static bool isSimpleTemplateIdType(QualType T) {
Sema::TemplateDeductionResult
Sema::SubstituteExplicitTemplateArguments(
FunctionTemplateDecl *FunctionTemplate,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ const TemplateArgumentListInfo &ExplicitTemplateArgs,
llvm::SmallVectorImpl<TemplateArgument> &Deduced,
llvm::SmallVectorImpl<QualType> &ParamTypes,
QualType *FunctionType,
@@ -1161,7 +1155,7 @@ Sema::SubstituteExplicitTemplateArguments(
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
- if (NumExplicitTemplateArgs == 0) {
+ if (ExplicitTemplateArgs.size() == 0) {
// No arguments to substitute; just copy over the parameter types and
// fill in the function type.
for (FunctionDecl::param_iterator P = Function->param_begin(),
@@ -1185,7 +1179,7 @@ Sema::SubstituteExplicitTemplateArguments(
// template argument list shall not specify more template-arguments than
// there are corresponding template-parameters.
TemplateArgumentListBuilder Builder(TemplateParams,
- NumExplicitTemplateArgs);
+ ExplicitTemplateArgs.size());
// Enter a new template instantiation context where we check the
// explicitly-specified template arguments against this function template,
@@ -1197,10 +1191,8 @@ Sema::SubstituteExplicitTemplateArguments(
return TDK_InstantiationDepth;
if (CheckTemplateArgumentList(FunctionTemplate,
- SourceLocation(), SourceLocation(),
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
SourceLocation(),
+ ExplicitTemplateArgs,
true,
Builder) || Trap.hasErrorOccurred())
return TDK_InvalidExplicitArguments;
@@ -1279,18 +1271,56 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
+ // Template argument deduction for function templates in a SFINAE context.
+ // Trap any errors that might occur.
+ SFINAETrap Trap(*this);
+
+ // Enter a new template instantiation context while we instantiate the
+ // actual function declaration.
+ InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
+ FunctionTemplate, Deduced.data(), Deduced.size(),
+ ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution);
+ if (Inst)
+ return TDK_InstantiationDepth;
+
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size());
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
- if (Deduced[I].isNull()) {
+ if (!Deduced[I].isNull()) {
+ Builder.Append(Deduced[I]);
+ continue;
+ }
+
+ // Substitute into the default template argument, if available.
+ NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I);
+ TemplateArgumentLoc DefArg
+ = SubstDefaultTemplateArgumentIfAvailable(FunctionTemplate,
+ FunctionTemplate->getLocation(),
+ FunctionTemplate->getSourceRange().getEnd(),
+ Param,
+ Builder);
+
+ // If there was no default argument, deduction is incomplete.
+ if (DefArg.getArgument().isNull()) {
Info.Param = makeTemplateParameter(
- const_cast<NamedDecl *>(TemplateParams->getParam(I)));
+ const_cast<NamedDecl *>(TemplateParams->getParam(I)));
return TDK_Incomplete;
}
+
+ // Check whether we can actually use the default argument.
+ if (CheckTemplateArgument(Param, DefArg,
+ FunctionTemplate,
+ FunctionTemplate->getLocation(),
+ FunctionTemplate->getSourceRange().getEnd(),
+ Builder)) {
+ Info.Param = makeTemplateParameter(
+ const_cast<NamedDecl *>(TemplateParams->getParam(I)));
+ return TDK_SubstitutionFailure;
+ }
- Builder.Append(Deduced[I]);
+ // If we get here, we successfully used the default template argument.
}
// Form the template argument list from the deduced template arguments.
@@ -1298,18 +1328,6 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
= new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
Info.reset(DeducedArgumentList);
- // Template argument deduction for function templates in a SFINAE context.
- // Trap any errors that might occur.
- SFINAETrap Trap(*this);
-
- // Enter a new template instantiation context while we instantiate the
- // actual function declaration.
- InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
- FunctionTemplate, Deduced.data(), Deduced.size(),
- ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution);
- if (Inst)
- return TDK_InstantiationDepth;
-
// Substitute the deduced template arguments into the function template
// declaration to produce the function template specialization.
Specialization = cast_or_null<FunctionDecl>(
@@ -1368,9 +1386,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
/// \returns the result of template argument deduction.
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- bool HasExplicitTemplateArgs,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
@@ -1398,11 +1414,10 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
= FunctionTemplate->getTemplateParameters();
llvm::SmallVector<TemplateArgument, 4> Deduced;
llvm::SmallVector<QualType, 4> ParamTypes;
- if (NumExplicitTemplateArgs) {
+ if (ExplicitTemplateArgs) {
TemplateDeductionResult Result =
SubstituteExplicitTemplateArguments(FunctionTemplate,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
+ *ExplicitTemplateArgs,
Deduced,
ParamTypes,
0,
@@ -1538,9 +1553,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
/// \returns the result of template argument deduction.
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- bool HasExplicitTemplateArgs,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ArgFunctionType,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
@@ -1552,11 +1565,10 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// Substitute any explicit template arguments.
llvm::SmallVector<TemplateArgument, 4> Deduced;
llvm::SmallVector<QualType, 4> ParamTypes;
- if (HasExplicitTemplateArgs) {
+ if (ExplicitTemplateArgs) {
if (TemplateDeductionResult Result
= SubstituteExplicitTemplateArguments(FunctionTemplate,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
+ *ExplicitTemplateArgs,
Deduced, ParamTypes,
&FunctionType, Info))
return Result;
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 58fe59e..623cde8 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -12,13 +12,13 @@
#include "Sema.h"
#include "TreeTransform.h"
+#include "Lookup.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Basic/LangOptions.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
@@ -491,7 +491,7 @@ bool Sema::isSFINAEContext() const {
// Template Instantiation for Types
//===----------------------------------------------------------------------===/
namespace {
- class VISIBILITY_HIDDEN TemplateInstantiator
+ class TemplateInstantiator
: public TreeTransform<TemplateInstantiator> {
const MultiLevelTemplateArgumentList &TemplateArgs;
SourceLocation Loc;
@@ -743,7 +743,6 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E,
= SemaRef.BuildDeclRefExpr(VD,
VD->getType().getNonReferenceType(),
E->getLocation(),
- /*FIXME:*/false, /*FIXME:*/false,
&SS);
if (RefExpr.isInvalid())
return SemaRef.ExprError();
@@ -755,8 +754,7 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E,
}
return SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(),
- E->getLocation(),
- /*FIXME:*/false, /*FIXME:*/false);
+ E->getLocation());
}
assert(Arg.getKind() == TemplateArgument::Integral);
@@ -788,46 +786,7 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E,
if (!InstD)
return SemaRef.ExprError();
- // Flatten using declarations into their shadow declarations.
- if (isa<UsingDecl>(InstD)) {
- UsingDecl *UD = cast<UsingDecl>(InstD);
-
- bool HasNonFunction = false;
-
- llvm::SmallVector<NamedDecl*, 8> Decls;
- for (UsingDecl::shadow_iterator I = UD->shadow_begin(),
- E = UD->shadow_end(); I != E; ++I) {
- NamedDecl *TD = (*I)->getTargetDecl();
- if (!TD->isFunctionOrFunctionTemplate())
- HasNonFunction = true;
-
- Decls.push_back(TD);
- }
-
- if (Decls.empty())
- return SemaRef.ExprError();
-
- if (Decls.size() == 1)
- InstD = Decls[0];
- else if (!HasNonFunction) {
- OverloadedFunctionDecl *OFD
- = OverloadedFunctionDecl::Create(SemaRef.Context,
- UD->getDeclContext(),
- UD->getDeclName());
- for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Decls.begin(),
- E = Decls.end(); I != E; ++I)
- if (isa<FunctionDecl>(*I))
- OFD->addOverload(cast<FunctionDecl>(*I));
- else
- OFD->addOverload(cast<FunctionTemplateDecl>(*I));
-
- InstD = OFD;
- } else {
- // FIXME
- assert(false && "using declaration resolved to mixed set");
- return SemaRef.ExprError();
- }
- }
+ assert(!isa<UsingDecl>(InstD) && "decl ref instantiated to UsingDecl");
CXXScopeSpec SS;
NestedNameSpecifier *Qualifier = 0;
@@ -841,10 +800,7 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E,
SS.setRange(E->getQualifierRange());
}
- return SemaRef.BuildDeclarationNameExpr(E->getLocation(), InstD,
- /*FIXME:*/false,
- &SS,
- isAddressOfOperand);
+ return SemaRef.BuildDeclarationNameExpr(SS, E->getLocation(), InstD);
}
Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr(
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 3f40ffc..a125857 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -18,12 +18,11 @@
#include "clang/AST/Expr.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
namespace {
- class VISIBILITY_HIDDEN TemplateDeclInstantiator
+ class TemplateDeclInstantiator
: public DeclVisitor<TemplateDeclInstantiator, Decl *> {
Sema &SemaRef;
DeclContext *Owner;
@@ -205,6 +204,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// 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())) {
@@ -1153,11 +1153,12 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
= PartialSpec->getTemplateArgsAsWritten();
unsigned N = PartialSpec->getNumTemplateArgsAsWritten();
- llvm::SmallVector<TemplateArgumentLoc, 4> InstTemplateArgs(N);
+ TemplateArgumentListInfo InstTemplateArgs; // no angle locations
for (unsigned I = 0; I != N; ++I) {
- if (SemaRef.Subst(PartialSpecTemplateArgs[I], InstTemplateArgs[I],
- TemplateArgs))
+ TemplateArgumentLoc Loc;
+ if (SemaRef.Subst(PartialSpecTemplateArgs[I], Loc, TemplateArgs))
return true;
+ InstTemplateArgs.addArgument(Loc);
}
@@ -1167,10 +1168,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
InstTemplateArgs.size());
if (SemaRef.CheckTemplateArgumentList(ClassTemplate,
PartialSpec->getLocation(),
- /*FIXME:*/PartialSpec->getLocation(),
- InstTemplateArgs.data(),
- InstTemplateArgs.size(),
- /*FIXME:*/PartialSpec->getLocation(),
+ InstTemplateArgs,
false,
Converted))
return true;
@@ -1203,8 +1201,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
// template arguments in the specialization.
QualType WrittenTy
= SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate),
- InstTemplateArgs.data(),
- InstTemplateArgs.size(),
+ InstTemplateArgs,
CanonType);
if (PrevDecl) {
@@ -1238,8 +1235,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
InstParams,
ClassTemplate,
Converted,
- InstTemplateArgs.data(),
- InstTemplateArgs.size(),
+ InstTemplateArgs,
0);
InstPartialSpec->setInstantiatedFromMember(PartialSpec);
InstPartialSpec->setTypeAsWritten(WrittenTy);
@@ -1887,22 +1883,6 @@ DeclContext *Sema::FindInstantiatedContext(DeclContext* DC,
/// this mapping from within the instantiation of X<int>.
NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs) {
- if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) {
- // Transform all of the elements of the overloaded function set.
- OverloadedFunctionDecl *Result
- = OverloadedFunctionDecl::Create(Context, CurContext, Ovl->getDeclName());
-
- for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
- FEnd = Ovl->function_end();
- F != FEnd; ++F) {
- Result->addOverload(
- AnyFunctionDecl::getFromNamedDecl(FindInstantiatedDecl(*F,
- TemplateArgs)));
- }
-
- return Result;
- }
-
DeclContext *ParentDC = D->getDeclContext();
if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
isa<TemplateTypeParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 00dc809..afce5e3 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -879,6 +879,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
switch (D.getName().getKind()) {
case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_OperatorFunctionId:
+ case UnqualifiedId::IK_LiteralOperatorId:
case UnqualifiedId::IK_TemplateId:
T = ConvertDeclSpecToType(D, *this);
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index ca680c2..28b2174 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -14,6 +14,7 @@
#define LLVM_CLANG_SEMA_TREETRANSFORM_H
#include "Sema.h"
+#include "Lookup.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
@@ -94,7 +95,8 @@ public:
typedef Sema::ExprArg ExprArg;
typedef Sema::MultiExprArg MultiExprArg;
typedef Sema::MultiStmtArg MultiStmtArg;
-
+ typedef Sema::DeclPtrTy DeclPtrTy;
+
/// \brief Initializes a new tree transformer.
TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { }
@@ -503,10 +505,7 @@ public:
/// different behavior.
QualType RebuildTemplateSpecializationType(TemplateName Template,
SourceLocation TemplateLoc,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *Args,
- unsigned NumArgs,
- SourceLocation RAngleLoc);
+ const TemplateArgumentListInfo &Args);
/// \brief Build a new qualified name type.
///
@@ -584,16 +583,6 @@ public:
bool TemplateKW,
TemplateDecl *Template);
- /// \brief Build a new template name given a nested name specifier, a flag
- /// indicating whether the "template" keyword was provided, and a set of
- /// overloaded function templates.
- ///
- /// By default, builds the new template name directly. Subclasses may override
- /// this routine to provide different behavior.
- TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
- bool TemplateKW,
- OverloadedFunctionDecl *Ovl);
-
/// \brief Build a new template name given a nested name specifier and the
/// name that is referred to as a template.
///
@@ -677,17 +666,19 @@ public:
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
OwningStmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::FullExprArg Cond,
- StmtArg Then, SourceLocation ElseLoc,
- StmtArg Else) {
- return getSema().ActOnIfStmt(IfLoc, Cond, move(Then), ElseLoc, move(Else));
+ VarDecl *CondVar, StmtArg Then,
+ SourceLocation ElseLoc, StmtArg Else) {
+ return getSema().ActOnIfStmt(IfLoc, Cond, DeclPtrTy::make(CondVar),
+ move(Then), ElseLoc, move(Else));
}
/// \brief Start building a new switch statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- OwningStmtResult RebuildSwitchStmtStart(ExprArg Cond) {
- return getSema().ActOnStartOfSwitchStmt(move(Cond));
+ OwningStmtResult RebuildSwitchStmtStart(Sema::FullExprArg Cond,
+ VarDecl *CondVar) {
+ return getSema().ActOnStartOfSwitchStmt(Cond, DeclPtrTy::make(CondVar));
}
/// \brief Attach the body to the switch statement.
@@ -706,8 +697,10 @@ public:
/// Subclasses may override this routine to provide different behavior.
OwningStmtResult RebuildWhileStmt(SourceLocation WhileLoc,
Sema::FullExprArg Cond,
+ VarDecl *CondVar,
StmtArg Body) {
- return getSema().ActOnWhileStmt(WhileLoc, Cond, move(Body));
+ return getSema().ActOnWhileStmt(WhileLoc, Cond, DeclPtrTy::make(CondVar),
+ move(Body));
}
/// \brief Build a new do-while statement.
@@ -729,10 +722,12 @@ public:
/// Subclasses may override this routine to provide different behavior.
OwningStmtResult RebuildForStmt(SourceLocation ForLoc,
SourceLocation LParenLoc,
- StmtArg Init, ExprArg Cond, ExprArg Inc,
+ StmtArg Init, Sema::FullExprArg Cond,
+ VarDecl *CondVar, Sema::FullExprArg Inc,
SourceLocation RParenLoc, StmtArg Body) {
- return getSema().ActOnForStmt(ForLoc, LParenLoc, move(Init), move(Cond),
- move(Inc), RParenLoc, move(Body));
+ return getSema().ActOnForStmt(ForLoc, LParenLoc, move(Init), Cond,
+ DeclPtrTy::make(CondVar),
+ Inc, RParenLoc, move(Body));
}
/// \brief Build a new goto statement.
@@ -818,6 +813,17 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildDeclarationNameExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ bool RequiresADL) {
+ return getSema().BuildDeclarationNameExpr(SS, R, RequiresADL);
+ }
+
+
+ /// \brief Build a new expression that references a declaration.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildDeclRefExpr(NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
NamedDecl *ND, SourceLocation Loc,
@@ -861,13 +867,10 @@ public:
= SemaRef.Context.DeclarationNames.getCXXDestructorName(
SemaRef.Context.getCanonicalType(DestroyedType));
- return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base),
- OperatorLoc,
- isArrow? tok::arrow : tok::period,
- DestroyedTypeLoc,
- Name,
- Sema::DeclPtrTy::make((Decl *)0),
- &SS);
+ return getSema().BuildMemberReferenceExpr(move(Base), OperatorLoc, isArrow,
+ SS, /*FIXME: FirstQualifier*/ 0,
+ Name, DestroyedTypeLoc,
+ /*TemplateArgs*/ 0);
}
/// \brief Build a new unary operator expression.
@@ -942,11 +945,7 @@ public:
SourceRange QualifierRange,
SourceLocation MemberLoc,
NamedDecl *Member,
- bool HasExplicitTemplateArgs,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
- SourceLocation RAngleLoc,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
NamedDecl *FirstQualifierInScope) {
if (!Member->getDeclName()) {
// We have a reference to an unnamed field.
@@ -965,18 +964,10 @@ public:
SS.setScopeRep(Qualifier);
}
- return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc,
- isArrow? tok::arrow : tok::period,
- MemberLoc,
- Member->getDeclName(),
- HasExplicitTemplateArgs,
- LAngleLoc,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
- RAngleLoc,
- /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0),
- &SS,
- FirstQualifierInScope);
+ return getSema().BuildMemberReferenceExpr(move(Base), OpLoc, isArrow,
+ SS, FirstQualifierInScope,
+ Member->getDeclName(), MemberLoc,
+ ExplicitTemplateArgs);
}
/// \brief Build a new binary operator expression.
@@ -1051,10 +1042,13 @@ public:
SourceLocation OpLoc,
SourceLocation AccessorLoc,
IdentifierInfo &Accessor) {
- return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc,
- tok::period, AccessorLoc,
+ CXXScopeSpec SS;
+ return getSema().BuildMemberReferenceExpr(move(Base),
+ OpLoc, /*IsArrow*/ false,
+ SS, /*FirstQualifierInScope*/ 0,
DeclarationName(&Accessor),
- /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
+ AccessorLoc,
+ /* TemplateArgs */ 0);
}
/// \brief Build a new initializer list expression.
@@ -1122,7 +1116,8 @@ public:
OwningExprResult RebuildParenListExpr(SourceLocation LParenLoc,
MultiExprArg SubExprs,
SourceLocation RParenLoc) {
- return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, move(SubExprs));
+ return getSema().ActOnParenOrParenListExpr(LParenLoc, RParenLoc,
+ move(SubExprs));
}
/// \brief Build a new address-of-label expression.
@@ -1383,18 +1378,6 @@ public:
0, RParenLoc);
}
- /// \brief Build a new C++ conditional declaration expression.
- ///
- /// By default, performs semantic analysis to build the new expression.
- /// Subclasses may override this routine to provide different behavior.
- OwningExprResult RebuildCXXConditionDeclExpr(SourceLocation StartLoc,
- SourceLocation EqLoc,
- VarDecl *Var) {
- return SemaRef.Owned(new (SemaRef.Context) CXXConditionDeclExpr(StartLoc,
- EqLoc,
- Var));
- }
-
/// \brief Build a new C++ "new" expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -1456,39 +1439,31 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- OwningExprResult RebuildUnresolvedDeclRefExpr(NestedNameSpecifier *NNS,
+ OwningExprResult RebuildDependentScopeDeclRefExpr(NestedNameSpecifier *NNS,
SourceRange QualifierRange,
DeclarationName Name,
SourceLocation Location,
- bool IsAddressOfOperand) {
+ const TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
SS.setRange(QualifierRange);
SS.setScopeRep(NNS);
- return getSema().ActOnDeclarationNameExpr(/*Scope=*/0,
- Location,
- Name,
- /*Trailing lparen=*/false,
- &SS,
- IsAddressOfOperand);
+
+ if (TemplateArgs)
+ return getSema().BuildQualifiedTemplateIdExpr(SS, Name, Location,
+ *TemplateArgs);
+
+ return getSema().BuildQualifiedDeclarationNameExpr(SS, Name, Location);
}
/// \brief Build a new template-id expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- OwningExprResult RebuildTemplateIdExpr(NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- TemplateName Template,
- SourceLocation TemplateLoc,
- SourceLocation LAngleLoc,
- TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation RAngleLoc) {
- return getSema().BuildTemplateIdExpr(Qualifier, QualifierRange,
- Template, TemplateLoc,
- LAngleLoc,
- TemplateArgs, NumTemplateArgs,
- RAngleLoc);
+ OwningExprResult RebuildTemplateIdExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ bool RequiresADL,
+ const TemplateArgumentListInfo &TemplateArgs) {
+ return getSema().BuildTemplateIdExpr(SS, R, RequiresADL, TemplateArgs);
}
/// \brief Build a new object-construction expression.
@@ -1546,76 +1521,43 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- OwningExprResult RebuildCXXUnresolvedMemberExpr(ExprArg BaseE,
+ OwningExprResult RebuildCXXDependentScopeMemberExpr(ExprArg BaseE,
bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
+ NamedDecl *FirstQualifierInScope,
DeclarationName Name,
SourceLocation MemberLoc,
- NamedDecl *FirstQualifierInScope) {
- OwningExprResult Base = move(BaseE);
- tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period;
-
+ const TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
SS.setRange(QualifierRange);
SS.setScopeRep(Qualifier);
- return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0,
- move(Base), OperatorLoc, OpKind,
- MemberLoc,
- Name,
- /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0),
- &SS,
- FirstQualifierInScope);
+ return SemaRef.BuildMemberReferenceExpr(move(BaseE), OperatorLoc, IsArrow,
+ SS, FirstQualifierInScope,
+ Name, MemberLoc, TemplateArgs);
}
- /// \brief Build a new member reference expression with explicit template
- /// arguments.
+ /// \brief Build a new member reference expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- OwningExprResult RebuildCXXUnresolvedMemberExpr(ExprArg BaseE,
- bool IsArrow,
- SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- TemplateName Template,
- SourceLocation TemplateNameLoc,
- NamedDecl *FirstQualifierInScope,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation RAngleLoc) {
+ OwningExprResult RebuildUnresolvedMemberExpr(ExprArg BaseE,
+ SourceLocation OperatorLoc,
+ bool IsArrow,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs) {
OwningExprResult Base = move(BaseE);
- tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period;
CXXScopeSpec SS;
SS.setRange(QualifierRange);
SS.setScopeRep(Qualifier);
- // FIXME: We're going to end up looking up the template based on its name,
- // twice! Also, duplicates part of Sema::BuildMemberAccessExpr.
- DeclarationName Name;
- if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl())
- Name = ActualTemplate->getDeclName();
- else if (OverloadedFunctionDecl *Ovl
- = Template.getAsOverloadedFunctionDecl())
- Name = Ovl->getDeclName();
- else {
- DependentTemplateName *DTN = Template.getAsDependentTemplateName();
- if (DTN->isIdentifier())
- Name = DTN->getIdentifier();
- else
- Name = SemaRef.Context.DeclarationNames.getCXXOperatorName(
- DTN->getOperator());
- }
- return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0, move(Base),
- OperatorLoc, OpKind,
- TemplateNameLoc, Name, true,
- LAngleLoc, TemplateArgs,
- NumTemplateArgs, RAngleLoc,
- Sema::DeclPtrTy(), &SS);
+ return SemaRef.BuildMemberReferenceExpr(move(Base), OperatorLoc, IsArrow,
+ SS, R, TemplateArgs);
}
/// \brief Build a new Objective-C @encode expression.
@@ -1664,7 +1606,7 @@ public:
FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first);
Expr *Callee
= new (SemaRef.Context) DeclRefExpr(Builtin, Builtin->getType(),
- BuiltinLoc, false, false);
+ BuiltinLoc);
SemaRef.UsualUnaryConversions(Callee);
// Build the CallExpr
@@ -1825,6 +1767,7 @@ TreeTransform<Derived>::TransformDeclarationName(DeclarationName Name,
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
case DeclarationName::CXXOperatorName:
+ case DeclarationName::CXXLiteralOperatorName:
case DeclarationName::CXXUsingDirective:
return Name;
@@ -1878,20 +1821,8 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name,
TransTemplate);
}
- OverloadedFunctionDecl *Ovl = QTN->getOverloadedFunctionDecl();
- assert(Ovl && "Not a template name or an overload set?");
- OverloadedFunctionDecl *TransOvl
- = cast_or_null<OverloadedFunctionDecl>(getDerived().TransformDecl(Ovl));
- if (!TransOvl)
- return TemplateName();
-
- if (!getDerived().AlwaysRebuild() &&
- NNS == QTN->getQualifier() &&
- TransOvl == Ovl)
- return Name;
-
- return getDerived().RebuildTemplateName(NNS, QTN->hasTemplateKeyword(),
- TransOvl);
+ // These should be getting filtered out before they make it into the AST.
+ assert(false && "overloaded template name survived to here");
}
if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
@@ -1927,18 +1858,9 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name,
return TemplateName(TransTemplate);
}
- OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl();
- assert(Ovl && "Not a template name or an overload set?");
- OverloadedFunctionDecl *TransOvl
- = cast_or_null<OverloadedFunctionDecl>(getDerived().TransformDecl(Ovl));
- if (!TransOvl)
- return TemplateName();
-
- if (!getDerived().AlwaysRebuild() &&
- TransOvl == Ovl)
- return Name;
-
- return TemplateName(TransOvl);
+ // These should be getting filtered out before they reach the AST.
+ assert(false && "overloaded function decl survived to here");
+ return TemplateName();
}
template<typename Derived>
@@ -2879,21 +2801,23 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
if (Template.isNull())
return QualType();
- llvm::SmallVector<TemplateArgumentLoc, 4> NewTemplateArgs(T->getNumArgs());
- for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i)
- if (getDerived().TransformTemplateArgument(TL.getArgLoc(i),
- NewTemplateArgs[i]))
+ TemplateArgumentListInfo NewTemplateArgs;
+ NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc());
+ NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc());
+
+ for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) {
+ TemplateArgumentLoc Loc;
+ if (getDerived().TransformTemplateArgument(TL.getArgLoc(i), Loc))
return QualType();
+ NewTemplateArgs.addArgument(Loc);
+ }
// FIXME: maybe don't rebuild if all the template arguments are the same.
QualType Result =
getDerived().RebuildTemplateSpecializationType(Template,
TL.getTemplateNameLoc(),
- TL.getLAngleLoc(),
- NewTemplateArgs.data(),
- NewTemplateArgs.size(),
- TL.getRAngleLoc());
+ NewTemplateArgs);
if (!Result.isNull()) {
TemplateSpecializationTypeLoc NewTL
@@ -3103,10 +3027,21 @@ template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
// Transform the condition
- OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
- if (Cond.isInvalid())
- return SemaRef.StmtError();
-
+ OwningExprResult Cond(SemaRef);
+ VarDecl *ConditionVar = 0;
+ if (S->getConditionVariable()) {
+ ConditionVar
+ = cast_or_null<VarDecl>(
+ getDerived().TransformDefinition(S->getConditionVariable()));
+ if (!ConditionVar)
+ return SemaRef.StmtError();
+ } else {
+ Cond = getDerived().TransformExpr(S->getCond());
+
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+ }
+
Sema::FullExprArg FullCond(getSema().FullExpr(Cond));
// Transform the "then" branch.
@@ -3121,11 +3056,13 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
if (!getDerived().AlwaysRebuild() &&
FullCond->get() == S->getCond() &&
+ ConditionVar == S->getConditionVariable() &&
Then.get() == S->getThen() &&
Else.get() == S->getElse())
return SemaRef.Owned(S->Retain());
- return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, move(Then),
+ return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, ConditionVar,
+ move(Then),
S->getElseLoc(), move(Else));
}
@@ -3133,12 +3070,26 @@ template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
// Transform the condition.
- OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
- if (Cond.isInvalid())
- return SemaRef.StmtError();
+ OwningExprResult Cond(SemaRef);
+ VarDecl *ConditionVar = 0;
+ if (S->getConditionVariable()) {
+ ConditionVar
+ = cast_or_null<VarDecl>(
+ getDerived().TransformDefinition(S->getConditionVariable()));
+ if (!ConditionVar)
+ return SemaRef.StmtError();
+ } else {
+ Cond = getDerived().TransformExpr(S->getCond());
+
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+ }
+ Sema::FullExprArg FullCond(getSema().FullExpr(Cond));
+
// Rebuild the switch statement.
- OwningStmtResult Switch = getDerived().RebuildSwitchStmtStart(move(Cond));
+ OwningStmtResult Switch = getDerived().RebuildSwitchStmtStart(FullCond,
+ ConditionVar);
if (Switch.isInvalid())
return SemaRef.StmtError();
@@ -3156,9 +3107,20 @@ template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
// Transform the condition
- OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
- if (Cond.isInvalid())
- return SemaRef.StmtError();
+ OwningExprResult Cond(SemaRef);
+ VarDecl *ConditionVar = 0;
+ if (S->getConditionVariable()) {
+ ConditionVar
+ = cast_or_null<VarDecl>(
+ getDerived().TransformDefinition(S->getConditionVariable()));
+ if (!ConditionVar)
+ return SemaRef.StmtError();
+ } else {
+ Cond = getDerived().TransformExpr(S->getCond());
+
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+ }
Sema::FullExprArg FullCond(getSema().FullExpr(Cond));
@@ -3169,10 +3131,12 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
if (!getDerived().AlwaysRebuild() &&
FullCond->get() == S->getCond() &&
+ ConditionVar == S->getConditionVariable() &&
Body.get() == S->getBody())
return SemaRef.Owned(S->Retain());
- return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, move(Body));
+ return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, ConditionVar,
+ move(Body));
}
template<typename Derived>
@@ -3207,9 +3171,20 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
return SemaRef.StmtError();
// Transform the condition
- OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
- if (Cond.isInvalid())
- return SemaRef.StmtError();
+ OwningExprResult Cond(SemaRef);
+ VarDecl *ConditionVar = 0;
+ if (S->getConditionVariable()) {
+ ConditionVar
+ = cast_or_null<VarDecl>(
+ getDerived().TransformDefinition(S->getConditionVariable()));
+ if (!ConditionVar)
+ return SemaRef.StmtError();
+ } else {
+ Cond = getDerived().TransformExpr(S->getCond());
+
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+ }
// Transform the increment
OwningExprResult Inc = getDerived().TransformExpr(S->getInc());
@@ -3229,7 +3204,9 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
return SemaRef.Owned(S->Retain());
return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(),
- move(Init), move(Cond), move(Inc),
+ move(Init), getSema().FullExpr(Cond),
+ ConditionVar,
+ getSema().FullExpr(Inc),
S->getRParenLoc(), move(Body));
}
@@ -3695,13 +3672,15 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E,
!E->hasExplicitTemplateArgumentList())
return SemaRef.Owned(E->Retain());
- llvm::SmallVector<TemplateArgumentLoc, 4> TransArgs;
+ TemplateArgumentListInfo TransArgs;
if (E->hasExplicitTemplateArgumentList()) {
- TransArgs.resize(E->getNumTemplateArgs());
+ TransArgs.setLAngleLoc(E->getLAngleLoc());
+ TransArgs.setRAngleLoc(E->getRAngleLoc());
for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) {
- if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I],
- TransArgs[I]))
+ TemplateArgumentLoc Loc;
+ if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], Loc))
return SemaRef.ExprError();
+ TransArgs.addArgument(Loc);
}
}
@@ -3715,11 +3694,8 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E,
E->getQualifierRange(),
E->getMemberLoc(),
Member,
- E->hasExplicitTemplateArgumentList(),
- E->getLAngleLoc(),
- TransArgs.data(),
- TransArgs.size(),
- E->getRAngleLoc(),
+ (E->hasExplicitTemplateArgumentList()
+ ? &TransArgs : 0),
0);
}
@@ -4425,24 +4401,6 @@ TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXConditionDeclExpr(CXXConditionDeclExpr *E,
- bool isAddressOfOperand) {
- VarDecl *Var
- = cast_or_null<VarDecl>(getDerived().TransformDefinition(E->getVarDecl()));
- if (!Var)
- return SemaRef.ExprError();
-
- if (!getDerived().AlwaysRebuild() &&
- Var == E->getVarDecl())
- return SemaRef.Owned(E->Retain());
-
- return getDerived().RebuildCXXConditionDeclExpr(E->getStartLoc(),
- /*FIXME:*/E->getStartLoc(),
- Var);
-}
-
-template<typename Derived>
-Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E,
bool isAddressOfOperand) {
// Transform the type that we're allocating
@@ -4558,11 +4516,66 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformUnresolvedFunctionNameExpr(
- UnresolvedFunctionNameExpr *E,
+TreeTransform<Derived>::TransformUnresolvedLookupExpr(
+ UnresolvedLookupExpr *Old,
bool isAddressOfOperand) {
- // There is no transformation we can apply to an unresolved function name.
- return SemaRef.Owned(E->Retain());
+ TemporaryBase Rebase(*this, Old->getNameLoc(), DeclarationName());
+
+ LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(),
+ Sema::LookupOrdinaryName);
+
+ // Transform all the decls.
+ 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();
+
+ // Expand using declarations.
+ if (isa<UsingDecl>(InstD)) {
+ UsingDecl *UD = cast<UsingDecl>(InstD);
+ for (UsingDecl::shadow_iterator I = UD->shadow_begin(),
+ E = UD->shadow_end(); I != E; ++I)
+ R.addDecl(*I);
+ continue;
+ }
+
+ R.addDecl(InstD);
+ }
+
+ // Resolve a kind, but don't do any further analysis. If it's
+ // ambiguous, the callee needs to deal with it.
+ R.resolveKind();
+
+ // Rebuild the nested-name qualifier, if present.
+ CXXScopeSpec SS;
+ NestedNameSpecifier *Qualifier = 0;
+ if (Old->getQualifier()) {
+ Qualifier = getDerived().TransformNestedNameSpecifier(Old->getQualifier(),
+ Old->getQualifierRange());
+ if (!Qualifier)
+ return SemaRef.ExprError();
+
+ SS.setScopeRep(Qualifier);
+ SS.setRange(Old->getQualifierRange());
+ }
+
+ // If we have no template arguments, it's a normal declaration name.
+ if (!Old->hasExplicitTemplateArgs())
+ return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL());
+
+ // If we have template arguments, rebuild them, then rebuild the
+ // templateid expression.
+ TemplateArgumentListInfo TransArgs(Old->getLAngleLoc(), Old->getRAngleLoc());
+ for (unsigned I = 0, N = Old->getNumTemplateArgs(); I != N; ++I) {
+ TemplateArgumentLoc Loc;
+ if (getDerived().TransformTemplateArgument(Old->getTemplateArgs()[I], Loc))
+ return SemaRef.ExprError();
+ TransArgs.addArgument(Loc);
+ }
+
+ return getDerived().RebuildTemplateIdExpr(SS, R, Old->requiresADL(),
+ TransArgs);
}
template<typename Derived>
@@ -4592,8 +4605,8 @@ TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformUnresolvedDeclRefExpr(
- UnresolvedDeclRefExpr *E,
+TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
+ DependentScopeDeclRefExpr *E,
bool isAddressOfOperand) {
NestedNameSpecifier *NNS
= getDerived().TransformNestedNameSpecifier(E->getQualifier(),
@@ -4606,56 +4619,30 @@ TreeTransform<Derived>::TransformUnresolvedDeclRefExpr(
if (!Name)
return SemaRef.ExprError();
- if (!getDerived().AlwaysRebuild() &&
- NNS == E->getQualifier() &&
- Name == E->getDeclName())
- return SemaRef.Owned(E->Retain());
-
- return getDerived().RebuildUnresolvedDeclRefExpr(NNS,
- E->getQualifierRange(),
- Name,
- E->getLocation(),
- isAddressOfOperand);
-}
-
-template<typename Derived>
-Sema::OwningExprResult
-TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E,
- bool isAddressOfOperand) {
- TemporaryBase Rebase(*this, E->getTemplateNameLoc(), DeclarationName());
-
- TemplateName Template
- = getDerived().TransformTemplateName(E->getTemplateName());
- if (Template.isNull())
- return SemaRef.ExprError();
+ if (!E->hasExplicitTemplateArgs()) {
+ if (!getDerived().AlwaysRebuild() &&
+ NNS == E->getQualifier() &&
+ Name == E->getDeclName())
+ return SemaRef.Owned(E->Retain());
- NestedNameSpecifier *Qualifier = 0;
- if (E->getQualifier()) {
- Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
- E->getQualifierRange());
- if (!Qualifier)
- return SemaRef.ExprError();
+ return getDerived().RebuildDependentScopeDeclRefExpr(NNS,
+ E->getQualifierRange(),
+ Name, E->getLocation(),
+ /*TemplateArgs*/ 0);
}
-
- llvm::SmallVector<TemplateArgumentLoc, 4> TransArgs(E->getNumTemplateArgs());
+
+ TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc());
for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) {
- if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I],
- TransArgs[I]))
+ TemplateArgumentLoc Loc;
+ if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], Loc))
return SemaRef.ExprError();
+ TransArgs.addArgument(Loc);
}
- // FIXME: Would like to avoid rebuilding if nothing changed, but we can't
- // compare template arguments (yet).
-
- // FIXME: It's possible that we'll find out now that the template name
- // actually refers to a type, in which case the caller is actually dealing
- // with a functional cast. Give a reasonable error message!
- return getDerived().RebuildTemplateIdExpr(Qualifier, E->getQualifierRange(),
- Template, E->getTemplateNameLoc(),
- E->getLAngleLoc(),
- TransArgs.data(),
- TransArgs.size(),
- E->getRAngleLoc());
+ return getDerived().RebuildDependentScopeDeclRefExpr(NNS,
+ E->getQualifierRange(),
+ Name, E->getLocation(),
+ &TransArgs);
}
template<typename Derived>
@@ -4828,8 +4815,8 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr(
- CXXUnresolvedMemberExpr *E,
+TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
+ CXXDependentScopeMemberExpr *E,
bool isAddressOfOperand) {
// Transform the base of the expression.
OwningExprResult Base = getDerived().TransformExpr(E->getBase());
@@ -4878,52 +4865,99 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr(
FirstQualifierInScope == E->getFirstQualifierFoundInScope())
return SemaRef.Owned(E->Retain());
- return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base),
+ return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base),
E->isArrow(),
E->getOperatorLoc(),
Qualifier,
E->getQualifierRange(),
+ FirstQualifierInScope,
Name,
E->getMemberLoc(),
- FirstQualifierInScope);
+ /*TemplateArgs*/ 0);
}
- // FIXME: This is an ugly hack, which forces the same template name to
- // be looked up multiple times. Yuck!
- TemporaryBase Rebase(*this, E->getMemberLoc(), DeclarationName());
- TemplateName OrigTemplateName;
- if (const IdentifierInfo *II = Name.getAsIdentifierInfo())
- OrigTemplateName = SemaRef.Context.getDependentTemplateName(0, II);
- else
- OrigTemplateName
- = SemaRef.Context.getDependentTemplateName(0,
- Name.getCXXOverloadedOperator());
-
- TemplateName Template
- = getDerived().TransformTemplateName(OrigTemplateName,
- QualType::getFromOpaquePtr(ObjectType));
- if (Template.isNull())
- return SemaRef.ExprError();
-
- llvm::SmallVector<TemplateArgumentLoc, 4> TransArgs(E->getNumTemplateArgs());
+ TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc());
for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) {
- if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I],
- TransArgs[I]))
+ TemplateArgumentLoc Loc;
+ if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], Loc))
return SemaRef.ExprError();
+ TransArgs.addArgument(Loc);
}
- return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base),
+ return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base),
E->isArrow(),
E->getOperatorLoc(),
Qualifier,
E->getQualifierRange(),
- Template,
- E->getMemberLoc(),
FirstQualifierInScope,
- E->getLAngleLoc(),
- TransArgs.data(),
- TransArgs.size(),
- E->getRAngleLoc());
+ Name,
+ E->getMemberLoc(),
+ &TransArgs);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old,
+ bool isAddressOfOperand) {
+ // Transform the base of the expression.
+ OwningExprResult Base = getDerived().TransformExpr(Old->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ NestedNameSpecifier *Qualifier = 0;
+ if (Old->getQualifier()) {
+ Qualifier
+ = getDerived().TransformNestedNameSpecifier(Old->getQualifier(),
+ Old->getQualifierRange());
+ if (Qualifier == 0)
+ return SemaRef.ExprError();
+ }
+
+ LookupResult R(SemaRef, Old->getMemberName(), Old->getMemberLoc(),
+ Sema::LookupOrdinaryName);
+
+ // Transform all the decls.
+ 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();
+
+ // Expand using declarations.
+ if (isa<UsingDecl>(InstD)) {
+ UsingDecl *UD = cast<UsingDecl>(InstD);
+ for (UsingDecl::shadow_iterator I = UD->shadow_begin(),
+ E = UD->shadow_end(); I != E; ++I)
+ R.addDecl(*I);
+ continue;
+ }
+
+ R.addDecl(InstD);
+ }
+
+ R.resolveKind();
+
+ TemplateArgumentListInfo TransArgs;
+ if (Old->hasExplicitTemplateArgs()) {
+ TransArgs.setLAngleLoc(Old->getLAngleLoc());
+ TransArgs.setRAngleLoc(Old->getRAngleLoc());
+ for (unsigned I = 0, N = Old->getNumTemplateArgs(); I != N; ++I) {
+ TemplateArgumentLoc Loc;
+ if (getDerived().TransformTemplateArgument(Old->getTemplateArgs()[I],
+ Loc))
+ return SemaRef.ExprError();
+ TransArgs.addArgument(Loc);
+ }
+ }
+
+ return getDerived().RebuildUnresolvedMemberExpr(move(Base),
+ Old->getOperatorLoc(),
+ Old->isArrow(),
+ Qualifier,
+ Old->getQualifierRange(),
+ R,
+ (Old->hasExplicitTemplateArgs()
+ ? &TransArgs : 0));
}
template<typename Derived>
@@ -5266,12 +5300,8 @@ template<typename Derived>
QualType TreeTransform<Derived>::RebuildTemplateSpecializationType(
TemplateName Template,
SourceLocation TemplateNameLoc,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *Args,
- unsigned NumArgs,
- SourceLocation RAngleLoc) {
- return SemaRef.CheckTemplateIdType(Template, TemplateNameLoc, LAngleLoc,
- Args, NumArgs, RAngleLoc);
+ const TemplateArgumentListInfo &TemplateArgs) {
+ return SemaRef.CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs);
}
template<typename Derived>
@@ -5280,7 +5310,7 @@ TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
SourceRange Range,
IdentifierInfo &II,
QualType ObjectType,
- NamedDecl *FirstQualifierInScope) {
+ NamedDecl *FirstQualifierInScope) {
CXXScopeSpec SS;
// FIXME: The source location information is all wrong.
SS.setRange(Range);
@@ -5330,14 +5360,6 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
template<typename Derived>
TemplateName
TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
- bool TemplateKW,
- OverloadedFunctionDecl *Ovl) {
- return SemaRef.Context.getQualifiedTemplateName(Qualifier, TemplateKW, Ovl);
-}
-
-template<typename Derived>
-TemplateName
-TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
const IdentifierInfo &II,
QualType ObjectType) {
CXXScopeSpec SS;
@@ -5349,7 +5371,8 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
/*FIXME:*/getDerived().getBaseLocation(),
SS,
Name,
- ObjectType.getAsOpaquePtr())
+ ObjectType.getAsOpaquePtr(),
+ /*EnteringContext=*/false)
.template getAsVal<TemplateName>();
}
@@ -5369,7 +5392,8 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
/*FIXME:*/getDerived().getBaseLocation(),
SS,
Name,
- ObjectType.getAsOpaquePtr())
+ ObjectType.getAsOpaquePtr(),
+ /*EnteringContext=*/false)
.template getAsVal<TemplateName>();
}
@@ -5382,8 +5406,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
ExprArg Second) {
Expr *FirstExpr = (Expr *)First.get();
Expr *SecondExpr = (Expr *)Second.get();
- DeclRefExpr *DRE
- = cast<DeclRefExpr>(((Expr *)Callee.get())->IgnoreParenCasts());
+ Expr *CalleeExpr = ((Expr *)Callee.get())->IgnoreParenCasts();
bool isPostIncDec = SecondExpr && (Op == OO_PlusPlus || Op == OO_MinusMinus);
// Determine whether this should be a builtin operation.
@@ -5391,7 +5414,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
if (!FirstExpr->getType()->isOverloadableType() &&
!SecondExpr->getType()->isOverloadableType())
return getSema().CreateBuiltinArraySubscriptExpr(move(First),
- DRE->getLocStart(),
+ CalleeExpr->getLocStart(),
move(Second), OpLoc);
} else if (Op == OO_Arrow) {
// -> is never a builtin operation.
@@ -5426,10 +5449,18 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
// used during overload resolution.
Sema::FunctionSet Functions;
- // FIXME: Do we have to check
- // IsAcceptableNonMemberOperatorCandidate for each of these?
- for (OverloadIterator F(DRE->getDecl()), FEnd; F != FEnd; ++F)
- Functions.insert(*F);
+ if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(CalleeExpr)) {
+ assert(ULE->requiresADL());
+
+ // FIXME: Do we have to check
+ // IsAcceptableNonMemberOperatorCandidate for each of these?
+ for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(),
+ E = ULE->decls_end(); I != E; ++I)
+ Functions.insert(AnyFunctionDecl::getFromNamedDecl(*I));
+ } else {
+ Functions.insert(AnyFunctionDecl::getFromNamedDecl(
+ cast<DeclRefExpr>(CalleeExpr)->getDecl()));
+ }
// Add any functions found via argument-dependent lookup.
Expr *Args[2] = { FirstExpr, SecondExpr };
@@ -5447,8 +5478,10 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
}
if (Op == OO_Subscript)
- return SemaRef.CreateOverloadedArraySubscriptExpr(DRE->getLocStart(), OpLoc,
- move(First),move(Second));
+ return SemaRef.CreateOverloadedArraySubscriptExpr(CalleeExpr->getLocStart(),
+ OpLoc,
+ move(First),
+ move(Second));
// Create the overloaded operator invocation for binary operators.
BinaryOperator::Opcode Opc =
OpenPOWER on IntegriCloud